diff --git a/.github/workflows/ci-static-analysis.yaml b/.github/workflows/ci-static-analysis.yaml
index 1ff990c56..cd338a584 100644
--- a/.github/workflows/ci-static-analysis.yaml
+++ b/.github/workflows/ci-static-analysis.yaml
@@ -26,6 +26,8 @@ jobs:
-
name: Install PHP
uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: 8.2
-
name: Validate composer.json
@@ -58,6 +60,8 @@ jobs:
- name: Install PHP
uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: 8.2
- name: Install Composer Dependencies
uses: "ramsey/composer-install@v2"
diff --git a/.github/workflows/ci-windows.yaml b/.github/workflows/ci-windows.yaml
index e35abb645..e99e6c559 100644
--- a/.github/workflows/ci-windows.yaml
+++ b/.github/workflows/ci-windows.yaml
@@ -13,6 +13,7 @@ env:
SYMFONY_PHPUNIT_DIR: "$HOME/symfony-bridge/.phpunit"
MAKER_SKIP_MERCURE_TEST: 1
MAKER_SKIP_PANTHER_TEST: 1
+ MAKER_TEST_WINDOWS: 1
MAKER_DISABLE_FILE_LINKS: 1
MAKER_ALLOW_DEV_DEPS_IN_APP: 0
SYMFONY_VERSION: '7.0.x-dev'
diff --git a/.symfony.bundle.yaml b/.symfony.bundle.yaml
index a9c304aee..5c0f1017a 100644
--- a/.symfony.bundle.yaml
+++ b/.symfony.bundle.yaml
@@ -2,5 +2,5 @@ branches: ["main"]
maintained_branches: ["main"]
-doc_dir: "src/Resources/doc"
+doc_dir: "docs"
diff --git a/_docs_build/.gitignore b/_docs_build/.gitignore
new file mode 100644
index 000000000..2cf7a3ffd
--- /dev/null
+++ b/_docs_build/.gitignore
@@ -0,0 +1 @@
+composer.lock
\ No newline at end of file
diff --git a/_docs_build/build.php b/_docs_build/build.php
index 20bec5ad2..94130918a 100755
--- a/_docs_build/build.php
+++ b/_docs_build/build.php
@@ -30,7 +30,7 @@
$outputDir = __DIR__.'/output';
$buildConfig = (new BuildConfig())
->setSymfonyVersion('7.1')
- ->setContentDir(__DIR__.'/../src/Resources/doc')
+ ->setContentDir(__DIR__.'/../docs')
->setOutputDir($outputDir)
->setImagesDir(__DIR__.'/output/_images')
->setImagesPublicPrefix('_images')
diff --git a/_docs_build/composer.lock b/_docs_build/composer.lock
deleted file mode 100644
index 5ee65995c..000000000
--- a/_docs_build/composer.lock
+++ /dev/null
@@ -1,1867 +0,0 @@
-{
- "_readme": [
- "This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
- "This file is @generated automatically"
- ],
- "content-hash": "54d13426e2db0a0cca88612376b5c9e0",
- "packages": [
- {
- "name": "doctrine/event-manager",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/event-manager.git",
- "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32",
- "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32",
- "shasum": ""
- },
- "require": {
- "php": "^8.1"
- },
- "conflict": {
- "doctrine/common": "<2.9"
- },
- "require-dev": {
- "doctrine/coding-standard": "^10",
- "phpstan/phpstan": "^1.8.8",
- "phpunit/phpunit": "^9.5",
- "vimeo/psalm": "^4.28"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\Common\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Guilherme Blanco",
- "email": "guilhermeblanco@gmail.com"
- },
- {
- "name": "Roman Borschel",
- "email": "roman@code-factory.org"
- },
- {
- "name": "Benjamin Eberlei",
- "email": "kontakt@beberlei.de"
- },
- {
- "name": "Jonathan Wage",
- "email": "jonwage@gmail.com"
- },
- {
- "name": "Johannes Schmitt",
- "email": "schmittjoh@gmail.com"
- },
- {
- "name": "Marco Pivetta",
- "email": "ocramius@gmail.com"
- }
- ],
- "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
- "homepage": "https://www.doctrine-project.org/projects/event-manager.html",
- "keywords": [
- "event",
- "event dispatcher",
- "event manager",
- "event system",
- "events"
- ],
- "support": {
- "issues": "https://github.com/doctrine/event-manager/issues",
- "source": "https://github.com/doctrine/event-manager/tree/2.0.0"
- },
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
- "type": "tidelift"
- }
- ],
- "time": "2022-10-12T20:59:15+00:00"
- },
- {
- "name": "doctrine/rst-parser",
- "version": "0.5.6",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/rst-parser.git",
- "reference": "ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/rst-parser/zipball/ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104",
- "reference": "ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104",
- "shasum": ""
- },
- "require": {
- "doctrine/event-manager": "^1.0 || ^2.0",
- "php": "^7.2 || ^8.0",
- "symfony/filesystem": "^4.1 || ^5.0 || ^6.0 || ^7.0",
- "symfony/finder": "^4.1 || ^5.0 || ^6.0 || ^7.0",
- "symfony/polyfill-mbstring": "^1.0",
- "symfony/string": "^5.3 || ^6.0 || ^7.0",
- "symfony/translation-contracts": "^1.1 || ^2.0 || ^3.0",
- "twig/twig": "^2.9 || ^3.3"
- },
- "require-dev": {
- "doctrine/coding-standard": "^11.0",
- "gajus/dindent": "^2.0.2",
- "phpstan/phpstan": "^1.9",
- "phpstan/phpstan-deprecation-rules": "^1.0",
- "phpstan/phpstan-phpunit": "^1.2",
- "phpstan/phpstan-strict-rules": "^1.4",
- "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0",
- "symfony/css-selector": "4.4 || ^5.2 || ^6.0 || ^7.0",
- "symfony/dom-crawler": "4.4 || ^5.2 || ^6.0 || ^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\RST\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Grégoire Passault",
- "email": "g.passault@gmail.com",
- "homepage": "http://www.gregwar.com/"
- },
- {
- "name": "Jonathan H. Wage",
- "email": "jonwage@gmail.com",
- "homepage": "https://jwage.com"
- }
- ],
- "description": "PHP library to parse reStructuredText documents and generate HTML or LaTeX documents.",
- "homepage": "https://github.com/doctrine/rst-parser",
- "keywords": [
- "html",
- "latex",
- "markup",
- "parser",
- "reStructuredText",
- "rst"
- ],
- "support": {
- "issues": "https://github.com/doctrine/rst-parser/issues",
- "source": "https://github.com/doctrine/rst-parser/tree/0.5.6"
- },
- "time": "2024-01-14T11:02:23+00:00"
- },
- {
- "name": "masterminds/html5",
- "version": "2.9.0",
- "source": {
- "type": "git",
- "url": "https://github.com/Masterminds/html5-php.git",
- "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
- "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "php": ">=5.3.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.7-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Masterminds\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Matt Butcher",
- "email": "technosophos@gmail.com"
- },
- {
- "name": "Matt Farina",
- "email": "matt@mattfarina.com"
- },
- {
- "name": "Asmir Mustafic",
- "email": "goetas@gmail.com"
- }
- ],
- "description": "An HTML5 parser and serializer.",
- "homepage": "http://masterminds.github.io/html5-php",
- "keywords": [
- "HTML5",
- "dom",
- "html",
- "parser",
- "querypath",
- "serializer",
- "xml"
- ],
- "support": {
- "issues": "https://github.com/Masterminds/html5-php/issues",
- "source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
- },
- "time": "2024-03-31T07:05:07+00:00"
- },
- {
- "name": "psr/container",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/container.git",
- "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
- "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Container\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common Container Interface (PHP FIG PSR-11)",
- "homepage": "https://github.com/php-fig/container",
- "keywords": [
- "PSR-11",
- "container",
- "container-interface",
- "container-interop",
- "psr"
- ],
- "support": {
- "issues": "https://github.com/php-fig/container/issues",
- "source": "https://github.com/php-fig/container/tree/2.0.2"
- },
- "time": "2021-11-05T16:47:00+00:00"
- },
- {
- "name": "psr/log",
- "version": "3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/log.git",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
- "shasum": ""
- },
- "require": {
- "php": ">=8.0.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Log\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for logging libraries",
- "homepage": "https://github.com/php-fig/log",
- "keywords": [
- "log",
- "psr",
- "psr-3"
- ],
- "support": {
- "source": "https://github.com/php-fig/log/tree/3.0.0"
- },
- "time": "2021-07-14T16:46:02+00:00"
- },
- {
- "name": "scrivo/highlight.php",
- "version": "v9.18.1.10",
- "source": {
- "type": "git",
- "url": "https://github.com/scrivo/highlight.php.git",
- "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/850f4b44697a2552e892ffe71490ba2733c2fc6e",
- "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": ">=5.4"
- },
- "require-dev": {
- "phpunit/phpunit": "^4.8|^5.7",
- "sabberworm/php-css-parser": "^8.3",
- "symfony/finder": "^2.8|^3.4|^5.4",
- "symfony/var-dumper": "^2.8|^3.4|^5.4"
- },
- "suggest": {
- "ext-mbstring": "Allows highlighting code with unicode characters and supports language with unicode keywords"
- },
- "type": "library",
- "autoload": {
- "files": [
- "HighlightUtilities/functions.php"
- ],
- "psr-0": {
- "Highlight\\": "",
- "HighlightUtilities\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Geert Bergman",
- "homepage": "http://www.scrivo.org/",
- "role": "Project Author"
- },
- {
- "name": "Vladimir Jimenez",
- "homepage": "https://allejo.io",
- "role": "Maintainer"
- },
- {
- "name": "Martin Folkers",
- "homepage": "https://twobrain.io",
- "role": "Contributor"
- }
- ],
- "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js",
- "keywords": [
- "code",
- "highlight",
- "highlight.js",
- "highlight.php",
- "syntax"
- ],
- "support": {
- "issues": "https://github.com/scrivo/highlight.php/issues",
- "source": "https://github.com/scrivo/highlight.php"
- },
- "funding": [
- {
- "url": "https://github.com/allejo",
- "type": "github"
- }
- ],
- "time": "2022-12-17T21:53:22+00:00"
- },
- {
- "name": "symfony-tools/docs-builder",
- "version": "v0.23.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony-tools/docs-builder.git",
- "reference": "218bfe8bef908cea3934851fd294ffa0d48db059"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony-tools/docs-builder/zipball/218bfe8bef908cea3934851fd294ffa0d48db059",
- "reference": "218bfe8bef908cea3934851fd294ffa0d48db059",
- "shasum": ""
- },
- "require": {
- "doctrine/rst-parser": "^0.5",
- "ext-curl": "*",
- "ext-json": "*",
- "php": ">=7.4",
- "scrivo/highlight.php": "^9.18.1",
- "symfony/console": "^5.2 || ^6.0 || ^7.0",
- "symfony/css-selector": "^5.2 || ^6.0 || ^7.0",
- "symfony/dom-crawler": "^5.2 || ^6.0 || ^7.0",
- "symfony/filesystem": "^5.2 || ^6.0 || ^7.0",
- "symfony/finder": "^5.2 || ^6.0 || ^7.0",
- "symfony/http-client": "^5.2 || ^6.0 || ^7.0",
- "twig/twig": "^2.14 || ^3.3"
- },
- "require-dev": {
- "gajus/dindent": "^2.0",
- "masterminds/html5": "^2.7",
- "symfony/phpunit-bridge": "^5.2 || ^6.0 || ^7.0",
- "symfony/process": "^5.2 || ^6.0 || ^7.0"
- },
- "bin": [
- "bin/docs-builder"
- ],
- "type": "project",
- "autoload": {
- "psr-4": {
- "SymfonyDocsBuilder\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "The build system for Symfony's documentation",
- "support": {
- "issues": "https://github.com/symfony-tools/docs-builder/issues",
- "source": "https://github.com/symfony-tools/docs-builder/tree/v0.23.0"
- },
- "time": "2023-12-26T14:50:41+00:00"
- },
- {
- "name": "symfony/console",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/console.git",
- "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f",
- "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^5.4|^6.0|^7.0"
- },
- "conflict": {
- "symfony/dependency-injection": "<5.4",
- "symfony/dotenv": "<5.4",
- "symfony/event-dispatcher": "<5.4",
- "symfony/lock": "<5.4",
- "symfony/process": "<5.4"
- },
- "provide": {
- "psr/log-implementation": "1.0|2.0|3.0"
- },
- "require-dev": {
- "psr/log": "^1|^2|^3",
- "symfony/config": "^5.4|^6.0|^7.0",
- "symfony/dependency-injection": "^5.4|^6.0|^7.0",
- "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/lock": "^5.4|^6.0|^7.0",
- "symfony/messenger": "^5.4|^6.0|^7.0",
- "symfony/process": "^5.4|^6.0|^7.0",
- "symfony/stopwatch": "^5.4|^6.0|^7.0",
- "symfony/var-dumper": "^5.4|^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Console\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Eases the creation of beautiful and testable command line interfaces",
- "homepage": "https://symfony.com",
- "keywords": [
- "cli",
- "command-line",
- "console",
- "terminal"
- ],
- "support": {
- "source": "https://github.com/symfony/console/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/css-selector",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/css-selector.git",
- "reference": "1c5d5c2103c3762aff27a27e1e2409e30a79083b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/1c5d5c2103c3762aff27a27e1e2409e30a79083b",
- "reference": "1c5d5c2103c3762aff27a27e1e2409e30a79083b",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\CssSelector\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Jean-François Simon",
- "email": "jeanfrancois.simon@sensiolabs.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Converts CSS selectors to XPath expressions",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/css-selector/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/deprecation-contracts",
- "version": "v3.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "files": [
- "function.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "A generic function and convention to trigger deprecation notices",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:32:20+00:00"
- },
- {
- "name": "symfony/dom-crawler",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/dom-crawler.git",
- "reference": "2088c5da700b1e7a8689fffc10dda6c1f643deea"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2088c5da700b1e7a8689fffc10dda6c1f643deea",
- "reference": "2088c5da700b1e7a8689fffc10dda6c1f643deea",
- "shasum": ""
- },
- "require": {
- "masterminds/html5": "^2.6",
- "php": ">=8.1",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.0"
- },
- "require-dev": {
- "symfony/css-selector": "^5.4|^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\DomCrawler\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Eases DOM navigation for HTML and XML documents",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/dom-crawler/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/filesystem",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/filesystem.git",
- "reference": "78dde75f8f6dbbca4ec436a4b0087f7af02076d4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/78dde75f8f6dbbca4ec436a4b0087f7af02076d4",
- "reference": "78dde75f8f6dbbca4ec436a4b0087f7af02076d4",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.8",
- "symfony/process": "^5.4|^6.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Filesystem\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides basic utilities for the filesystem",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/filesystem/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/finder",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/finder.git",
- "reference": "511c48990be17358c23bf45c5d71ab85d40fb764"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/511c48990be17358c23bf45c5d71ab85d40fb764",
- "reference": "511c48990be17358c23bf45c5d71ab85d40fb764",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "symfony/filesystem": "^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Finder\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Finds files and directories via an intuitive fluent interface",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/finder/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-23T10:36:43+00:00"
- },
- {
- "name": "symfony/http-client",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/http-client.git",
- "reference": "3683d8107cf1efdd24795cc5f7482be1eded34ac"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client/zipball/3683d8107cf1efdd24795cc5f7482be1eded34ac",
- "reference": "3683d8107cf1efdd24795cc5f7482be1eded34ac",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "psr/log": "^1|^2|^3",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/http-client-contracts": "^3.4.1",
- "symfony/service-contracts": "^2.5|^3"
- },
- "conflict": {
- "php-http/discovery": "<1.15",
- "symfony/http-foundation": "<6.3"
- },
- "provide": {
- "php-http/async-client-implementation": "*",
- "php-http/client-implementation": "*",
- "psr/http-client-implementation": "1.0",
- "symfony/http-client-implementation": "3.0"
- },
- "require-dev": {
- "amphp/amp": "^2.5",
- "amphp/http-client": "^4.2.1",
- "amphp/http-tunnel": "^1.0",
- "amphp/socket": "^1.1",
- "guzzlehttp/promises": "^1.4|^2.0",
- "nyholm/psr7": "^1.0",
- "php-http/httplug": "^1.0|^2.0",
- "psr/http-client": "^1.0",
- "symfony/dependency-injection": "^5.4|^6.0|^7.0",
- "symfony/http-kernel": "^5.4|^6.0|^7.0",
- "symfony/messenger": "^5.4|^6.0|^7.0",
- "symfony/process": "^5.4|^6.0|^7.0",
- "symfony/stopwatch": "^5.4|^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\HttpClient\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
- "homepage": "https://symfony.com",
- "keywords": [
- "http"
- ],
- "support": {
- "source": "https://github.com/symfony/http-client/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/http-client-contracts",
- "version": "v3.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/http-client-contracts.git",
- "reference": "20414d96f391677bf80078aa55baece78b82647d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d",
- "reference": "20414d96f391677bf80078aa55baece78b82647d",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\HttpClient\\": ""
- },
- "exclude-from-classmap": [
- "/Test/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to HTTP clients",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:32:20+00:00"
- },
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-01-29T20:11:03+00:00"
- },
- {
- "name": "symfony/polyfill-intl-grapheme",
- "version": "v1.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
- "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for intl's grapheme_* functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "grapheme",
- "intl",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-01-29T20:11:03+00:00"
- },
- {
- "name": "symfony/polyfill-intl-normalizer",
- "version": "v1.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
- "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for intl's Normalizer class and related functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "intl",
- "normalizer",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-01-29T20:11:03+00:00"
- },
- {
- "name": "symfony/polyfill-mbstring",
- "version": "v1.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "provide": {
- "ext-mbstring": "*"
- },
- "suggest": {
- "ext-mbstring": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Mbstring\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for the Mbstring extension",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "mbstring",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-01-29T20:11:03+00:00"
- },
- {
- "name": "symfony/polyfill-php80",
- "version": "v1.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
- "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php80\\": ""
- },
- "classmap": [
- "Resources/stubs"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ion Bazan",
- "email": "ion.bazan@gmail.com"
- },
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-01-29T20:11:03+00:00"
- },
- {
- "name": "symfony/process",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/process.git",
- "reference": "cdb1c81c145fd5aa9b0038bab694035020943381"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/cdb1c81c145fd5aa9b0038bab694035020943381",
- "reference": "cdb1c81c145fd5aa9b0038bab694035020943381",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Process\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Executes commands in sub-processes",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/process/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/service-contracts",
- "version": "v3.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/service-contracts.git",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "psr/container": "^1.1|^2.0",
- "symfony/deprecation-contracts": "^2.5|^3"
- },
- "conflict": {
- "ext-psr": "<1.1|>=2"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\Service\\": ""
- },
- "exclude-from-classmap": [
- "/Test/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to writing services",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:32:20+00:00"
- },
- {
- "name": "symfony/string",
- "version": "v6.4.7",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/string.git",
- "reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/ffeb9591c61f65a68d47f77d12b83fa530227a69",
- "reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
- "symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0"
- },
- "conflict": {
- "symfony/translation-contracts": "<2.5"
- },
- "require-dev": {
- "symfony/error-handler": "^5.4|^6.0|^7.0",
- "symfony/http-client": "^5.4|^6.0|^7.0",
- "symfony/intl": "^6.2|^7.0",
- "symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^5.4|^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "files": [
- "Resources/functions.php"
- ],
- "psr-4": {
- "Symfony\\Component\\String\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
- "homepage": "https://symfony.com",
- "keywords": [
- "grapheme",
- "i18n",
- "string",
- "unicode",
- "utf-8",
- "utf8"
- ],
- "support": {
- "source": "https://github.com/symfony/string/tree/v6.4.7"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:22:46+00:00"
- },
- {
- "name": "symfony/translation-contracts",
- "version": "v3.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/translation-contracts.git",
- "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
- "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\Translation\\": ""
- },
- "exclude-from-classmap": [
- "/Test/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to translation",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-18T09:32:20+00:00"
- },
- {
- "name": "twig/twig",
- "version": "v3.10.3",
- "source": {
- "type": "git",
- "url": "https://github.com/twigphp/Twig.git",
- "reference": "67f29781ffafa520b0bbfbd8384674b42db04572"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572",
- "reference": "67f29781ffafa520b0bbfbd8384674b42db04572",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-ctype": "^1.8",
- "symfony/polyfill-mbstring": "^1.3",
- "symfony/polyfill-php80": "^1.22"
- },
- "require-dev": {
- "psr/container": "^1.0|^2.0",
- "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/Resources/core.php",
- "src/Resources/debug.php",
- "src/Resources/escaper.php",
- "src/Resources/string_loader.php"
- ],
- "psr-4": {
- "Twig\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com",
- "homepage": "http://fabien.potencier.org",
- "role": "Lead Developer"
- },
- {
- "name": "Twig Team",
- "role": "Contributors"
- },
- {
- "name": "Armin Ronacher",
- "email": "armin.ronacher@active-4.com",
- "role": "Project Founder"
- }
- ],
- "description": "Twig, the flexible, fast, and secure template language for PHP",
- "homepage": "https://twig.symfony.com",
- "keywords": [
- "templating"
- ],
- "support": {
- "issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.10.3"
- },
- "funding": [
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/twig/twig",
- "type": "tidelift"
- }
- ],
- "time": "2024-05-16T10:04:27+00:00"
- }
- ],
- "packages-dev": [],
- "aliases": [],
- "minimum-stability": "dev",
- "stability-flags": [],
- "prefer-stable": true,
- "prefer-lowest": false,
- "platform": {
- "php": ">=8.1"
- },
- "platform-dev": [],
- "platform-overrides": {
- "php": "8.1.0"
- },
- "plugin-api-version": "2.6.0"
-}
diff --git a/composer.json b/composer.json
index 3b9010d17..df1c451ba 100644
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,7 @@
"php": ">=8.1",
"doctrine/inflector": "^2.0",
"nikic/php-parser": "^4.18|^5.0",
+ "php-cs-fixer/shim": "^v3.64",
"symfony/config": "^6.4|^7.0",
"symfony/console": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
diff --git a/src/Resources/help/MakeAuth.txt b/config/help/MakeAuth.txt
similarity index 100%
rename from src/Resources/help/MakeAuth.txt
rename to config/help/MakeAuth.txt
diff --git a/src/Resources/help/MakeCommand.txt b/config/help/MakeCommand.txt
similarity index 100%
rename from src/Resources/help/MakeCommand.txt
rename to config/help/MakeCommand.txt
diff --git a/src/Resources/help/MakeController.txt b/config/help/MakeController.txt
similarity index 100%
rename from src/Resources/help/MakeController.txt
rename to config/help/MakeController.txt
diff --git a/src/Resources/help/MakeCrud.txt b/config/help/MakeCrud.txt
similarity index 100%
rename from src/Resources/help/MakeCrud.txt
rename to config/help/MakeCrud.txt
diff --git a/src/Resources/help/MakeDockerDatabase.txt b/config/help/MakeDockerDatabase.txt
similarity index 97%
rename from src/Resources/help/MakeDockerDatabase.txt
rename to config/help/MakeDockerDatabase.txt
index b4eaccc3f..426f33943 100644
--- a/src/Resources/help/MakeDockerDatabase.txt
+++ b/config/help/MakeDockerDatabase.txt
@@ -1,5 +1,5 @@
-The %command.name% command generates or updates databases services in compose.yaml
-
-php %command.full_name%
-
-Supports MySQL, MariaDB and PostgreSQL
+The %command.name% command generates or updates databases services in compose.yaml
+
+php %command.full_name%
+
+Supports MySQL, MariaDB and PostgreSQL
diff --git a/src/Resources/help/MakeEntity.txt b/config/help/MakeEntity.txt
similarity index 100%
rename from src/Resources/help/MakeEntity.txt
rename to config/help/MakeEntity.txt
diff --git a/src/Resources/help/MakeFixture.txt b/config/help/MakeFixture.txt
similarity index 100%
rename from src/Resources/help/MakeFixture.txt
rename to config/help/MakeFixture.txt
diff --git a/src/Resources/help/MakeForm.txt b/config/help/MakeForm.txt
similarity index 100%
rename from src/Resources/help/MakeForm.txt
rename to config/help/MakeForm.txt
diff --git a/src/Resources/help/MakeFunctionalTest.txt b/config/help/MakeFunctionalTest.txt
similarity index 100%
rename from src/Resources/help/MakeFunctionalTest.txt
rename to config/help/MakeFunctionalTest.txt
diff --git a/src/Resources/help/MakeListener.txt b/config/help/MakeListener.txt
similarity index 100%
rename from src/Resources/help/MakeListener.txt
rename to config/help/MakeListener.txt
diff --git a/src/Resources/help/MakeMessage.txt b/config/help/MakeMessage.txt
similarity index 100%
rename from src/Resources/help/MakeMessage.txt
rename to config/help/MakeMessage.txt
diff --git a/src/Resources/help/MakeMiddleware.txt b/config/help/MakeMiddleware.txt
similarity index 100%
rename from src/Resources/help/MakeMiddleware.txt
rename to config/help/MakeMiddleware.txt
diff --git a/src/Resources/help/MakeMigration.txt b/config/help/MakeMigration.txt
similarity index 100%
rename from src/Resources/help/MakeMigration.txt
rename to config/help/MakeMigration.txt
diff --git a/src/Resources/help/MakeRegistrationForm.txt b/config/help/MakeRegistrationForm.txt
similarity index 100%
rename from src/Resources/help/MakeRegistrationForm.txt
rename to config/help/MakeRegistrationForm.txt
diff --git a/src/Resources/help/MakeResetPassword.txt b/config/help/MakeResetPassword.txt
similarity index 100%
rename from src/Resources/help/MakeResetPassword.txt
rename to config/help/MakeResetPassword.txt
diff --git a/src/Resources/help/MakeScheduler.txt b/config/help/MakeScheduler.txt
similarity index 100%
rename from src/Resources/help/MakeScheduler.txt
rename to config/help/MakeScheduler.txt
diff --git a/src/Resources/help/MakeSerializerEncoder.txt b/config/help/MakeSerializerEncoder.txt
similarity index 100%
rename from src/Resources/help/MakeSerializerEncoder.txt
rename to config/help/MakeSerializerEncoder.txt
diff --git a/src/Resources/help/MakeSerializerNormalizer.txt b/config/help/MakeSerializerNormalizer.txt
similarity index 100%
rename from src/Resources/help/MakeSerializerNormalizer.txt
rename to config/help/MakeSerializerNormalizer.txt
diff --git a/src/Resources/help/MakeStimulusController.txt b/config/help/MakeStimulusController.txt
similarity index 100%
rename from src/Resources/help/MakeStimulusController.txt
rename to config/help/MakeStimulusController.txt
diff --git a/src/Resources/help/MakeSubscriber.txt b/config/help/MakeSubscriber.txt
similarity index 100%
rename from src/Resources/help/MakeSubscriber.txt
rename to config/help/MakeSubscriber.txt
diff --git a/src/Resources/help/MakeTest.txt b/config/help/MakeTest.txt
similarity index 100%
rename from src/Resources/help/MakeTest.txt
rename to config/help/MakeTest.txt
diff --git a/src/Resources/help/MakeTwigExtension.txt b/config/help/MakeTwigExtension.txt
similarity index 100%
rename from src/Resources/help/MakeTwigExtension.txt
rename to config/help/MakeTwigExtension.txt
diff --git a/src/Resources/help/MakeUnitTest.txt b/config/help/MakeUnitTest.txt
similarity index 100%
rename from src/Resources/help/MakeUnitTest.txt
rename to config/help/MakeUnitTest.txt
diff --git a/src/Resources/help/MakeUser.txt b/config/help/MakeUser.txt
similarity index 100%
rename from src/Resources/help/MakeUser.txt
rename to config/help/MakeUser.txt
diff --git a/src/Resources/help/MakeValidator.txt b/config/help/MakeValidator.txt
similarity index 100%
rename from src/Resources/help/MakeValidator.txt
rename to config/help/MakeValidator.txt
diff --git a/src/Resources/help/MakeVoter.txt b/config/help/MakeVoter.txt
similarity index 100%
rename from src/Resources/help/MakeVoter.txt
rename to config/help/MakeVoter.txt
diff --git a/src/Resources/help/MakeWebhook.txt b/config/help/MakeWebhook.txt
similarity index 100%
rename from src/Resources/help/MakeWebhook.txt
rename to config/help/MakeWebhook.txt
diff --git a/src/Resources/help/_WithTests.txt b/config/help/_WithTests.txt
similarity index 100%
rename from src/Resources/help/_WithTests.txt
rename to config/help/_WithTests.txt
diff --git a/src/Resources/help/_WithUid.txt b/config/help/_WithUid.txt
similarity index 100%
rename from src/Resources/help/_WithUid.txt
rename to config/help/_WithUid.txt
diff --git a/src/Resources/help/security/MakeCustom.txt b/config/help/security/MakeCustom.txt
similarity index 100%
rename from src/Resources/help/security/MakeCustom.txt
rename to config/help/security/MakeCustom.txt
diff --git a/src/Resources/help/security/MakeFormLogin.txt b/config/help/security/MakeFormLogin.txt
similarity index 100%
rename from src/Resources/help/security/MakeFormLogin.txt
rename to config/help/security/MakeFormLogin.txt
diff --git a/src/Resources/config/makers.xml b/config/makers.xml
similarity index 100%
rename from src/Resources/config/makers.xml
rename to config/makers.xml
diff --git a/src/Resources/config/php-cs-fixer.config.php b/config/php-cs-fixer.config.php
similarity index 67%
rename from src/Resources/config/php-cs-fixer.config.php
rename to config/php-cs-fixer.config.php
index 9b5ee2826..59acf276b 100644
--- a/src/Resources/config/php-cs-fixer.config.php
+++ b/config/php-cs-fixer.config.php
@@ -9,6 +9,14 @@
* file that was distributed with this source code.
*/
+/*
+ * This PHP-CS-Fixer config file is used by the TemplateLinter for userland
+ * code when say make:controller is run. If a user does not have a php-cs-fixer
+ * config file, this one is used on the generated PHP files.
+ *
+ * It should not be confused by the root level .php-cs-fixer.dist.php config
+ * which is used to maintain the MakerBundle codebase itself.
+ */
return (new PhpCsFixer\Config())
->setRules([
'@Symfony' => true,
diff --git a/src/Resources/config/services.xml b/config/services.xml
similarity index 98%
rename from src/Resources/config/services.xml
rename to config/services.xml
index 5fbc0439b..8f0b2a209 100644
--- a/src/Resources/config/services.xml
+++ b/config/services.xml
@@ -41,6 +41,7 @@
+
%env(default::string:MAKER_PHP_CS_FIXER_BINARY_PATH)%
%env(default::string:MAKER_PHP_CS_FIXER_CONFIG_PATH)%
diff --git a/src/Resources/doc/index.rst b/docs/index.rst
similarity index 97%
rename from src/Resources/doc/index.rst
rename to docs/index.rst
index 1d56c1e9c..e1942b5e6 100644
--- a/src/Resources/doc/index.rst
+++ b/docs/index.rst
@@ -41,6 +41,9 @@ optional arguments and options. Check them out with the ``--help`` option:
$ php bin/console make:controller --help
+.. caution::
+
+ ``make:entity`` requires ``doctrine/orm`` to be installed and configured. This maker support only ORM, not ODM.
Linting Generated Code
______________________
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d35e0fca4..8cf19ce2a 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -19,8 +19,12 @@
+
+
+
+
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
deleted file mode 100644
index 15c718318..000000000
--- a/src/DependencyInjection/Configuration.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bundle\MakerBundle\DependencyInjection;
-
-use Symfony\Component\Config\Definition\Builder\TreeBuilder;
-use Symfony\Component\Config\Definition\ConfigurationInterface;
-
-class Configuration implements ConfigurationInterface
-{
- public function getConfigTreeBuilder(): TreeBuilder
- {
- $treeBuilder = new TreeBuilder('maker');
- $rootNode = $treeBuilder->getRootNode();
-
- $rootNode
- ->children()
- ->scalarNode('root_namespace')->defaultValue('App')->end()
- ->booleanNode('generate_final_classes')->defaultTrue()->end()
- ->booleanNode('generate_final_entities')->defaultFalse()->end()
- ->end()
- ;
-
- return $treeBuilder;
- }
-}
diff --git a/src/DependencyInjection/MakerExtension.php b/src/DependencyInjection/MakerExtension.php
deleted file mode 100644
index 1de775bff..000000000
--- a/src/DependencyInjection/MakerExtension.php
+++ /dev/null
@@ -1,58 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bundle\MakerBundle\DependencyInjection;
-
-use Symfony\Bundle\MakerBundle\DependencyInjection\CompilerPass\MakeCommandRegistrationPass;
-use Symfony\Bundle\MakerBundle\MakerInterface;
-use Symfony\Component\Config\FileLocator;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Loader;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-
-/**
- * This is the class that loads and manages your bundle configuration.
- *
- * @see http://symfony.com/doc/current/cookbook/bundles/extension.html
- */
-class MakerExtension extends Extension
-{
- public function load(array $configs, ContainerBuilder $container): void
- {
- $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
- $loader->load('services.xml');
- $loader->load('makers.xml');
-
- $configuration = $this->getConfiguration($configs, $container);
- $config = $this->processConfiguration($configuration, $configs);
-
- $rootNamespace = trim($config['root_namespace'], '\\');
-
- $autoloaderFinderDefinition = $container->getDefinition('maker.autoloader_finder');
- $autoloaderFinderDefinition->replaceArgument(0, $rootNamespace);
-
- $makeCommandDefinition = $container->getDefinition('maker.generator');
- $makeCommandDefinition->replaceArgument(1, $rootNamespace);
-
- $doctrineHelperDefinition = $container->getDefinition('maker.doctrine_helper');
- $doctrineHelperDefinition->replaceArgument(0, $rootNamespace.'\\Entity');
-
- $componentGeneratorDefinition = $container->getDefinition('maker.template_component_generator');
- $componentGeneratorDefinition
- ->replaceArgument(0, $config['generate_final_classes'])
- ->replaceArgument(1, $config['generate_final_entities'])
- ->replaceArgument(2, $rootNamespace)
- ;
-
- $container->registerForAutoconfiguration(MakerInterface::class)
- ->addTag(MakeCommandRegistrationPass::MAKER_TAG);
- }
-}
diff --git a/src/Generator.php b/src/Generator.php
index 315b33427..fbadc1bca 100644
--- a/src/Generator.php
+++ b/src/Generator.php
@@ -63,7 +63,7 @@ public function generateClass(string $className, string $templateName, array $va
$targetPath = $this->fileManager->getRelativePathForFutureClass($className);
if (null === $targetPath) {
- throw new \LogicException(\sprintf('Could not determine where to locate the new class "%s", maybe try with a full namespace like "\\My\\Full\\Namespace\\%s"', $className, Str::getShortClassName($className)));
+ throw new \LogicException(\sprintf('Could not determine where to locate the new class "%s", maybe try with a full namespace like "My\\Full\\Namespace\\%s"', $className, Str::getShortClassName($className)));
}
$variables = array_merge($variables, [
@@ -76,6 +76,41 @@ public function generateClass(string $className, string $templateName, array $va
return $targetPath;
}
+ /**
+ * Future replacement for generateClass().
+ *
+ * @internal
+ *
+ * @param string $templateName Template name in the templates/ dir to use
+ * @param array $variables Array of variables to pass to the template
+ * @param bool $isController Set to true if generating a Controller that needs
+ * access to the TemplateComponentGenerator ("generator") in
+ * the twig template. e.g. to create route attributes for a route method
+ *
+ * @return string The path where the file will be created
+ *
+ * @throws \Exception
+ */
+ final public function generateClassFromClassData(ClassData $classData, string $templateName, array $variables = [], bool $isController = false): string
+ {
+ $classData = $this->templateComponentGenerator->configureClass($classData);
+ $targetPath = $this->fileManager->getRelativePathForFutureClass($classData->getFullClassName());
+
+ if (null === $targetPath) {
+ throw new \LogicException(\sprintf('Could not determine where to locate the new class "%s", maybe try with a full namespace like "My\\Full\\Namespace\\%s"', $classData->getFullClassName(), $classData->getClassName()));
+ }
+
+ $globalTemplateVars = ['class_data' => $classData];
+
+ if ($isController) {
+ $globalTemplateVars['generator'] = $this->templateComponentGenerator;
+ }
+
+ $this->addOperation($targetPath, $templateName, array_merge($variables, $globalTemplateVars));
+
+ return $targetPath;
+ }
+
/**
* Generate a normal file from a template.
*
@@ -264,10 +299,14 @@ private function addOperation(string $targetPath, string $templateName, array $v
$templatePath = $templateName;
if (!file_exists($templatePath)) {
- $templatePath = __DIR__.'/Resources/skeleton/'.$templateName;
+ $templatePath = \sprintf('%s/templates/%s', \dirname(__DIR__), $templateName);
if (!file_exists($templatePath)) {
- throw new \Exception(\sprintf('Cannot find template "%s"', $templateName));
+ $templatePath = $this->getTemplateFromLegacySkeletonPath($templateName);
+ }
+
+ if (!file_exists($templatePath)) {
+ throw new \Exception(\sprintf('Cannot find template "%s" in the templates/ dir.', $templateName));
}
}
@@ -276,4 +315,27 @@ private function addOperation(string $targetPath, string $templateName, array $v
'variables' => $variables,
];
}
+
+ /**
+ * @legacy - Remove when public generate methods become "internal" to MakerBundle in v2
+ */
+ private function getTemplateFromLegacySkeletonPath(string $templateName): string
+ {
+ $templatePath = $templateName;
+ if (!file_exists($templatePath)) {
+ $templatePath = __DIR__.'/Resources/skeleton/'.$templateName;
+
+ if (!file_exists($templatePath)) {
+ throw new \Exception(\sprintf('Cannot find template "%s"', $templateName));
+ }
+ }
+
+ @trigger_deprecation(
+ 'symfony/maker-bundle',
+ '1.62.0',
+ 'Storing templates in src/Resources/skeleton is deprecated. Store MakerBundle templates in the "~/templates/" dir instead.',
+ );
+
+ return $templatePath;
+ }
}
diff --git a/src/Maker/AbstractMaker.php b/src/Maker/AbstractMaker.php
index 530bae0dd..bbc00062e 100644
--- a/src/Maker/AbstractMaker.php
+++ b/src/Maker/AbstractMaker.php
@@ -55,4 +55,17 @@ protected function addDependencies(array $dependencies, ?string $message = null)
$message
);
}
+
+ /**
+ * Get the help file contents needed for "setHelp()" of a maker.
+ *
+ * @param string $helpFileName the filename (omit path) of the help file located in config/help/
+ * e.g. MakeController.txt
+ *
+ * @internal
+ */
+ final protected function getHelpFileContents(string $helpFileName): string
+ {
+ return file_get_contents(\sprintf('%s/config/help/%s', \dirname(__DIR__, 2), $helpFileName));
+ }
}
diff --git a/src/Maker/Common/CanGenerateTestsTrait.php b/src/Maker/Common/CanGenerateTestsTrait.php
index 18d7566af..aae231704 100644
--- a/src/Maker/Common/CanGenerateTestsTrait.php
+++ b/src/Maker/Common/CanGenerateTestsTrait.php
@@ -28,7 +28,7 @@ trait CanGenerateTestsTrait
public function configureCommandWithTestsOption(Command $command): Command
{
- $testsHelp = file_get_contents(\dirname(__DIR__, 2).'/Resources/help/_WithTests.txt');
+ $testsHelp = file_get_contents(\dirname(__DIR__, 3).'/config/help/_WithTests.txt');
$help = $command->getHelp()."\n".$testsHelp;
$command
diff --git a/src/Maker/Common/UidTrait.php b/src/Maker/Common/UidTrait.php
index 25e8269de..d3ecb6ea4 100644
--- a/src/Maker/Common/UidTrait.php
+++ b/src/Maker/Common/UidTrait.php
@@ -34,7 +34,7 @@ trait UidTrait
*/
protected function addWithUuidOption(Command $command): Command
{
- $uidHelp = file_get_contents(\dirname(__DIR__, 2).'/Resources/help/_WithUid.txt');
+ $uidHelp = file_get_contents(\dirname(__DIR__, 3).'/config/help/_WithUid.txt');
$help = $command->getHelp()."\n".$uidHelp;
$command
diff --git a/src/Maker/MakeAuthenticator.php b/src/Maker/MakeAuthenticator.php
index 155f44fe7..3f7c9e417 100644
--- a/src/Maker/MakeAuthenticator.php
+++ b/src/Maker/MakeAuthenticator.php
@@ -92,7 +92,8 @@ public static function getCommandDescription(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeAuth.txt'));
+ ->setHelp($this->getHelpFileContents('MakeAuth.txt'))
+ ;
}
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
diff --git a/src/Maker/MakeCommand.php b/src/Maker/MakeCommand.php
index e8f586d19..52d331c53 100644
--- a/src/Maker/MakeCommand.php
+++ b/src/Maker/MakeCommand.php
@@ -58,7 +58,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, \sprintf('Choose a command name (e.g. app:%s>)', Str::asCommand(Str::getRandomTerm())))
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeCommand.txt'))
+ ->setHelp($this->getHelpFileContents('MakeCommand.txt'))
;
}
diff --git a/src/Maker/MakeController.php b/src/Maker/MakeController.php
index 4cf84e1f6..58e049eb5 100644
--- a/src/Maker/MakeController.php
+++ b/src/Maker/MakeController.php
@@ -12,13 +12,15 @@
namespace Symfony\Bundle\MakerBundle\Maker;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
+use Symfony\Bundle\MakerBundle\Maker\Common\CanGenerateTestsTrait;
use Symfony\Bundle\MakerBundle\Str;
+use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData;
use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil;
-use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -34,6 +36,13 @@
*/
final class MakeController extends AbstractMaker
{
+ use CanGenerateTestsTrait;
+
+ private bool $isInvokable;
+ private ClassData $controllerClassData;
+ private bool $usesTwigTemplate;
+ private string $twigTemplatePath;
+
public function __construct(private ?PhpCompatUtil $phpCompatUtil = null)
{
if (null !== $phpCompatUtil) {
@@ -61,55 +70,89 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
->addArgument('controller-class', InputArgument::OPTIONAL, \sprintf('Choose a name for your controller class (e.g. %sController>)', Str::asClassName(Str::getRandomTerm())))
->addOption('no-template', null, InputOption::VALUE_NONE, 'Use this option to disable template generation')
->addOption('invokable', 'i', InputOption::VALUE_NONE, 'Use this option to create an invokable controller')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeController.txt'))
+ ->setHelp($this->getHelpFileContents('MakeController.txt'))
;
+
+ $this->configureCommandWithTestsOption($command);
}
- public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
+ public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
{
- $controllerClassNameDetails = $generator->createClassNameDetails(
- $input->getArgument('controller-class'),
- 'Controller\\',
- 'Controller'
- );
+ $this->usesTwigTemplate = $this->isTwigInstalled() && !$input->getOption('no-template');
+ $this->isInvokable = (bool) $input->getOption('invokable');
- $withTemplate = $this->isTwigInstalled() && !$input->getOption('no-template');
- $isInvokable = (bool) $input->getOption('invokable');
-
- $useStatements = new UseStatementGenerator([
- AbstractController::class,
- $withTemplate ? Response::class : JsonResponse::class,
- Route::class,
- ]);
-
- $templateName = Str::asFilePath($controllerClassNameDetails->getRelativeNameWithoutSuffix())
- .($isInvokable ? '.html.twig' : '/index.html.twig');
-
- $controllerPath = $generator->generateController(
- $controllerClassNameDetails->getFullName(),
- 'controller/Controller.tpl.php',
- [
- 'use_statements' => $useStatements,
- 'route_path' => Str::asRoutePath($controllerClassNameDetails->getRelativeNameWithoutSuffix()),
- 'route_name' => Str::asRouteName($controllerClassNameDetails->getRelativeNameWithoutSuffix()),
- 'method_name' => $isInvokable ? '__invoke' : 'index',
- 'with_template' => $withTemplate,
- 'template_name' => $templateName,
+ $controllerClass = $input->getArgument('controller-class');
+ $controllerClassName = \sprintf('Controller\%s', $controllerClass);
+
+ // If the class name provided is absolute, we do not assume it will live in src/Controller
+ // e.g. src/Custom/Location/For/MyController instead of src/Controller/MyController
+ if ($isAbsoluteNamespace = '\\' === $controllerClass[0]) {
+ $controllerClassName = substr($controllerClass, 1);
+ }
+
+ $this->controllerClassData = ClassData::create(
+ class: $controllerClassName,
+ suffix: 'Controller',
+ extendsClass: AbstractController::class,
+ useStatements: [
+ $this->usesTwigTemplate ? Response::class : JsonResponse::class,
+ Route::class,
]
);
- if ($withTemplate) {
+ // Again if the class name is absolute, lets not make assumptions about where the twig template
+ // should live. E.g. templates/custom/location/for/my_controller.html.twig instead of
+ // templates/my/controller.html.twig. We do however remove the root_namespace prefix in either case
+ // so we don't end up with templates/app/my/controller.html.twig
+ $templateName = $isAbsoluteNamespace ?
+ $this->controllerClassData->getFullClassName(withoutRootNamespace: true, withoutSuffix: true) :
+ $this->controllerClassData->getClassName(relative: true, withoutSuffix: true)
+ ;
+
+ // Convert the twig template name into a file path where it will be generated.
+ $this->twigTemplatePath = \sprintf('%s%s', Str::asFilePath($templateName), $this->isInvokable ? '.html.twig' : '/index.html.twig');
+
+ $this->interactSetGenerateTests($input, $io);
+ }
+
+ public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
+ {
+ $controllerPath = $generator->generateClassFromClassData($this->controllerClassData, 'controller/Controller.tpl.php', [
+ 'route_path' => Str::asRoutePath($this->controllerClassData->getClassName(relative: true, withoutSuffix: true)),
+ 'route_name' => Str::AsRouteName($this->controllerClassData->getClassName(relative: true, withoutSuffix: true)),
+ 'method_name' => $this->isInvokable ? '__invoke' : 'index',
+ 'with_template' => $this->usesTwigTemplate,
+ 'template_name' => $this->twigTemplatePath,
+ ], true);
+
+ if ($this->usesTwigTemplate) {
$generator->generateTemplate(
- $templateName,
+ $this->twigTemplatePath,
'controller/twig_template.tpl.php',
[
'controller_path' => $controllerPath,
'root_directory' => $generator->getRootDirectory(),
- 'class_name' => $controllerClassNameDetails->getShortName(),
+ 'class_name' => $this->controllerClassData->getClassName(),
]
);
}
+ if ($this->shouldGenerateTests()) {
+ $testClassData = ClassData::create(
+ class: \sprintf('Tests\Controller\%s', $this->controllerClassData->getClassName(relative: true, withoutSuffix: true)),
+ suffix: 'ControllerTest',
+ extendsClass: WebTestCase::class,
+ );
+
+ $generator->generateClassFromClassData($testClassData, 'controller/test/Test.tpl.php', [
+ 'route_path' => Str::asRoutePath($this->controllerClassData->getClassName(relative: true, withoutSuffix: true)),
+ ]);
+
+ if (!class_exists(WebTestCase::class)) {
+ $io->caution('You\'ll need to install the `symfony/test-pack` to execute the tests for your new controller.');
+ }
+ }
+
$generator->writeChanges();
$this->writeSuccessMessage($io);
diff --git a/src/Maker/MakeCrud.php b/src/Maker/MakeCrud.php
index 0a37b2ba4..f535d24bd 100644
--- a/src/Maker/MakeCrud.php
+++ b/src/Maker/MakeCrud.php
@@ -71,7 +71,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('entity-class', InputArgument::OPTIONAL, \sprintf('The class name of the entity to create CRUD (e.g. %s>)', Str::asClassName(Str::getRandomTerm())))
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeCrud.txt'))
+ ->setHelp($this->getHelpFileContents('MakeCrud.txt'))
;
$inputConfig->setArgumentAsNonInteractive('entity-class');
diff --git a/src/Maker/MakeDockerDatabase.php b/src/Maker/MakeDockerDatabase.php
index bb8391669..5f6ffcb08 100644
--- a/src/Maker/MakeDockerDatabase.php
+++ b/src/Maker/MakeDockerDatabase.php
@@ -65,7 +65,7 @@ public static function getCommandDescription(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeDockerDatabase.txt'))
+ ->setHelp($this->getHelpFileContents('MakeDockerDatabase.txt'))
;
}
diff --git a/src/Maker/MakeEntity.php b/src/Maker/MakeEntity.php
index dfc25301d..e0498f36b 100644
--- a/src/Maker/MakeEntity.php
+++ b/src/Maker/MakeEntity.php
@@ -97,7 +97,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
->addOption('broadcast', 'b', InputOption::VALUE_NONE, 'Add the ability to broadcast entity updates using Symfony UX Turbo?')
->addOption('regenerate', null, InputOption::VALUE_NONE, 'Instead of adding new fields, simply generate the methods (e.g. getter/setter) for existing fields')
->addOption('overwrite', null, InputOption::VALUE_NONE, 'Overwrite any existing getter/setter methods')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeEntity.txt'))
+ ->setHelp($this->getHelpFileContents('MakeEntity.txt'))
;
$this->addWithUuidOption($command);
diff --git a/src/Maker/MakeFixtures.php b/src/Maker/MakeFixtures.php
index befc384bc..137ef5c98 100644
--- a/src/Maker/MakeFixtures.php
+++ b/src/Maker/MakeFixtures.php
@@ -44,7 +44,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('fixtures-class', InputArgument::OPTIONAL, 'The class name of the fixtures to create (e.g. AppFixtures>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeFixture.txt'))
+ ->setHelp($this->getHelpFileContents('MakeFixture.txt'))
;
}
diff --git a/src/Maker/MakeForm.php b/src/Maker/MakeForm.php
index 4859064b8..7387ead57 100644
--- a/src/Maker/MakeForm.php
+++ b/src/Maker/MakeForm.php
@@ -53,7 +53,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
$command
->addArgument('name', InputArgument::OPTIONAL, \sprintf('The name of the form class (e.g. %sType>)', Str::asClassName(Str::getRandomTerm())))
->addArgument('bound-class', InputArgument::OPTIONAL, 'The name of Entity or fully qualified model class name that the new form will be bound to (empty for none)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeForm.txt'))
+ ->setHelp($this->getHelpFileContents('MakeForm.txt'))
;
$inputConfig->setArgumentAsNonInteractive('bound-class');
diff --git a/src/Maker/MakeFunctionalTest.php b/src/Maker/MakeFunctionalTest.php
index 69277c585..16f0281c0 100644
--- a/src/Maker/MakeFunctionalTest.php
+++ b/src/Maker/MakeFunctionalTest.php
@@ -50,7 +50,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the functional test class (e.g. DefaultControllerTest>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeFunctionalTest.txt'))
+ ->setHelp($this->getHelpFileContents('MakeFunctionalTest.txt'))
;
}
diff --git a/src/Maker/MakeListener.php b/src/Maker/MakeListener.php
index 298c419ec..6b00b51f2 100644
--- a/src/Maker/MakeListener.php
+++ b/src/Maker/MakeListener.php
@@ -66,7 +66,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
$command
->addArgument('name', InputArgument::OPTIONAL, 'Choose a class name for your event listener or subscriber (e.g. ExceptionListener> or ExceptionSubscriber>)')
->addArgument('event', InputArgument::OPTIONAL, 'What event do you want to listen to?')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeListener.txt'))
+ ->setHelp($this->getHelpFileContents('MakeListener.txt'))
;
$inputConfig->setArgumentAsNonInteractive('event');
diff --git a/src/Maker/MakeMessage.php b/src/Maker/MakeMessage.php
index 682601a44..74fc1e692 100644
--- a/src/Maker/MakeMessage.php
+++ b/src/Maker/MakeMessage.php
@@ -50,7 +50,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the message class (e.g. SendEmailMessage>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeMessage.txt'))
+ ->setHelp($this->getHelpFileContents('MakeMessage.txt'))
;
}
diff --git a/src/Maker/MakeMessengerMiddleware.php b/src/Maker/MakeMessengerMiddleware.php
index 2b1c189e9..f640d90cb 100644
--- a/src/Maker/MakeMessengerMiddleware.php
+++ b/src/Maker/MakeMessengerMiddleware.php
@@ -45,7 +45,8 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the middleware class (e.g. CustomMiddleware>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeMessage.txt'));
+ ->setHelp($this->getHelpFileContents('MakeMessage.txt'))
+ ;
}
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
diff --git a/src/Maker/MakeMigration.php b/src/Maker/MakeMigration.php
index 5c0afc054..206a8d84d 100644
--- a/src/Maker/MakeMigration.php
+++ b/src/Maker/MakeMigration.php
@@ -60,7 +60,7 @@ public function setApplication(Application $application)
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeMigration.txt'))
+ ->setHelp($this->getHelpFileContents('MakeMigration.txt'))
;
if (class_exists(MigrationsDiffDoctrineCommand::class)) {
diff --git a/src/Maker/MakeRegistrationForm.php b/src/Maker/MakeRegistrationForm.php
index eeb5237ee..48a8ae34a 100644
--- a/src/Maker/MakeRegistrationForm.php
+++ b/src/Maker/MakeRegistrationForm.php
@@ -108,7 +108,7 @@ public static function getCommandDescription(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeRegistrationForm.txt'))
+ ->setHelp($this->getHelpFileContents('MakeRegistrationForm.txt'))
;
$this->configureCommandWithTestsOption($command);
diff --git a/src/Maker/MakeResetPassword.php b/src/Maker/MakeResetPassword.php
index 38938f24f..ae7b039c7 100644
--- a/src/Maker/MakeResetPassword.php
+++ b/src/Maker/MakeResetPassword.php
@@ -119,7 +119,7 @@ public static function getCommandDescription(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeResetPassword.txt'))
+ ->setHelp($this->getHelpFileContents('MakeResetPassword.txt'))
;
$this->addWithUuidOption($command);
diff --git a/src/Maker/MakeSchedule.php b/src/Maker/MakeSchedule.php
index 999fd000f..ff1c94ffd 100644
--- a/src/Maker/MakeSchedule.php
+++ b/src/Maker/MakeSchedule.php
@@ -58,7 +58,7 @@ public static function getCommandDescription(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeScheduler.txt'))
+ ->setHelp($this->getHelpFileContents('MakeScheduler.txt'))
;
}
diff --git a/src/Maker/MakeSerializerEncoder.php b/src/Maker/MakeSerializerEncoder.php
index 7bdb69f11..8fc033b6b 100644
--- a/src/Maker/MakeSerializerEncoder.php
+++ b/src/Maker/MakeSerializerEncoder.php
@@ -44,7 +44,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
$command
->addArgument('name', InputArgument::OPTIONAL, 'Choose a class name for your encoder (e.g. YamlEncoder>)')
->addArgument('format', InputArgument::OPTIONAL, 'Pick your format name (e.g. yaml>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeSerializerEncoder.txt'))
+ ->setHelp($this->getHelpFileContents('MakeSerializerEncoder.txt'))
;
}
diff --git a/src/Maker/MakeSerializerNormalizer.php b/src/Maker/MakeSerializerNormalizer.php
index a23f24d56..39381ece1 100644
--- a/src/Maker/MakeSerializerNormalizer.php
+++ b/src/Maker/MakeSerializerNormalizer.php
@@ -54,7 +54,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'Choose a class name for your normalizer (e.g. UserNormalizer>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeSerializerNormalizer.txt'))
+ ->setHelp($this->getHelpFileContents('MakeSerializerNormalizer.txt'))
;
}
diff --git a/src/Maker/MakeStimulusController.php b/src/Maker/MakeStimulusController.php
index 95bee3890..0610c7d3b 100644
--- a/src/Maker/MakeStimulusController.php
+++ b/src/Maker/MakeStimulusController.php
@@ -44,7 +44,8 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::REQUIRED, 'The name of the Stimulus controller (e.g. hello>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeStimulusController.txt'));
+ ->setHelp($this->getHelpFileContents('MakeStimulusController.txt'))
+ ;
}
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
diff --git a/src/Maker/MakeSubscriber.php b/src/Maker/MakeSubscriber.php
index faba42df3..cf1002c82 100644
--- a/src/Maker/MakeSubscriber.php
+++ b/src/Maker/MakeSubscriber.php
@@ -55,7 +55,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
$command
->addArgument('name', InputArgument::OPTIONAL, 'Choose a class name for your event subscriber (e.g. ExceptionSubscriber>)')
->addArgument('event', InputArgument::OPTIONAL, 'What event do you want to subscribe to?')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeSubscriber.txt'))
+ ->setHelp($this->getHelpFileContents('MakeSubscriber.txt'))
;
$inputConfig->setArgumentAsNonInteractive('event');
diff --git a/src/Maker/MakeTest.php b/src/Maker/MakeTest.php
index 25ffa3512..47be59ab0 100644
--- a/src/Maker/MakeTest.php
+++ b/src/Maker/MakeTest.php
@@ -82,7 +82,8 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
$command
->addArgument('type', InputArgument::OPTIONAL, 'The type of test: '.implode(', ', $typesDesc))
->addArgument('name', InputArgument::OPTIONAL, 'The name of the test class (e.g. BlogPostTest>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeTest.txt').implode("\n", $typesHelp));
+ ->setHelp($this->getHelpFileContents('MakeTest.txt').implode("\n", $typesHelp))
+ ;
$inputConfig->setArgumentAsNonInteractive('name');
$inputConfig->setArgumentAsNonInteractive('type');
diff --git a/src/Maker/MakeTwigComponent.php b/src/Maker/MakeTwigComponent.php
index 91908ebe5..4bf55ee8d 100644
--- a/src/Maker/MakeTwigComponent.php
+++ b/src/Maker/MakeTwigComponent.php
@@ -79,14 +79,14 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
$generator->generateClass(
$factory->getFullName(),
- \sprintf('%s/../Resources/skeleton/twig/%s', __DIR__, $live ? 'LiveComponent.tpl.php' : 'Component.tpl.php'),
+ \sprintf('%s/templates/twig/%s', \dirname(__DIR__, 2), $live ? 'LiveComponent.tpl.php' : 'Component.tpl.php'),
[
'live' => $live,
]
);
$generator->generateTemplate(
"components/{$templatePath}.html.twig",
- \sprintf('%s/../Resources/skeleton/twig/%s', __DIR__, 'component_template.tpl.php')
+ \sprintf('%s/templates/twig/%s', \dirname(__DIR__, 2), 'component_template.tpl.php')
);
$generator->writeChanges();
diff --git a/src/Maker/MakeTwigExtension.php b/src/Maker/MakeTwigExtension.php
index a51ffe996..809b09259 100644
--- a/src/Maker/MakeTwigExtension.php
+++ b/src/Maker/MakeTwigExtension.php
@@ -44,7 +44,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the Twig extension class (e.g. AppExtension>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeTwigExtension.txt'))
+ ->setHelp($this->getHelpFileContents('MakeTwigExtension.txt'))
;
}
diff --git a/src/Maker/MakeUnitTest.php b/src/Maker/MakeUnitTest.php
index d7ef272f6..79a407fbd 100644
--- a/src/Maker/MakeUnitTest.php
+++ b/src/Maker/MakeUnitTest.php
@@ -45,7 +45,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the unit test class (e.g. UtilTest>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeUnitTest.txt'))
+ ->setHelp($this->getHelpFileContents('MakeUnitTest.txt'))
;
}
diff --git a/src/Maker/MakeUser.php b/src/Maker/MakeUser.php
index 8027672f6..ddfd0721a 100644
--- a/src/Maker/MakeUser.php
+++ b/src/Maker/MakeUser.php
@@ -77,7 +77,8 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
->addOption('is-entity', null, InputOption::VALUE_NONE, 'Do you want to store user data in the database (via Doctrine)?')
->addOption('identity-property-name', null, InputOption::VALUE_REQUIRED, 'Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid)')
->addOption('with-password', null, InputOption::VALUE_NONE, 'Will this app be responsible for checking the password? Choose No if the password is actually checked by some other system (e.g. a single sign-on server)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeUser.txt'));
+ ->setHelp($this->getHelpFileContents('MakeUser.txt'))
+ ;
$this->addWithUuidOption($command);
diff --git a/src/Maker/MakeValidator.php b/src/Maker/MakeValidator.php
index 7fb12c299..f638a12d5 100644
--- a/src/Maker/MakeValidator.php
+++ b/src/Maker/MakeValidator.php
@@ -16,9 +16,12 @@
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Str;
+use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Validation;
/**
@@ -42,33 +45,38 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the validator class (e.g. EnabledValidator>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeValidator.txt'))
+ ->setHelp($this->getHelpFileContents('MakeValidator.txt'))
;
}
/** @return void */
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
{
- $validatorClassNameDetails = $generator->createClassNameDetails(
- $input->getArgument('name'),
- 'Validator\\',
- 'Validator'
+ $validatorClassData = ClassData::create(
+ class: \sprintf('Validator\\%s', $input->getArgument('name')),
+ suffix: 'Validator',
+ extendsClass: ConstraintValidator::class,
+ useStatements: [
+ Constraint::class,
+ ],
);
- $constraintFullClassName = Str::removeSuffix($validatorClassNameDetails->getFullName(), 'Validator');
+ $constraintDataClass = ClassData::create(
+ class: \sprintf('Validator\\%s', Str::removeSuffix($validatorClassData->getClassName(), 'Validator')),
+ extendsClass: Constraint::class,
+ );
- $generator->generateClass(
- $validatorClassNameDetails->getFullName(),
+ $generator->generateClassFromClassData(
+ $validatorClassData,
'validator/Validator.tpl.php',
[
- 'constraint_class_name' => Str::getShortClassName($constraintFullClassName),
+ 'constraint_class_name' => $constraintDataClass->getClassName(),
]
);
- $generator->generateClass(
- $constraintFullClassName,
+ $generator->generateClassFromClassData(
+ $constraintDataClass,
'validator/Constraint.tpl.php',
- []
);
$generator->writeChanges();
diff --git a/src/Maker/MakeVoter.php b/src/Maker/MakeVoter.php
index faabc993e..0e12f28f1 100644
--- a/src/Maker/MakeVoter.php
+++ b/src/Maker/MakeVoter.php
@@ -43,7 +43,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'The name of the security voter class (e.g. BlogPostVoter>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeVoter.txt'))
+ ->setHelp($this->getHelpFileContents('MakeVoter.txt'))
;
}
@@ -60,10 +60,9 @@ class: \sprintf('Security\Voter\%s', $input->getArgument('name')),
]
);
- $generator->generateClass(
- $voterClassData->getFullClassName(),
+ $generator->generateClassFromClassData(
+ $voterClassData,
'security/Voter.tpl.php',
- ['class_data' => $voterClassData]
);
$generator->writeChanges();
diff --git a/src/Maker/MakeWebhook.php b/src/Maker/MakeWebhook.php
index a0c77a074..a7b3f2423 100644
--- a/src/Maker/MakeWebhook.php
+++ b/src/Maker/MakeWebhook.php
@@ -90,7 +90,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
{
$command
->addArgument('name', InputArgument::OPTIONAL, 'Name of the webhook to create (e.g. github, stripe, ...>)')
- ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeWebhook.txt'))
+ ->setHelp($this->getHelpFileContents('MakeWebhook.txt'))
;
$inputConfig->setArgumentAsNonInteractive('name');
diff --git a/src/Maker/Security/MakeCustomAuthenticator.php b/src/Maker/Security/MakeCustomAuthenticator.php
index 6cc1407f6..c3ecae946 100644
--- a/src/Maker/Security/MakeCustomAuthenticator.php
+++ b/src/Maker/Security/MakeCustomAuthenticator.php
@@ -68,7 +68,7 @@ public static function getCommandDescription(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
$command
- ->setHelp(file_get_contents(__DIR__.'/../../Resources/help/security/MakeCustom.txt'))
+ ->setHelp($this->getHelpFileContents('security/MakeCustom.txt'))
;
}
diff --git a/src/Maker/Security/MakeFormLogin.php b/src/Maker/Security/MakeFormLogin.php
index 8ae6e012e..641c048d9 100644
--- a/src/Maker/Security/MakeFormLogin.php
+++ b/src/Maker/Security/MakeFormLogin.php
@@ -77,7 +77,9 @@ public static function getCommandName(): string
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
{
- $command->setHelp(file_get_contents(\dirname(__DIR__, 2).'/Resources/help/security/MakeFormLogin.txt'));
+ $command
+ ->setHelp($this->getHelpFileContents('security/MakeFormLogin.txt'))
+ ;
$this->configureCommandWithTestsOption($command);
}
diff --git a/src/MakerBundle.php b/src/MakerBundle.php
index 427e2103c..42516aec8 100644
--- a/src/MakerBundle.php
+++ b/src/MakerBundle.php
@@ -14,16 +14,57 @@
use Symfony\Bundle\MakerBundle\DependencyInjection\CompilerPass\MakeCommandRegistrationPass;
use Symfony\Bundle\MakerBundle\DependencyInjection\CompilerPass\RemoveMissingParametersPass;
use Symfony\Bundle\MakerBundle\DependencyInjection\CompilerPass\SetDoctrineAnnotatedPrefixesPass;
+use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
/**
* @author Javier Eguiluz
* @author Ryan Weaver
*/
-class MakerBundle extends Bundle
+class MakerBundle extends AbstractBundle
{
+ protected string $extensionAlias = 'maker';
+
+ public function configure(DefinitionConfigurator $definition): void
+ {
+ $definition->rootNode()
+ ->children()
+ ->scalarNode('root_namespace')->defaultValue('App')->end()
+ ->booleanNode('generate_final_classes')->defaultTrue()->end()
+ ->booleanNode('generate_final_entities')->defaultFalse()->end()
+ ->end()
+ ;
+ }
+
+ public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
+ {
+ $container->import('../config/services.xml');
+ $container->import('../config/makers.xml');
+
+ $rootNamespace = trim($config['root_namespace'], '\\');
+
+ $container->services()
+ ->get('maker.autoloader_finder')
+ ->arg(0, $rootNamespace)
+ ->get('maker.generator')
+ ->arg(1, $rootNamespace)
+ ->get('maker.doctrine_helper')
+ ->arg(0, \sprintf('%s\\Entity', $rootNamespace))
+ ->get('maker.template_component_generator')
+ ->arg(0, $config['generate_final_classes'])
+ ->arg(1, $config['generate_final_entities'])
+ ->arg(2, $rootNamespace)
+ ;
+
+ $builder
+ ->registerForAutoconfiguration(MakerInterface::class)
+ ->addTag(MakeCommandRegistrationPass::MAKER_TAG)
+ ;
+ }
+
public function build(ContainerBuilder $container): void
{
// add a priority so we run before the core command pass
diff --git a/src/Resources/bin/php-cs-fixer-v3.49.0.phar b/src/Resources/bin/php-cs-fixer-v3.49.0.phar
deleted file mode 100755
index cbbbe5834..000000000
Binary files a/src/Resources/bin/php-cs-fixer-v3.49.0.phar and /dev/null differ
diff --git a/src/Resources/skeleton/validator/Constraint.tpl.php b/src/Resources/skeleton/validator/Constraint.tpl.php
deleted file mode 100644
index 7baafa472..000000000
--- a/src/Resources/skeleton/validator/Constraint.tpl.php
+++ /dev/null
@@ -1,20 +0,0 @@
-= "
-
-namespace = $namespace; ?>;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * @Annotation
- *
- * @Target({"PROPERTY", "METHOD", "ANNOTATION"})
- */
-#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
-class = $class_name ?> extends Constraint
-{
- /*
- * Any public properties become valid options for the annotation.
- * Then, use these in your validator class.
- */
- public string $message = 'The value "{{ value }}" is not valid.';
-}
diff --git a/src/Test/MakerTestRunner.php b/src/Test/MakerTestRunner.php
index 0eb07a3e0..4e6287437 100644
--- a/src/Test/MakerTestRunner.php
+++ b/src/Test/MakerTestRunner.php
@@ -35,7 +35,16 @@ public function runMaker(array $inputs, string $argumentsString = '', bool $allo
{
$this->executedMakerProcess = $this->environment->runMaker($inputs, $argumentsString, $allowedToFail, $envVars);
- return $this->executedMakerProcess->getOutput();
+ $output = $this->executedMakerProcess->getOutput();
+
+ // Allows for debugging the actual CLI output from within a test process. E.g. Manually viewing the output of the
+ // `make:voter` command that was run within the MakeVoterTest from your local command line.
+ // You should never use this in CI unless you know what you're doing - resource intensive.
+ if ('true' === getenv('MAKER_TEST_DUMP_OUTPUT')) {
+ dump(['Maker Process Output' => $output, 'Maker Process Error Output' => $this->executedMakerProcess->getErrorOutput()]);
+ }
+
+ return $output;
}
/**
@@ -198,7 +207,7 @@ public function updateSchema(): void
public function runTests(): void
{
$internalTestProcess = MakerTestProcess::create(
- \sprintf('php %s', $this->getPath('/bin/phpunit')),
+ \sprintf('php %s', $this->getPath('bin/phpunit')),
$this->environment->getPath())
->run(true)
;
diff --git a/src/Util/ClassSource/Model/ClassData.php b/src/Util/ClassSource/Model/ClassData.php
index 988404f2a..4ce0cd605 100644
--- a/src/Util/ClassSource/Model/ClassData.php
+++ b/src/Util/ClassSource/Model/ClassData.php
@@ -29,7 +29,11 @@ private function __construct(
private UseStatementGenerator $useStatementGenerator,
private bool $isFinal = true,
private string $rootNamespace = 'App',
+ private ?string $classSuffix = null,
) {
+ if (str_starts_with(haystack: $this->namespace, needle: $this->rootNamespace)) {
+ $this->namespace = substr_replace(string: $this->namespace, replace: '', offset: 0, length: \strlen($this->rootNamespace) + 1);
+ }
}
public static function create(string $class, ?string $suffix = null, ?string $extendsClass = null, bool $isEntity = false, array $useStatements = []): self
@@ -52,12 +56,30 @@ className: Str::asClassName($className),
extends: null === $extendsClass ? null : Str::getShortClassName($extendsClass),
isEntity: $isEntity,
useStatementGenerator: $useStatements,
+ classSuffix: $suffix,
);
}
- public function getClassName(): string
+ public function getClassName(bool $relative = false, bool $withoutSuffix = false): string
{
- return $this->className;
+ if (!$withoutSuffix && !$relative) {
+ return $this->className;
+ }
+
+ if ($relative) {
+ $class = \sprintf('%s\%s', $this->namespace, $this->className);
+
+ $firstNsSeparatorPosition = stripos($class, '\\');
+ $class = substr_replace(string: $class, replace: '', offset: 0, length: $firstNsSeparatorPosition + 1);
+
+ if ($withoutSuffix) {
+ $class = Str::removeSuffix($class, $this->classSuffix);
+ }
+
+ return $class;
+ }
+
+ return Str::removeSuffix($this->className, $this->classSuffix);
}
public function getNamespace(): string
@@ -66,12 +88,31 @@ public function getNamespace(): string
return $this->rootNamespace;
}
+ // Namespace is already absolute, don't add the rootNamespace.
+ if (str_starts_with($this->namespace, '\\')) {
+ return substr_replace($this->namespace, '', 0, 1);
+ }
+
return \sprintf('%s\%s', $this->rootNamespace, $this->namespace);
}
- public function getFullClassName(): string
+ /**
+ * Get the full class name.
+ *
+ * @param bool $withoutRootNamespace Get the full class name without global root namespace. e.g. "App"
+ * @param bool $withoutSuffix Get the full class name without the class suffix. e.g. "MyController" instead of "MyControllerController"
+ */
+ public function getFullClassName($withoutRootNamespace = false, $withoutSuffix = false): string
{
- return \sprintf('%s\%s', $this->getNamespace(), $this->className);
+ $className = \sprintf('%s\%s', $this->getNamespace(), $withoutSuffix ? Str::removeSuffix($this->className, $this->classSuffix) : $this->className);
+
+ if ($withoutRootNamespace) {
+ if (str_starts_with(haystack: $className, needle: $this->rootNamespace)) {
+ $className = substr_replace(string: $className, replace: '', offset: 0, length: \strlen($this->rootNamespace) + 1);
+ }
+ }
+
+ return $className;
}
public function setRootNamespace(string $rootNamespace): self
diff --git a/src/Util/ClassSourceManipulator.php b/src/Util/ClassSourceManipulator.php
index 25b57bdbb..e68211223 100644
--- a/src/Util/ClassSourceManipulator.php
+++ b/src/Util/ClassSourceManipulator.php
@@ -143,7 +143,7 @@ public function addEntityField(ClassProperty $mapping): void
}
$propertyType = $typeHint;
- if ($propertyType && !$defaultValue) {
+ if ($propertyType && !$defaultValue && 'mixed' !== $propertyType) {
// all property types
$propertyType = '?'.$propertyType;
}
@@ -162,13 +162,13 @@ public function addEntityField(ClassProperty $mapping): void
// getter methods always have nullable return values
// because even though these are required in the db, they may not be set yet
// unless there is a default value
- null === $defaultValue,
+ null === $defaultValue && 'mixed' !== $propertyType,
$commentLines
);
// don't generate setters for id fields
if (!($mapping->id ?? false)) {
- $this->addSetter($mapping->propertyName, $typeHint, $nullable);
+ $this->addSetter($mapping->propertyName, $typeHint, $nullable && 'mixed' !== $propertyType);
}
}
@@ -485,10 +485,6 @@ private function createSetterNodeBuilder(string $propertyName, $type, bool $isNu
private function getSetterName(string $propertyName, $type): string
{
- if ('bool' === $type && 0 === strncasecmp($propertyName, 'is', 2)) {
- return 'set'.Str::asCamelCase(substr($propertyName, 2));
- }
-
return 'set'.Str::asCamelCase($propertyName);
}
diff --git a/src/Util/TemplateLinter.php b/src/Util/TemplateLinter.php
index 1d29d195d..19907938d 100644
--- a/src/Util/TemplateLinter.php
+++ b/src/Util/TemplateLinter.php
@@ -12,6 +12,7 @@
namespace Symfony\Bundle\MakerBundle\Util;
use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
+use Symfony\Bundle\MakerBundle\FileManager;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
@@ -25,14 +26,12 @@
*/
final class TemplateLinter
{
- // Version must match bundled version file name. e.g. php-cs-fixer-v3.49.9.phar
- public const BUNDLED_PHP_CS_FIXER_VERSION = '3.49.0';
-
private bool $usingBundledPhpCsFixer = true;
private bool $usingBundledPhpCsFixerConfig = true;
private bool $needsPhpCmdPrefix = true;
public function __construct(
+ private FileManager $fileManager,
private ?string $phpCsFixerBinaryPath = null,
private ?string $phpCsFixerConfigPath = null,
) {
@@ -98,9 +97,15 @@ public function writeLinterMessage(OutputInterface $output): void
private function setBinary(): void
{
- // Use Bundled PHP-CS-Fixer
+ // Use Bundled (shim) PHP-CS-Fixer
if (null === $this->phpCsFixerBinaryPath) {
- $this->phpCsFixerBinaryPath = \sprintf('%s/Resources/bin/php-cs-fixer-v%s.phar', \dirname(__DIR__), self::BUNDLED_PHP_CS_FIXER_VERSION);
+ $shimLocation = \sprintf('%s/vendor/bin/php-cs-fixer', \dirname(__DIR__, 2));
+
+ if (is_file($shimLocation)) {
+ $this->phpCsFixerBinaryPath = $shimLocation;
+
+ return;
+ }
return;
}
@@ -129,7 +134,8 @@ private function setBinary(): void
private function setConfig(): void
{
// No config provided, but there is a dist config file in the project dir
- if (null === $this->phpCsFixerConfigPath && file_exists($defaultConfigPath = '.php-cs-fixer.dist.php')) {
+ $defaultConfigPath = \sprintf('%s/.php-cs-fixer.dist.php', $this->fileManager->getRootDirectory());
+ if (null === $this->phpCsFixerConfigPath && file_exists($defaultConfigPath)) {
$this->phpCsFixerConfigPath = $defaultConfigPath;
$this->usingBundledPhpCsFixerConfig = false;
@@ -139,7 +145,7 @@ private function setConfig(): void
// No config provided and no project dist config - use our config
if (null === $this->phpCsFixerConfigPath) {
- $this->phpCsFixerConfigPath = \dirname(__DIR__).'/Resources/config/php-cs-fixer.config.php';
+ $this->phpCsFixerConfigPath = \sprintf('%s/config/php-cs-fixer.config.php', \dirname(__DIR__, 2));
return;
}
diff --git a/src/Resources/skeleton/Class.tpl.php b/templates/Class.tpl.php
similarity index 100%
rename from src/Resources/skeleton/Class.tpl.php
rename to templates/Class.tpl.php
diff --git a/src/Resources/skeleton/authenticator/EmptyAuthenticator.tpl.php b/templates/authenticator/EmptyAuthenticator.tpl.php
similarity index 100%
rename from src/Resources/skeleton/authenticator/EmptyAuthenticator.tpl.php
rename to templates/authenticator/EmptyAuthenticator.tpl.php
diff --git a/src/Resources/skeleton/authenticator/EmptySecurityController.tpl.php b/templates/authenticator/EmptySecurityController.tpl.php
similarity index 100%
rename from src/Resources/skeleton/authenticator/EmptySecurityController.tpl.php
rename to templates/authenticator/EmptySecurityController.tpl.php
diff --git a/src/Resources/skeleton/authenticator/LoginFormAuthenticator.tpl.php b/templates/authenticator/LoginFormAuthenticator.tpl.php
similarity index 100%
rename from src/Resources/skeleton/authenticator/LoginFormAuthenticator.tpl.php
rename to templates/authenticator/LoginFormAuthenticator.tpl.php
diff --git a/src/Resources/skeleton/authenticator/login_form.tpl.php b/templates/authenticator/login_form.tpl.php
similarity index 100%
rename from src/Resources/skeleton/authenticator/login_form.tpl.php
rename to templates/authenticator/login_form.tpl.php
diff --git a/src/Resources/skeleton/command/Command.tpl.php b/templates/command/Command.tpl.php
similarity index 100%
rename from src/Resources/skeleton/command/Command.tpl.php
rename to templates/command/Command.tpl.php
diff --git a/src/Resources/skeleton/controller/Controller.tpl.php b/templates/controller/Controller.tpl.php
similarity index 71%
rename from src/Resources/skeleton/controller/Controller.tpl.php
rename to templates/controller/Controller.tpl.php
index 8f509e699..9d9948457 100644
--- a/src/Resources/skeleton/controller/Controller.tpl.php
+++ b/templates/controller/Controller.tpl.php
@@ -1,10 +1,10 @@
= "
-namespace = $namespace; ?>;
+namespace = $class_data->getNamespace(); ?>;
-= $use_statements; ?>
+= $class_data->getUseStatements(); ?>
-class = $class_name; ?> extends AbstractController
+= $class_data->getClassDeclaration(); ?>
{
= $generator->generateRouteForControllerMethod($route_path, $route_name); ?>
public function = $method_name ?>(): ResponseJsonResponse
@@ -12,7 +12,7 @@ public function = $method_name ?>(): Response
return $this->render('= $template_name ?>', [
- 'controller_name' => '= $class_name ?>',
+ 'controller_name' => '= $class_data->getClassName() ?>',
]);
return $this->json([
diff --git a/templates/controller/test/Test.tpl.php b/templates/controller/test/Test.tpl.php
new file mode 100644
index 000000000..802fcc694
--- /dev/null
+++ b/templates/controller/test/Test.tpl.php
@@ -0,0 +1,16 @@
+= "
+
+namespace = $class_data->getNamespace(); ?>;
+
+= $class_data->getUseStatements(); ?>
+
+= $class_data->getClassDeclaration(); ?>
+{
+ public function testIndex(): void
+ {
+ $client = static::createClient();
+ $client->request('GET', '= $route_path; ?>');
+
+ self::assertResponseIsSuccessful();
+ }
+}
diff --git a/src/Resources/skeleton/controller/twig_template.tpl.php b/templates/controller/twig_template.tpl.php
similarity index 100%
rename from src/Resources/skeleton/controller/twig_template.tpl.php
rename to templates/controller/twig_template.tpl.php
diff --git a/src/Resources/skeleton/crud/controller/Controller.tpl.php b/templates/crud/controller/Controller.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/controller/Controller.tpl.php
rename to templates/crud/controller/Controller.tpl.php
diff --git a/src/Resources/skeleton/crud/templates/_delete_form.tpl.php b/templates/crud/templates/_delete_form.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/templates/_delete_form.tpl.php
rename to templates/crud/templates/_delete_form.tpl.php
diff --git a/src/Resources/skeleton/crud/templates/_form.tpl.php b/templates/crud/templates/_form.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/templates/_form.tpl.php
rename to templates/crud/templates/_form.tpl.php
diff --git a/src/Resources/skeleton/crud/templates/edit.tpl.php b/templates/crud/templates/edit.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/templates/edit.tpl.php
rename to templates/crud/templates/edit.tpl.php
diff --git a/src/Resources/skeleton/crud/templates/index.tpl.php b/templates/crud/templates/index.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/templates/index.tpl.php
rename to templates/crud/templates/index.tpl.php
diff --git a/src/Resources/skeleton/crud/templates/new.tpl.php b/templates/crud/templates/new.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/templates/new.tpl.php
rename to templates/crud/templates/new.tpl.php
diff --git a/src/Resources/skeleton/crud/templates/show.tpl.php b/templates/crud/templates/show.tpl.php
similarity index 100%
rename from src/Resources/skeleton/crud/templates/show.tpl.php
rename to templates/crud/templates/show.tpl.php
diff --git a/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php b/templates/crud/test/Test.EntityManager.tpl.php
similarity index 86%
rename from src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php
rename to templates/crud/test/Test.EntityManager.tpl.php
index 36003d7e4..031a8cb6e 100644
--- a/src/Resources/skeleton/crud/test/Test.EntityManager.tpl.php
+++ b/templates/crud/test/Test.EntityManager.tpl.php
@@ -9,16 +9,16 @@
{
private KernelBrowser $client;
private EntityManagerInterface $manager;
- private EntityRepository $repository;
+ private EntityRepository $= lcfirst($entity_var_singular); ?>Repository;
private string $path = '= $route_path; ?>/';
protected function setUp(): void
{
$this->client = static::createClient();
$this->manager = static::getContainer()->get('doctrine')->getManager();
- $this->repository = $this->manager->getRepository(= $entity_class_name; ?>::class);
+ $this->= lcfirst($entity_var_singular); ?>Repository = $this->manager->getRepository(= $entity_class_name; ?>::class);
- foreach ($this->repository->findAll() as $object) {
+ foreach ($this->= lcfirst($entity_var_singular); ?>Repository->findAll() as $object) {
$this->manager->remove($object);
}
@@ -52,7 +52,7 @@ public function testNew(): void
self::assertResponseRedirects($this->path);
- self::assertSame(1, $this->repository->count([]));
+ self::assertSame(1, $this->= lcfirst($entity_var_singular); ?>Repository->count([]));
}
public function testShow(): void
@@ -95,7 +95,7 @@ public function testEdit(): void
self::assertResponseRedirects('= $route_path; ?>/');
- $fixture = $this->repository->findAll();
+ $fixture = $this->= lcfirst($entity_var_singular); ?>Repository->findAll();
$typeOptions): ?>
self::assertSame('Something New', $fixture[0]->get= ucfirst($form_field); ?>());
@@ -117,6 +117,6 @@ public function testRemove(): void
$this->client->submitForm('Delete');
self::assertResponseRedirects('= $route_path; ?>/');
- self::assertSame(0, $this->repository->count([]));
+ self::assertSame(0, $this->= lcfirst($entity_var_singular); ?>Repository->count([]));
}
}
diff --git a/src/Resources/skeleton/doctrine/Entity.tpl.php b/templates/doctrine/Entity.tpl.php
similarity index 100%
rename from src/Resources/skeleton/doctrine/Entity.tpl.php
rename to templates/doctrine/Entity.tpl.php
diff --git a/src/Resources/skeleton/doctrine/Fixtures.tpl.php b/templates/doctrine/Fixtures.tpl.php
similarity index 100%
rename from src/Resources/skeleton/doctrine/Fixtures.tpl.php
rename to templates/doctrine/Fixtures.tpl.php
diff --git a/src/Resources/skeleton/doctrine/Repository.tpl.php b/templates/doctrine/Repository.tpl.php
similarity index 100%
rename from src/Resources/skeleton/doctrine/Repository.tpl.php
rename to templates/doctrine/Repository.tpl.php
diff --git a/src/Resources/skeleton/doctrine/broadcast_twig_template.tpl.php b/templates/doctrine/broadcast_twig_template.tpl.php
similarity index 100%
rename from src/Resources/skeleton/doctrine/broadcast_twig_template.tpl.php
rename to templates/doctrine/broadcast_twig_template.tpl.php
diff --git a/src/Resources/skeleton/event/Listener.tpl.php b/templates/event/Listener.tpl.php
similarity index 100%
rename from src/Resources/skeleton/event/Listener.tpl.php
rename to templates/event/Listener.tpl.php
diff --git a/src/Resources/skeleton/event/Subscriber.tpl.php b/templates/event/Subscriber.tpl.php
similarity index 100%
rename from src/Resources/skeleton/event/Subscriber.tpl.php
rename to templates/event/Subscriber.tpl.php
diff --git a/src/Resources/skeleton/form/Type.tpl.php b/templates/form/Type.tpl.php
similarity index 100%
rename from src/Resources/skeleton/form/Type.tpl.php
rename to templates/form/Type.tpl.php
diff --git a/src/Resources/skeleton/message/Message.tpl.php b/templates/message/Message.tpl.php
similarity index 100%
rename from src/Resources/skeleton/message/Message.tpl.php
rename to templates/message/Message.tpl.php
diff --git a/src/Resources/skeleton/message/MessageHandler.tpl.php b/templates/message/MessageHandler.tpl.php
similarity index 100%
rename from src/Resources/skeleton/message/MessageHandler.tpl.php
rename to templates/message/MessageHandler.tpl.php
diff --git a/src/Resources/skeleton/middleware/Middleware.tpl.php b/templates/middleware/Middleware.tpl.php
similarity index 100%
rename from src/Resources/skeleton/middleware/Middleware.tpl.php
rename to templates/middleware/Middleware.tpl.php
diff --git a/src/Resources/skeleton/registration/RegistrationController.tpl.php b/templates/registration/RegistrationController.tpl.php
similarity index 100%
rename from src/Resources/skeleton/registration/RegistrationController.tpl.php
rename to templates/registration/RegistrationController.tpl.php
diff --git a/src/Resources/skeleton/registration/Test.WithVerify.tpl.php b/templates/registration/Test.WithVerify.tpl.php
similarity index 100%
rename from src/Resources/skeleton/registration/Test.WithVerify.tpl.php
rename to templates/registration/Test.WithVerify.tpl.php
diff --git a/src/Resources/skeleton/registration/Test.WithoutVerify.tpl.php b/templates/registration/Test.WithoutVerify.tpl.php
similarity index 100%
rename from src/Resources/skeleton/registration/Test.WithoutVerify.tpl.php
rename to templates/registration/Test.WithoutVerify.tpl.php
diff --git a/src/Resources/skeleton/registration/twig_email.tpl.php b/templates/registration/twig_email.tpl.php
similarity index 100%
rename from src/Resources/skeleton/registration/twig_email.tpl.php
rename to templates/registration/twig_email.tpl.php
diff --git a/src/Resources/skeleton/registration/twig_template.tpl.php b/templates/registration/twig_template.tpl.php
similarity index 100%
rename from src/Resources/skeleton/registration/twig_template.tpl.php
rename to templates/registration/twig_template.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/ChangePasswordFormType.tpl.php b/templates/resetPassword/ChangePasswordFormType.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/ChangePasswordFormType.tpl.php
rename to templates/resetPassword/ChangePasswordFormType.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordController.tpl.php b/templates/resetPassword/ResetPasswordController.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/ResetPasswordController.tpl.php
rename to templates/resetPassword/ResetPasswordController.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordRequestFormType.tpl.php b/templates/resetPassword/ResetPasswordRequestFormType.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/ResetPasswordRequestFormType.tpl.php
rename to templates/resetPassword/ResetPasswordRequestFormType.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/Test.ResetPasswordController.tpl.php b/templates/resetPassword/Test.ResetPasswordController.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/Test.ResetPasswordController.tpl.php
rename to templates/resetPassword/Test.ResetPasswordController.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/twig_check_email.tpl.php b/templates/resetPassword/twig_check_email.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/twig_check_email.tpl.php
rename to templates/resetPassword/twig_check_email.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/twig_email.tpl.php b/templates/resetPassword/twig_email.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/twig_email.tpl.php
rename to templates/resetPassword/twig_email.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/twig_request.tpl.php b/templates/resetPassword/twig_request.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/twig_request.tpl.php
rename to templates/resetPassword/twig_request.tpl.php
diff --git a/src/Resources/skeleton/resetPassword/twig_reset.tpl.php b/templates/resetPassword/twig_reset.tpl.php
similarity index 100%
rename from src/Resources/skeleton/resetPassword/twig_reset.tpl.php
rename to templates/resetPassword/twig_reset.tpl.php
diff --git a/src/Resources/skeleton/scheduler/Schedule.tpl.php b/templates/scheduler/Schedule.tpl.php
similarity index 100%
rename from src/Resources/skeleton/scheduler/Schedule.tpl.php
rename to templates/scheduler/Schedule.tpl.php
diff --git a/src/Resources/skeleton/security/UserProvider.tpl.php b/templates/security/UserProvider.tpl.php
similarity index 100%
rename from src/Resources/skeleton/security/UserProvider.tpl.php
rename to templates/security/UserProvider.tpl.php
diff --git a/src/Resources/skeleton/security/Voter.tpl.php b/templates/security/Voter.tpl.php
similarity index 100%
rename from src/Resources/skeleton/security/Voter.tpl.php
rename to templates/security/Voter.tpl.php
diff --git a/src/Resources/skeleton/security/custom/Authenticator.tpl.php b/templates/security/custom/Authenticator.tpl.php
similarity index 100%
rename from src/Resources/skeleton/security/custom/Authenticator.tpl.php
rename to templates/security/custom/Authenticator.tpl.php
diff --git a/src/Resources/skeleton/security/formLogin/LoginController.tpl.php b/templates/security/formLogin/LoginController.tpl.php
similarity index 100%
rename from src/Resources/skeleton/security/formLogin/LoginController.tpl.php
rename to templates/security/formLogin/LoginController.tpl.php
diff --git a/src/Resources/skeleton/security/formLogin/Test.LoginController.tpl.php b/templates/security/formLogin/Test.LoginController.tpl.php
similarity index 100%
rename from src/Resources/skeleton/security/formLogin/Test.LoginController.tpl.php
rename to templates/security/formLogin/Test.LoginController.tpl.php
diff --git a/src/Resources/skeleton/security/formLogin/login_form.tpl.php b/templates/security/formLogin/login_form.tpl.php
similarity index 100%
rename from src/Resources/skeleton/security/formLogin/login_form.tpl.php
rename to templates/security/formLogin/login_form.tpl.php
diff --git a/src/Resources/skeleton/serializer/Encoder.tpl.php b/templates/serializer/Encoder.tpl.php
similarity index 100%
rename from src/Resources/skeleton/serializer/Encoder.tpl.php
rename to templates/serializer/Encoder.tpl.php
diff --git a/src/Resources/skeleton/serializer/Normalizer.tpl.php b/templates/serializer/Normalizer.tpl.php
similarity index 100%
rename from src/Resources/skeleton/serializer/Normalizer.tpl.php
rename to templates/serializer/Normalizer.tpl.php
diff --git a/src/Resources/skeleton/stimulus/Controller.tpl.php b/templates/stimulus/Controller.tpl.php
similarity index 100%
rename from src/Resources/skeleton/stimulus/Controller.tpl.php
rename to templates/stimulus/Controller.tpl.php
diff --git a/src/Resources/skeleton/test/ApiTestCase.tpl.php b/templates/test/ApiTestCase.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/ApiTestCase.tpl.php
rename to templates/test/ApiTestCase.tpl.php
diff --git a/src/Resources/skeleton/test/Functional.tpl.php b/templates/test/Functional.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/Functional.tpl.php
rename to templates/test/Functional.tpl.php
diff --git a/src/Resources/skeleton/test/KernelTestCase.tpl.php b/templates/test/KernelTestCase.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/KernelTestCase.tpl.php
rename to templates/test/KernelTestCase.tpl.php
diff --git a/src/Resources/skeleton/test/PantherTestCase.tpl.php b/templates/test/PantherTestCase.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/PantherTestCase.tpl.php
rename to templates/test/PantherTestCase.tpl.php
diff --git a/src/Resources/skeleton/test/TestCase.tpl.php b/templates/test/TestCase.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/TestCase.tpl.php
rename to templates/test/TestCase.tpl.php
diff --git a/src/Resources/skeleton/test/Unit.tpl.php b/templates/test/Unit.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/Unit.tpl.php
rename to templates/test/Unit.tpl.php
diff --git a/src/Resources/skeleton/test/WebTestCase.tpl.php b/templates/test/WebTestCase.tpl.php
similarity index 100%
rename from src/Resources/skeleton/test/WebTestCase.tpl.php
rename to templates/test/WebTestCase.tpl.php
diff --git a/src/Resources/skeleton/twig/Component.tpl.php b/templates/twig/Component.tpl.php
similarity index 100%
rename from src/Resources/skeleton/twig/Component.tpl.php
rename to templates/twig/Component.tpl.php
diff --git a/src/Resources/skeleton/twig/Extension.tpl.php b/templates/twig/Extension.tpl.php
similarity index 100%
rename from src/Resources/skeleton/twig/Extension.tpl.php
rename to templates/twig/Extension.tpl.php
diff --git a/src/Resources/skeleton/twig/LiveComponent.tpl.php b/templates/twig/LiveComponent.tpl.php
similarity index 100%
rename from src/Resources/skeleton/twig/LiveComponent.tpl.php
rename to templates/twig/LiveComponent.tpl.php
diff --git a/src/Resources/skeleton/twig/Runtime.tpl.php b/templates/twig/Runtime.tpl.php
similarity index 100%
rename from src/Resources/skeleton/twig/Runtime.tpl.php
rename to templates/twig/Runtime.tpl.php
diff --git a/src/Resources/skeleton/twig/component_template.tpl.php b/templates/twig/component_template.tpl.php
similarity index 100%
rename from src/Resources/skeleton/twig/component_template.tpl.php
rename to templates/twig/component_template.tpl.php
diff --git a/templates/validator/Constraint.tpl.php b/templates/validator/Constraint.tpl.php
new file mode 100644
index 000000000..414c19eeb
--- /dev/null
+++ b/templates/validator/Constraint.tpl.php
@@ -0,0 +1,21 @@
+= "
+
+namespace = $class_data->getNamespace(); ?>;
+
+= $class_data->getUseStatements(); ?>
+
+#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
+= $class_data->getClassDeclaration(); ?>
+{
+ public string $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.';
+
+ // You can use #[HasNamedArguments] to make some constraint options required.
+ // All configurable options must be passed to the constructor.
+ public function __construct(
+ public string $mode = 'strict',
+ ?array $groups = null,
+ mixed $payload = null
+ ) {
+ parent::__construct([], $groups, $payload);
+ }
+}
diff --git a/templates/validator/Validator.tpl.php b/templates/validator/Validator.tpl.php
new file mode 100644
index 000000000..ef711e888
--- /dev/null
+++ b/templates/validator/Validator.tpl.php
@@ -0,0 +1,23 @@
+= "
+
+namespace = $class_data->getNamespace(); ?>;
+
+= $class_data->getUseStatements(); ?>
+
+= $class_data->getClassDeclaration(); ?>
+{
+ public function validate(mixed $value, Constraint $constraint): void
+ {
+ /** @var = $constraint_class_name ?> $constraint */
+
+ if (null === $value || '' === $value) {
+ return;
+ }
+
+ // TODO: implement the validation here
+ $this->context->buildViolation($constraint->message)
+ ->setParameter('{{ value }}', $value)
+ ->addViolation()
+ ;
+ }
+}
diff --git a/src/Resources/skeleton/verifyEmail/EmailVerifier.tpl.php b/templates/verifyEmail/EmailVerifier.tpl.php
similarity index 97%
rename from src/Resources/skeleton/verifyEmail/EmailVerifier.tpl.php
rename to templates/verifyEmail/EmailVerifier.tpl.php
index f5e37f7f2..85422dfc9 100644
--- a/src/Resources/skeleton/verifyEmail/EmailVerifier.tpl.php
+++ b/templates/verifyEmail/EmailVerifier.tpl.php
@@ -43,7 +43,7 @@ public function handleEmailConfirmation(Request $request, = $user_class_name ?
{
$this->verifyEmailHelper->validateEmailConfirmationFromRequest($request, (string) $user->= $id_getter ?>(), (string) $user->= $email_getter?>());
- $user->setVerified(true);
+ $user->setIsVerified(true);
$this->entityManager->persist($user);
$this->entityManager->flush();
diff --git a/src/Resources/skeleton/webhook/RequestParser.tpl.php b/templates/webhook/RequestParser.tpl.php
similarity index 100%
rename from src/Resources/skeleton/webhook/RequestParser.tpl.php
rename to templates/webhook/RequestParser.tpl.php
diff --git a/src/Resources/skeleton/webhook/WebhookConsumer.tpl.php b/templates/webhook/WebhookConsumer.tpl.php
similarity index 100%
rename from src/Resources/skeleton/webhook/WebhookConsumer.tpl.php
rename to templates/webhook/WebhookConsumer.tpl.php
diff --git a/tests/Command/MakerCommandTest.php b/tests/Command/MakerCommandTest.php
index 06aa9823d..d52b2d723 100644
--- a/tests/Command/MakerCommandTest.php
+++ b/tests/Command/MakerCommandTest.php
@@ -40,7 +40,7 @@ public function testExceptionOnMissingDependencies(): void
$fileManager = $this->createMock(FileManager::class);
- $command = new MakerCommand($maker, $fileManager, new Generator($fileManager, 'App'), new TemplateLinter());
+ $command = new MakerCommand($maker, $fileManager, new Generator($fileManager, 'App'), new TemplateLinter($fileManager));
// needed because it's normally set by the Application
$command->setName('make:foo');
$tester = new CommandTester($command);
@@ -53,7 +53,7 @@ public function testExceptionOnUnknownRootNamespace(): void
$fileManager = $this->createMock(FileManager::class);
- $command = new MakerCommand($maker, $fileManager, new Generator($fileManager, 'Unknown'), new TemplateLinter());
+ $command = new MakerCommand($maker, $fileManager, new Generator($fileManager, 'Unknown'), new TemplateLinter($fileManager));
// needed because it's normally set by the Application
$command->setName('make:foo');
$tester = new CommandTester($command);
diff --git a/tests/Maker/MakeControllerTest.php b/tests/Maker/MakeControllerTest.php
index 026d390c5..656a4884a 100644
--- a/tests/Maker/MakeControllerTest.php
+++ b/tests/Maker/MakeControllerTest.php
@@ -15,6 +15,11 @@
use Symfony\Bundle\MakerBundle\Test\MakerTestCase;
use Symfony\Bundle\MakerBundle\Test\MakerTestRunner;
+/**
+ * Passing namespaces interactively can be done like "App\Controller\MyController"
+ * but passing as a command argument, you must add a double set of slashes. e.g.
+ * "App\\\\Controller\\\\MyController".
+ */
class MakeControllerTest extends MakerTestCase
{
protected function getMakerClass(): string
@@ -32,6 +37,41 @@ public function getTestDetails(): \Generator
]);
$this->assertContainsCount('created: ', $output, 1);
+ $this->runControllerTest($runner, 'it_generates_a_controller.php');
+
+ // Ensure the generated controller matches what we expect
+ self::assertSame(
+ expected: file_get_contents(\dirname(__DIR__).'/fixtures/make-controller/expected/FinalController.php'),
+ actual: file_get_contents($runner->getPath('src/Controller/FooBarController.php'))
+ );
+ }),
+ ];
+
+ yield 'it_generates_a_controller-with-tests' => [$this->createMakerTest()
+ ->addExtraDependencies('symfony/test-pack')
+ ->run(function (MakerTestRunner $runner) {
+ $output = $runner->runMaker([
+ 'FooBar', // controller class name
+ 'y', // create tests
+ ]);
+
+ $this->assertStringContainsString('src/Controller/FooBarController.php', $output);
+ $this->assertStringContainsString('tests/Controller/FooBarControllerTest.php', $output);
+
+ $this->assertFileExists($runner->getPath('src/Controller/FooBarController.php'));
+ $this->assertFileExists($runner->getPath('tests/Controller/FooBarControllerTest.php'));
+
+ $this->runControllerTest($runner, 'it_generates_a_controller.php');
+ }),
+ ];
+
+ yield 'it_generates_a_controller__no_input' => [$this->createMakerTest()
+ ->run(function (MakerTestRunner $runner) {
+ $output = $runner->runMaker([], 'FooBar');
+
+ $this->assertContainsCount('created: ', $output, 1);
+
+ $this->assertFileExists($runner->getPath('src/Controller/FooBarController.php'));
$this->runControllerTest($runner, 'it_generates_a_controller.php');
}),
@@ -49,6 +89,24 @@ public function getTestDetails(): \Generator
self::assertFileExists($controllerPath);
$this->runControllerTest($runner, 'it_generates_a_controller_with_twig.php');
+
+ // Ensure the generated controller matches what we expect
+ self::assertSame(
+ expected: file_get_contents(\dirname(__DIR__).'/fixtures/make-controller/expected/FinalControllerWithTemplate.php'),
+ actual: file_get_contents($runner->getPath('src/Controller/FooTwigController.php'))
+ );
+ }),
+ ];
+
+ yield 'it_generates_a_controller_with_twig__no_input' => [$this->createMakerTest()
+ ->addExtraDependencies('twig')
+ ->run(function (MakerTestRunner $runner) {
+ $runner->runMaker([], 'FooTwig');
+
+ $this->assertFileExists($runner->getPath('src/Controller/FooTwigController.php'));
+ $this->assertFileExists($runner->getPath('templates/foo_twig/index.html.twig'));
+
+ $this->runControllerTest($runner, 'it_generates_a_controller_with_twig.php');
}),
];
@@ -98,6 +156,19 @@ public function getTestDetails(): \Generator
}),
];
+ yield 'it_generates_a_controller_in_sub_namespace__no_input' => [$this->createMakerTest()
+ ->skipTest(
+ message: 'Test Skipped - MAKER_TEST_WINDOWS is true.',
+ skipped: getenv('MAKER_TEST_WINDOWS')
+ )
+ ->run(function (MakerTestRunner $runner) {
+ $output = $runner->runMaker([], 'Admin\\\\FooBar');
+
+ $this->assertFileExists($runner->getPath('src/Controller/Admin/FooBarController.php'));
+ $this->assertStringContainsString('src/Controller/Admin/FooBarController.php', $output);
+ }),
+ ];
+
yield 'it_generates_a_controller_in_sub_namespace_with_template' => [$this->createMakerTest()
->addExtraDependencies('twig')
->run(function (MakerTestRunner $runner) {
@@ -129,6 +200,22 @@ public function getTestDetails(): \Generator
}),
];
+ yield 'it_generates_a_controller_with_full_custom_namespace__no_input' => [$this->createMakerTest()
+ ->skipTest(
+ message: 'Test Skipped - MAKER_TEST_WINDOWS is true.',
+ skipped: getenv('MAKER_TEST_WINDOWS')
+ )
+ ->addExtraDependencies('twig')
+ ->run(function (MakerTestRunner $runner) {
+ $output = $runner->runMaker([], '\\\\App\\\\Foo\\\\Bar\\\\CoolController');
+
+ self::assertFileExists($runner->getPath('templates/foo/bar/cool/index.html.twig'));
+
+ $this->assertStringContainsString('src/Foo/Bar/CoolController.php', $output);
+ $this->assertStringContainsString('templates/foo/bar/cool/index.html.twig', $output);
+ }),
+ ];
+
yield 'it_generates_a_controller_with_invoke' => [$this->createMakerTest()
->addExtraDependencies('twig')
->run(function (MakerTestRunner $runner) {
diff --git a/tests/Maker/MakeEntityTest.php b/tests/Maker/MakeEntityTest.php
index 4403a53c2..54059bad3 100644
--- a/tests/Maker/MakeEntityTest.php
+++ b/tests/Maker/MakeEntityTest.php
@@ -120,6 +120,8 @@ public function getTestDetails(): \Generator
];
yield 'it_creates_a_new_class_and_api_resource' => [$this->createMakeEntityTest()
+ // @legacy - re-enable test when https://github.com/symfony/recipes/pull/1339 is merged
+ ->skipTest('Waiting for https://github.com/symfony/recipes/pull/1339')
->addExtraDependencies('api')
->run(function (MakerTestRunner $runner) {
$runner->runMaker([
@@ -679,6 +681,8 @@ public function getTestDetails(): \Generator
];
yield 'it_makes_new_entity_no_to_all_extras' => [$this->createMakeEntityTestForMercure()
+ // @legacy - re-enable test when https://github.com/symfony/recipes/pull/1339 is merged
+ ->skipTest('Waiting for https://github.com/symfony/recipes/pull/1339')
->addExtraDependencies('api')
// special setup done in createMakeEntityTestForMercure()
->run(function (MakerTestRunner $runner) {
diff --git a/tests/Maker/MakeValidatorTest.php b/tests/Maker/MakeValidatorTest.php
index 0ca11939c..acc551b0c 100644
--- a/tests/Maker/MakeValidatorTest.php
+++ b/tests/Maker/MakeValidatorTest.php
@@ -32,6 +32,18 @@ public function getTestDetails(): \Generator
'FooBar',
]
);
+
+ // Validator
+ $expectedVoterPath = \dirname(__DIR__).'/fixtures/make-validator/expected/FooBarValidator.php';
+ $generatedVoter = $runner->getPath('src/Validator/FooBarValidator.php');
+
+ self::assertSame(file_get_contents($expectedVoterPath), file_get_contents($generatedVoter));
+
+ // Constraint
+ $expectedVoterPath = \dirname(__DIR__).'/fixtures/make-validator/expected/FooBar.php';
+ $generatedVoter = $runner->getPath('src/Validator/FooBar.php');
+
+ self::assertSame(file_get_contents($expectedVoterPath), file_get_contents($generatedVoter));
}),
];
}
diff --git a/tests/Maker/TemplateLinterTest.php b/tests/Maker/TemplateLinterTest.php
index cf14850ab..2747bb033 100644
--- a/tests/Maker/TemplateLinterTest.php
+++ b/tests/Maker/TemplateLinterTest.php
@@ -33,7 +33,6 @@ protected function getMakerClass(): string
public function getTestDetails(): \Generator
{
yield 'lints_templates_with_custom_php_cs_fixer_and_config' => [$this->createMakerTest()
- ->addExtraDependencies('php-cs-fixer/shim')
->run(function (MakerTestRunner $runner) {
$runner->copy('template-linter/php-cs-fixer.test.php', 'php-cs-fixer.test.php');
@@ -53,13 +52,12 @@ public function getTestDetails(): \Generator
self::assertStringContainsString('Linted by custom php-cs-config', $generatedTemplate);
- $expectedOutput = 'System PHP-CS-Fixer (bin/php-cs-fixer) & System PHP-CS-Fixer Configuration (php-cs-fixer.test.php)';
+ $expectedOutput = 'System PHP-CS-Fixer (bin/php-cs-fixer) & System PHP-CS-Fixer Configuration';
self::assertStringContainsString($expectedOutput, $output);
}),
];
yield 'lints_templates_with_flex_generated_config_file' => [$this->createMakerTest()
- ->addExtraDependencies('php-cs-fixer/shim')
->run(function (MakerTestRunner $runner) {
$runner->replaceInFile(
'.php-cs-fixer.dist.php',
@@ -79,13 +77,14 @@ public function getTestDetails(): \Generator
self::assertStringContainsString('Linted with stock php-cs-config', $generatedTemplate);
- $expectedOutput = 'Bundled PHP-CS-Fixer & System PHP-CS-Fixer Configuration (.php-cs-fixer.dist.php)';
+ $expectedOutput = 'Bundled PHP-CS-Fixer & System PHP-CS-Fixer Configuration';
self::assertStringContainsString($expectedOutput, $output);
}),
];
yield 'lints_templates_with_bundled_php_cs_fixer' => [$this->createMakerTest()
->run(function (MakerTestRunner $runner) {
+ $runner->deleteFile('.php-cs-fixer.dist.php');
// Voter class name
$output = $runner->runMaker(['FooBar']);
diff --git a/tests/Util/ClassSource/ClassDataTest.php b/tests/Util/ClassSource/ClassDataTest.php
index cbad75dec..27d345028 100644
--- a/tests/Util/ClassSource/ClassDataTest.php
+++ b/tests/Util/ClassSource/ClassDataTest.php
@@ -91,4 +91,56 @@ public function namespaceDataProvider(): \Generator
yield ['MyController', 'Maker', 'Maker', 'Maker\MyController'];
yield ['Controller\MyController', 'Maker', 'Maker\Controller', 'Maker\Controller\MyController'];
}
+
+ public function testGetClassName(): void
+ {
+ $class = ClassData::create(class: 'Controller\\Foo', suffix: 'Controller');
+ self::assertSame('FooController', $class->getClassName());
+ self::assertSame('Foo', $class->getClassName(relative: false, withoutSuffix: true));
+ self::assertSame('FooController', $class->getClassName(relative: true, withoutSuffix: false));
+ self::assertSame('Foo', $class->getClassName(relative: true, withoutSuffix: true));
+ self::assertSame('App\Controller\FooController', $class->getFullClassName());
+ }
+
+ public function testGetClassNameRelativeNamespace(): void
+ {
+ $class = ClassData::create(class: 'Controller\\Admin\\Foo', suffix: 'Controller');
+ self::assertSame('FooController', $class->getClassName());
+ self::assertSame('Foo', $class->getClassName(relative: false, withoutSuffix: true));
+ self::assertSame('Admin\FooController', $class->getClassName(relative: true, withoutSuffix: false));
+ self::assertSame('Admin\Foo', $class->getClassName(relative: true, withoutSuffix: true));
+ self::assertSame('App\Controller\Admin\FooController', $class->getFullClassName());
+ }
+
+ public function testGetClassNameWithAbsoluteNamespace(): void
+ {
+ $class = ClassData::create(class: '\\Foo\\Bar\\Admin\\Baz', suffix: 'Controller');
+ self::assertSame('BazController', $class->getClassName());
+ self::assertSame('Foo\Bar\Admin', $class->getNamespace());
+ self::assertSame('Foo\Bar\Admin\BazController', $class->getFullClassName());
+ }
+
+ /** @dataProvider fullClassNameProvider */
+ public function testGetFullClassName(string $class, ?string $rootNamespace, bool $withoutRootNamespace, bool $withoutSuffix, string $expectedFullClassName): void
+ {
+ $class = ClassData::create($class, suffix: 'Controller');
+
+ if (null !== $rootNamespace) {
+ $class->setRootNamespace($rootNamespace);
+ }
+
+ self::assertSame($expectedFullClassName, $class->getFullClassName(withoutRootNamespace: $withoutRootNamespace, withoutSuffix: $withoutSuffix));
+ }
+
+ public function fullClassNameProvider(): \Generator
+ {
+ yield ['Controller\MyController', null, false, false, 'App\Controller\MyController'];
+ yield ['Controller\MyController', null, true, false, 'Controller\MyController'];
+ yield ['Controller\MyController', null, false, true, 'App\Controller\My'];
+ yield ['Controller\MyController', null, true, true, 'Controller\My'];
+ yield ['Controller\MyController', 'Custom', false, false, 'Custom\Controller\MyController'];
+ yield ['Controller\MyController', 'Custom', true, false, 'Controller\MyController'];
+ yield ['Controller\MyController', 'Custom', false, true, 'Custom\Controller\My'];
+ yield ['Controller\MyController', 'Custom', true, true, 'Controller\My'];
+ }
}
diff --git a/tests/Util/TemplateLinterTest.php b/tests/Util/TemplateLinterTest.php
index aca250c4f..f5086b6e7 100644
--- a/tests/Util/TemplateLinterTest.php
+++ b/tests/Util/TemplateLinterTest.php
@@ -11,7 +11,9 @@
namespace Symfony\Bundle\MakerBundle\Tests\Util;
+use Composer\InstalledVersions;
use PHPUnit\Framework\TestCase;
+use Symfony\Bundle\MakerBundle\FileManager;
use Symfony\Bundle\MakerBundle\Util\TemplateLinter;
use Symfony\Component\Process\Process;
@@ -28,27 +30,30 @@ public function testExceptionBinaryPathDoesntExist(): void
{
$this->expectExceptionMessage('The MAKER_PHP_CS_FIXER_BINARY_PATH provided: /some/bad/path does not exist.');
- new TemplateLinter(phpCsFixerBinaryPath: '/some/bad/path');
+ new TemplateLinter($this->createMock(FileManager::class), phpCsFixerBinaryPath: '/some/bad/path');
}
public function testExceptionThrownIfConfigPathDoesntExist(): void
{
$this->expectExceptionMessage('The MAKER_PHP_CS_FIXER_CONFIG_PATH provided: /bad/config/path does not exist.');
- new TemplateLinter(phpCsFixerConfigPath: '/bad/config/path');
+ new TemplateLinter($this->createMock(FileManager::class), phpCsFixerConfigPath: '/bad/config/path');
}
public function testPhpCsFixerVersion(): void
{
$this->markTestSkippedOnWindows();
- $fixerPath = \sprintf('%s/src/Resources/bin/php-cs-fixer-v%s.phar', \dirname(__DIR__, 2), TemplateLinter::BUNDLED_PHP_CS_FIXER_VERSION);
+ $fixerPath = \sprintf('%s/vendor/php-cs-fixer/shim/php-cs-fixer', \dirname(__DIR__, 2));
+
+ // Get the installed version and remove the preceding "v"
+ $expectedVersion = ltrim(InstalledVersions::getPrettyVersion('php-cs-fixer/shim'), 'v');
$process = Process::fromShellCommandline(\sprintf('%s -V', $fixerPath));
$process->run();
- self::assertStringContainsString(TemplateLinter::BUNDLED_PHP_CS_FIXER_VERSION, $process->getOutput());
+ self::assertStringContainsString($expectedVersion, $process->getOutput());
}
private function markTestSkippedOnWindows(): void
diff --git a/tests/Util/fixtures/add_setter/User_bool_begins_with_is.php b/tests/Util/fixtures/add_setter/User_bool_begins_with_is.php
index 7b52a6158..f55b60a4f 100644
--- a/tests/Util/fixtures/add_setter/User_bool_begins_with_is.php
+++ b/tests/Util/fixtures/add_setter/User_bool_begins_with_is.php
@@ -17,7 +17,7 @@ public function getId(): ?int
return $this->id;
}
- public function setFooProp(bool $isFooProp): static
+ public function setIsFooProp(bool $isFooProp): static
{
$this->isFooProp = $isFooProp;
diff --git a/tests/fixtures/make-controller/expected/FinalController.php b/tests/fixtures/make-controller/expected/FinalController.php
new file mode 100644
index 000000000..30dcd8f1b
--- /dev/null
+++ b/tests/fixtures/make-controller/expected/FinalController.php
@@ -0,0 +1,19 @@
+json([
+ 'message' => 'Welcome to your new controller!',
+ 'path' => 'src/Controller/FooBarController.php',
+ ]);
+ }
+}
diff --git a/tests/fixtures/make-controller/expected/FinalControllerWithTemplate.php b/tests/fixtures/make-controller/expected/FinalControllerWithTemplate.php
new file mode 100644
index 000000000..0a1c4e566
--- /dev/null
+++ b/tests/fixtures/make-controller/expected/FinalControllerWithTemplate.php
@@ -0,0 +1,18 @@
+render('foo_twig/index.html.twig', [
+ 'controller_name' => 'FooTwigController',
+ ]);
+ }
+}
diff --git a/tests/fixtures/make-controller/tests/it_generates_a_controller.php b/tests/fixtures/make-controller/tests/it_generates_a_controller.php
index 8884cd1fa..f0a6a5651 100644
--- a/tests/fixtures/make-controller/tests/it_generates_a_controller.php
+++ b/tests/fixtures/make-controller/tests/it_generates_a_controller.php
@@ -4,7 +4,7 @@
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
-class GeneratedControllerTest extends WebTestCase
+final class GeneratedControllerTest extends WebTestCase
{
public function testController()
{
diff --git a/tests/fixtures/make-controller/tests/it_generates_a_controller_with_twig.php b/tests/fixtures/make-controller/tests/it_generates_a_controller_with_twig.php
index c21887ea1..e3980fe57 100644
--- a/tests/fixtures/make-controller/tests/it_generates_a_controller_with_twig.php
+++ b/tests/fixtures/make-controller/tests/it_generates_a_controller_with_twig.php
@@ -4,7 +4,7 @@
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
-class GeneratedControllerTest extends WebTestCase
+final class GeneratedControllerTest extends WebTestCase
{
public function testController()
{
diff --git a/tests/fixtures/make-controller/tests/it_generates_an_invokable_controller.php b/tests/fixtures/make-controller/tests/it_generates_an_invokable_controller.php
index ed26ac147..6e6a80a22 100644
--- a/tests/fixtures/make-controller/tests/it_generates_an_invokable_controller.php
+++ b/tests/fixtures/make-controller/tests/it_generates_an_invokable_controller.php
@@ -4,7 +4,7 @@
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
-class GeneratedControllerTest extends WebTestCase
+final class GeneratedControllerTest extends WebTestCase
{
public function testControllerValidity()
{
diff --git a/tests/fixtures/make-serializer-normalizer/EntityFixtureNormalizer.php b/tests/fixtures/make-serializer-normalizer/EntityFixtureNormalizer.php
index 848110fab..4316e3b27 100644
--- a/tests/fixtures/make-serializer-normalizer/EntityFixtureNormalizer.php
+++ b/tests/fixtures/make-serializer-normalizer/EntityFixtureNormalizer.php
@@ -10,7 +10,7 @@ class EntityFixtureNormalizer implements NormalizerInterface
{
public function __construct(
#[Autowire(service: 'serializer.normalizer.object')]
- private NormalizerInterface $normalizer
+ private NormalizerInterface $normalizer,
) {
}
diff --git a/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php b/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php
index 3f253fdbd..8a8c50aaf 100644
--- a/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php
+++ b/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php
@@ -9,7 +9,7 @@ class FooBarNormalizer implements NormalizerInterface
{
public function __construct(
#[Autowire(service: 'serializer.normalizer.object')]
- private NormalizerInterface $normalizer
+ private NormalizerInterface $normalizer,
) {
}
diff --git a/tests/fixtures/make-validator/expected/FooBar.php b/tests/fixtures/make-validator/expected/FooBar.php
new file mode 100644
index 000000000..239fd8bf1
--- /dev/null
+++ b/tests/fixtures/make-validator/expected/FooBar.php
@@ -0,0 +1,21 @@
+
+;
+namespace App\Validator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
-class = $class_name ?> extends ConstraintValidator
+final class FooBarValidator extends ConstraintValidator
{
public function validate(mixed $value, Constraint $constraint): void
{
- /** @var = $constraint_class_name ?> $constraint */
+ /* @var FooBar $constraint */
if (null === $value || '' === $value) {
return;
@@ -18,6 +18,7 @@ public function validate(mixed $value, Constraint $constraint): void
// TODO: implement the validation here
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $value)
- ->addViolation();
+ ->addViolation()
+ ;
}
}
diff --git a/tests/fixtures/make-voter/expected/FooBarVoter.php b/tests/fixtures/make-voter/expected/FooBarVoter.php
index 2cfc1ee22..2a2cf060c 100644
--- a/tests/fixtures/make-voter/expected/FooBarVoter.php
+++ b/tests/fixtures/make-voter/expected/FooBarVoter.php
@@ -22,7 +22,6 @@ protected function supports(string $attribute, mixed $subject): bool
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
-
// if the user is anonymous, do not grant access
if (!$user instanceof UserInterface) {
return false;
@@ -34,7 +33,6 @@ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInter
// logic to determine if the user can EDIT
// return true or false
break;
-
case self::VIEW:
// logic to determine if the user can VIEW
// return true or false
diff --git a/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php b/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php
index e38fb4ad2..f67500726 100644
--- a/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php
+++ b/tests/fixtures/make-voter/expected/not_final_FooBarVoter.php
@@ -22,7 +22,6 @@ protected function supports(string $attribute, mixed $subject): bool
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
-
// if the user is anonymous, do not grant access
if (!$user instanceof UserInterface) {
return false;
@@ -34,7 +33,6 @@ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInter
// logic to determine if the user can EDIT
// return true or false
break;
-
case self::VIEW:
// logic to determine if the user can VIEW
// return true or false