diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml
index c7a17edd06c..2ecd4fc7d2d 100644
--- a/.doctor-rst.yaml
+++ b/.doctor-rst.yaml
@@ -1,9 +1,5 @@
rules:
american_english: ~
- argument_variable_must_match_type:
- arguments:
- - { type: 'ContainerBuilder', name: 'container' }
- - { type: 'ContainerConfigurator', name: 'container' }
avoid_repetetive_words: ~
blank_line_after_anchor: ~
blank_line_after_directive: ~
@@ -23,10 +19,12 @@ rules:
ensure_order_of_code_blocks_in_configuration_block: ~
ensure_php_reference_syntax: ~
extend_abstract_controller: ~
- extension_xlf_instead_of_xliff: ~
+ # extension_xlf_instead_of_xliff: ~
forbidden_directives:
directives:
- '.. index::'
+ - directive: '.. caution::'
+ replacements: ['.. warning::', '.. danger::']
indention: ~
lowercase_as_in_use_statements: ~
max_blank_lines:
@@ -43,6 +41,7 @@ rules:
no_composer_req: ~
no_directive_after_shorthand: ~
no_duplicate_use_statements: ~
+ no_empty_literals: ~
no_explicit_use_of_code_block_php: ~
no_footnotes: ~
no_inheritdoc: ~
@@ -75,35 +74,40 @@ rules:
# master
versionadded_directive_major_version:
- major_version: 5
+ major_version: 7
versionadded_directive_min_version:
- min_version: '5.0'
+ min_version: '7.0'
deprecated_directive_major_version:
- major_version: 5
+ major_version: 7
deprecated_directive_min_version:
- min_version: '5.0'
+ min_version: '7.0'
exclude_rule_for_file:
- path: configuration/multiple_kernels.rst
rule_name: replacement
+ - path: page_creation.rst
+ rule_name: no_php_open_tag_in_code_block_php_directive
+ - path: frontend/create_ux_bundle.rst
+ rule_name: argument_variable_must_match_type
# do not report as violation
whitelist:
regex:
- - '/FOSUserBundle(.*)\.yml/'
+ - '/``.yml``/'
- '/(.*)\.orm\.yml/' # currently DoctrineBundle only supports .yml
lines:
- 'in config files, so the old ``app/config/config_dev.yml`` goes to'
- '#. The most important config file is ``app/config/services.yml``, which now is'
- 'The bin/console Command'
- '.. _`LDAP injection`: http://projects.webappsec.org/w/page/13246947/LDAP%20Injection'
+ - '.. versionadded:: 2.8.0' # Doctrine
- '.. versionadded:: 1.9.0' # Encore
- '.. versionadded:: 1.18' # Flex in setup/upgrade_minor.rst
- '.. versionadded:: 1.0.0' # Encore
- - '.. versionadded:: 5.1' # Private Services
+ - '.. versionadded:: 2.7.1' # Doctrine
- '123,' # assertion for var_dumper - components/var_dumper.rst
- '"foo",' # assertion for var_dumper - components/var_dumper.rst
- '$var .= "Because of this `\xE9` octet (\\xE9),\n";'
@@ -113,4 +117,6 @@ whitelist:
- '.. versionadded:: 3.5' # Monolog
- '.. versionadded:: 3.0' # Doctrine ORM
- '.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket'
- - '.. End to End Tests (E2E)'
+ - 'End to End Tests (E2E)'
+ - '.. versionadded:: 2.2.0' # Panther
+ - '* Inline code blocks use double-ticks (````like this````).'
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 4d67a5c084c..497dfd9b430 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -26,9 +26,8 @@ jobs:
- name: "Set-up PHP"
uses: shivammathur/setup-php@v2
with:
- php-version: 8.1
+ php-version: 8.4
coverage: none
- tools: "composer:v2"
- name: Get composer cache directory
id: composercache
@@ -73,7 +72,7 @@ jobs:
key: ${{ runner.os }}-doctor-rst-${{ steps.extract_base_branch.outputs.branch }}
- name: "Run DOCtor-RST"
- uses: docker://oskarstark/doctor-rst:1.63.0
+ uses: docker://oskarstark/doctor-rst:1.67.0
with:
args: --short --error-format=github --cache-file=/github/workspace/.cache/doctor-rst.cache
@@ -93,7 +92,7 @@ jobs:
- name: Set-up PHP
uses: shivammathur/setup-php@v2
with:
- php-version: 8.1
+ php-version: 8.4
coverage: none
- name: Fetch branch from where the PR started
diff --git a/README.md b/README.md
index ed323a8ee83..5c063058c02 100644
--- a/README.md
+++ b/README.md
@@ -27,8 +27,8 @@ We love contributors! For more information on how you can contribute, please rea
the [Symfony Docs Contributing Guide](https://symfony.com/doc/current/contributing/documentation/overview.html).
> [!IMPORTANT]
-> Use `5.4` branch as the base of your pull requests, unless you are documenting a
-> feature that was introduced *after* Symfony 5.4 (e.g. in Symfony 7.1).
+> Use `6.4` branch as the base of your pull requests, unless you are documenting a
+> feature that was introduced *after* Symfony 6.4 (e.g. in Symfony 7.2).
Build Documentation Locally
---------------------------
diff --git a/_build/build.php b/_build/build.php
index be2fb062a77..b684700a848 100755
--- a/_build/build.php
+++ b/_build/build.php
@@ -15,12 +15,19 @@
->addOption('generate-fjson-files', null, InputOption::VALUE_NONE, 'Use this option to generate docs both in HTML and JSON formats')
->addOption('disable-cache', null, InputOption::VALUE_NONE, 'Use this option to force a full regeneration of all doc contents')
->setCode(function(InputInterface $input, OutputInterface $output) {
+ // the doc building app doesn't work on Windows
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $output->writeln('ERROR: The application that builds Symfony Docs does not support Windows. You can try using a Linux distribution via WSL (Windows Subsystem for Linux).');
+
+ return 1;
+ }
+
$io = new SymfonyStyle($input, $output);
$io->text('Building all Symfony Docs...');
$outputDir = __DIR__.'/output';
$buildConfig = (new BuildConfig())
- ->setSymfonyVersion('5.4')
+ ->setSymfonyVersion('7.1')
->setContentDir(__DIR__.'/..')
->setOutputDir($outputDir)
->setImagesDir(__DIR__.'/output/_images')
diff --git a/_build/composer.json b/_build/composer.json
index e09d79de52f..f77976b10f4 100644
--- a/_build/composer.json
+++ b/_build/composer.json
@@ -3,7 +3,7 @@
"prefer-stable": true,
"config": {
"platform": {
- "php": "8.1.0"
+ "php": "8.3"
},
"preferred-install": {
"*": "dist"
@@ -14,9 +14,9 @@
}
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.3",
"symfony/console": "^6.2",
"symfony/process": "^6.2",
- "symfony-tools/docs-builder": "^0.21"
+ "symfony-tools/docs-builder": "^0.27"
}
}
diff --git a/_build/composer.lock b/_build/composer.lock
index 89a4e7da3c6..b9a4646f8ae 100644
--- a/_build/composer.lock
+++ b/_build/composer.lock
@@ -4,77 +4,33 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "8a771cef10c68c570bff7875e4bdece3",
+ "content-hash": "e38eca557458275428db96db370d2c74",
"packages": [
- {
- "name": "doctrine/deprecations",
- "version": "v1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/deprecations.git",
- "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
- "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
- "shasum": ""
- },
- "require": {
- "php": "^7.1|^8.0"
- },
- "require-dev": {
- "doctrine/coding-standard": "^9",
- "phpunit/phpunit": "^7.5|^8.5|^9.5",
- "psr/log": "^1|^2|^3"
- },
- "suggest": {
- "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
- "homepage": "https://www.doctrine-project.org/",
- "support": {
- "issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
- },
- "time": "2022-05-02T15:47:09+00:00"
- },
{
"name": "doctrine/event-manager",
- "version": "1.2.0",
+ "version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
- "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520"
+ "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520",
- "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520",
+ "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e",
+ "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e",
"shasum": ""
},
"require": {
- "doctrine/deprecations": "^0.5.3 || ^1",
- "php": "^7.1 || ^8.0"
+ "php": "^8.1"
},
"conflict": {
"doctrine/common": "<2.9"
},
"require-dev": {
- "doctrine/coding-standard": "^9 || ^10",
- "phpstan/phpstan": "~1.4.10 || ^1.8.8",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "vimeo/psalm": "^4.24"
+ "doctrine/coding-standard": "^12",
+ "phpstan/phpstan": "^1.8.8",
+ "phpunit/phpunit": "^10.5",
+ "vimeo/psalm": "^5.24"
},
"type": "library",
"autoload": {
@@ -123,7 +79,7 @@
],
"support": {
"issues": "https://github.com/doctrine/event-manager/issues",
- "source": "https://github.com/doctrine/event-manager/tree/1.2.0"
+ "source": "https://github.com/doctrine/event-manager/tree/2.0.1"
},
"funding": [
{
@@ -139,42 +95,42 @@
"type": "tidelift"
}
],
- "time": "2022-10-12T20:51:15+00:00"
+ "time": "2024-05-22T20:47:39+00:00"
},
{
"name": "doctrine/rst-parser",
- "version": "0.5.3",
+ "version": "0.5.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/rst-parser.git",
- "reference": "0b1d413d6bb27699ccec1151da6f617554d02c13"
+ "reference": "ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/rst-parser/zipball/0b1d413d6bb27699ccec1151da6f617554d02c13",
- "reference": "0b1d413d6bb27699ccec1151da6f617554d02c13",
+ "url": "https://api.github.com/repos/doctrine/rst-parser/zipball/ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104",
+ "reference": "ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104",
"shasum": ""
},
"require": {
- "doctrine/event-manager": "^1.0",
+ "doctrine/event-manager": "^1.0 || ^2.0",
"php": "^7.2 || ^8.0",
- "symfony/filesystem": "^4.1 || ^5.0 || ^6.0",
- "symfony/finder": "^4.1 || ^5.0 || ^6.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",
- "symfony/translation-contracts": "^1.1 || ^2.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": "^10.0",
+ "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",
- "symfony/dom-crawler": "4.4 || ^5.2 || ^6.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": {
@@ -210,32 +166,30 @@
],
"support": {
"issues": "https://github.com/doctrine/rst-parser/issues",
- "source": "https://github.com/doctrine/rst-parser/tree/0.5.3"
+ "source": "https://github.com/doctrine/rst-parser/tree/0.5.6"
},
- "time": "2022-12-29T16:24:52+00:00"
+ "time": "2024-01-14T11:02:23+00:00"
},
{
"name": "masterminds/html5",
- "version": "2.7.6",
+ "version": "2.9.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
- "reference": "897eb517a343a2281f11bc5556d6548db7d93947"
+ "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/897eb517a343a2281f11bc5556d6548db7d93947",
- "reference": "897eb517a343a2281f11bc5556d6548db7d93947",
+ "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
+ "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"shasum": ""
},
"require": {
- "ext-ctype": "*",
"ext-dom": "*",
- "ext-libxml": "*",
"php": ">=5.3.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7"
+ "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
},
"type": "library",
"extra": {
@@ -279,9 +233,9 @@
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
- "source": "https://github.com/Masterminds/html5-php/tree/2.7.6"
+ "source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
},
- "time": "2022-08-18T16:18:26+00:00"
+ "time": "2024-03-31T07:05:07+00:00"
},
{
"name": "psr/container",
@@ -338,16 +292,16 @@
},
{
"name": "psr/log",
- "version": "3.0.0",
+ "version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
@@ -382,9 +336,9 @@
"psr-3"
],
"support": {
- "source": "https://github.com/php-fig/log/tree/3.0.0"
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
},
- "time": "2021-07-14T16:46:02+00:00"
+ "time": "2024-09-11T13:17:53+00:00"
},
{
"name": "scrivo/highlight.php",
@@ -466,37 +420,37 @@
},
{
"name": "symfony-tools/docs-builder",
- "version": "v0.21.0",
+ "version": "0.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony-tools/docs-builder.git",
- "reference": "7ab92db15e9be7d6af51b86db87c7e41a14ba18b"
+ "reference": "720b52b2805122a4c08376496bd9661944c2624a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony-tools/docs-builder/zipball/7ab92db15e9be7d6af51b86db87c7e41a14ba18b",
- "reference": "7ab92db15e9be7d6af51b86db87c7e41a14ba18b",
+ "url": "https://api.github.com/repos/symfony-tools/docs-builder/zipball/720b52b2805122a4c08376496bd9661944c2624a",
+ "reference": "720b52b2805122a4c08376496bd9661944c2624a",
"shasum": ""
},
"require": {
"doctrine/rst-parser": "^0.5",
"ext-curl": "*",
"ext-json": "*",
- "php": ">=7.4",
- "scrivo/highlight.php": "^9.12.0",
- "symfony/console": "^5.2 || ^6.0",
- "symfony/css-selector": "^5.2 || ^6.0",
- "symfony/dom-crawler": "^5.2 || ^6.0",
- "symfony/filesystem": "^5.2 || ^6.0",
- "symfony/finder": "^5.2 || ^6.0",
- "symfony/http-client": "^5.2 || ^6.0",
+ "php": ">=8.3",
+ "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",
- "symfony/process": "^5.2 || ^6.0"
+ "symfony/phpunit-bridge": "^5.2 || ^6.0 || ^7.0",
+ "symfony/process": "^5.2 || ^6.0 || ^7.0"
},
"bin": [
"bin/docs-builder"
@@ -514,30 +468,30 @@
"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.21.0"
+ "source": "https://github.com/symfony-tools/docs-builder/tree/0.27.0"
},
- "time": "2023-07-11T15:21:07+00:00"
+ "time": "2025-03-21T09:48:45+00:00"
},
{
"name": "symfony/console",
- "version": "v6.2.8",
+ "version": "v6.4.17",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "3582d68a64a86ec25240aaa521ec8bc2342b369b"
+ "reference": "799445db3f15768ecc382ac5699e6da0520a0a04"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/3582d68a64a86ec25240aaa521ec8bc2342b369b",
- "reference": "3582d68a64a86ec25240aaa521ec8bc2342b369b",
+ "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04",
+ "reference": "799445db3f15768ecc382ac5699e6da0520a0a04",
"shasum": ""
},
"require": {
"php": ">=8.1",
- "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/service-contracts": "^1.1|^2|^3",
- "symfony/string": "^5.4|^6.0"
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/string": "^5.4|^6.0|^7.0"
},
"conflict": {
"symfony/dependency-injection": "<5.4",
@@ -551,18 +505,16 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^5.4|^6.0",
- "symfony/dependency-injection": "^5.4|^6.0",
- "symfony/event-dispatcher": "^5.4|^6.0",
- "symfony/lock": "^5.4|^6.0",
- "symfony/process": "^5.4|^6.0",
- "symfony/var-dumper": "^5.4|^6.0"
- },
- "suggest": {
- "psr/log": "For using the console logger",
- "symfony/event-dispatcher": "",
- "symfony/lock": "",
- "symfony/process": ""
+ "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": {
@@ -596,7 +548,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.2.8"
+ "source": "https://github.com/symfony/console/tree/v6.4.17"
},
"funding": [
{
@@ -612,24 +564,24 @@
"type": "tidelift"
}
],
- "time": "2023-03-29T21:42:15+00:00"
+ "time": "2024-12-07T12:07:30+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v6.2.7",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "aedf3cb0f5b929ec255d96bbb4909e9932c769e0"
+ "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/aedf3cb0f5b929ec255d96bbb4909e9932c769e0",
- "reference": "aedf3cb0f5b929ec255d96bbb4909e9932c769e0",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2",
+ "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.2"
},
"type": "library",
"autoload": {
@@ -661,7 +613,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/css-selector/tree/v6.2.7"
+ "source": "https://github.com/symfony/css-selector/tree/v7.2.0"
},
"funding": [
{
@@ -677,20 +629,20 @@
"type": "tidelift"
}
],
- "time": "2023-02-14T08:44:56+00:00"
+ "time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.2.1",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e"
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
- "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@@ -698,12 +650,12 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.3-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.5-dev"
}
},
"autoload": {
@@ -728,7 +680,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -744,33 +696,30 @@
"type": "tidelift"
}
],
- "time": "2023-03-01T10:25:55+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/dom-crawler",
- "version": "v6.2.8",
+ "version": "v7.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "0e0d0f709997ad1224ef22bb0a28287c44b7840f"
+ "reference": "19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/0e0d0f709997ad1224ef22bb0a28287c44b7840f",
- "reference": "0e0d0f709997ad1224ef22bb0a28287c44b7840f",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7",
+ "reference": "19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7",
"shasum": ""
},
"require": {
"masterminds/html5": "^2.6",
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
- "symfony/css-selector": "^5.4|^6.0"
- },
- "suggest": {
- "symfony/css-selector": ""
+ "symfony/css-selector": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -798,7 +747,7 @@
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/dom-crawler/tree/v6.2.8"
+ "source": "https://github.com/symfony/dom-crawler/tree/v7.2.4"
},
"funding": [
{
@@ -814,27 +763,30 @@
"type": "tidelift"
}
],
- "time": "2023-03-09T16:20:02+00:00"
+ "time": "2025-02-17T15:53:07+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v6.2.7",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "82b6c62b959f642d000456f08c6d219d749215b3"
+ "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/82b6c62b959f642d000456f08c6d219d749215b3",
- "reference": "82b6c62b959f642d000456f08c6d219d749215b3",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
+ "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
+ "require-dev": {
+ "symfony/process": "^6.4|^7.0"
+ },
"type": "library",
"autoload": {
"psr-4": {
@@ -861,7 +813,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v6.2.7"
+ "source": "https://github.com/symfony/filesystem/tree/v7.2.0"
},
"funding": [
{
@@ -877,27 +829,27 @@
"type": "tidelift"
}
],
- "time": "2023-02-14T08:44:56+00:00"
+ "time": "2024-10-25T15:15:23+00:00"
},
{
"name": "symfony/finder",
- "version": "v6.2.7",
+ "version": "v7.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "20808dc6631aecafbe67c186af5dcb370be3a0eb"
+ "reference": "87a71856f2f56e4100373e92529eed3171695cfb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/20808dc6631aecafbe67c186af5dcb370be3a0eb",
- "reference": "20808dc6631aecafbe67c186af5dcb370be3a0eb",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb",
+ "reference": "87a71856f2f56e4100373e92529eed3171695cfb",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.2"
},
"require-dev": {
- "symfony/filesystem": "^6.0"
+ "symfony/filesystem": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -925,7 +877,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v6.2.7"
+ "source": "https://github.com/symfony/finder/tree/v7.2.2"
},
"funding": [
{
@@ -941,28 +893,33 @@
"type": "tidelift"
}
],
- "time": "2023-02-16T09:57:23+00:00"
+ "time": "2024-12-30T19:00:17+00:00"
},
{
"name": "symfony/http-client",
- "version": "v6.2.8",
+ "version": "v7.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
- "reference": "66391ba3a8862c560e1d9134c96d9bd2a619b477"
+ "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client/zipball/66391ba3a8862c560e1d9134c96d9bd2a619b477",
- "reference": "66391ba3a8862c560e1d9134c96d9bd2a619b477",
+ "url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
+ "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"psr/log": "^1|^2|^3",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/http-client-contracts": "^3",
- "symfony/service-contracts": "^1.0|^2|^3"
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/http-client-contracts": "~3.4.4|^3.5.2",
+ "symfony/service-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "amphp/amp": "<2.5",
+ "php-http/discovery": "<1.15",
+ "symfony/http-foundation": "<6.4"
},
"provide": {
"php-http/async-client-implementation": "*",
@@ -971,18 +928,20 @@
"symfony/http-client-implementation": "3.0"
},
"require-dev": {
- "amphp/amp": "^2.5",
- "amphp/http-client": "^4.2.1",
- "amphp/http-tunnel": "^1.0",
+ "amphp/http-client": "^4.2.1|^5.0",
+ "amphp/http-tunnel": "^1.0|^2.0",
"amphp/socket": "^1.1",
- "guzzlehttp/promises": "^1.4",
+ "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",
- "symfony/http-kernel": "^5.4|^6.0",
- "symfony/process": "^5.4|^6.0",
- "symfony/stopwatch": "^5.4|^6.0"
+ "symfony/amphp-http-client-meta": "^1.0|^2.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0",
+ "symfony/stopwatch": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -1013,7 +972,7 @@
"http"
],
"support": {
- "source": "https://github.com/symfony/http-client/tree/v6.2.8"
+ "source": "https://github.com/symfony/http-client/tree/v7.2.4"
},
"funding": [
{
@@ -1029,36 +988,33 @@
"type": "tidelift"
}
],
- "time": "2023-03-31T09:14:44+00:00"
+ "time": "2025-02-13T10:27:23+00:00"
},
{
"name": "symfony/http-client-contracts",
- "version": "v3.2.1",
+ "version": "v3.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
- "reference": "df2ecd6cb70e73c1080e6478aea85f5f4da2c48b"
+ "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/df2ecd6cb70e73c1080e6478aea85f5f4da2c48b",
- "reference": "df2ecd6cb70e73c1080e6478aea85f5f4da2c48b",
+ "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645",
+ "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
- "suggest": {
- "symfony/http-client-implementation": ""
- },
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.3-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.5-dev"
}
},
"autoload": {
@@ -1094,7 +1050,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/http-client-contracts/tree/v3.2.1"
+ "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2"
},
"funding": [
{
@@ -1110,24 +1066,24 @@
"type": "tidelift"
}
],
- "time": "2023-03-01T10:32:47+00:00"
+ "time": "2024-12-07T08:49:48+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.27.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
- "reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
@@ -1137,12 +1093,9 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.27-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1176,7 +1129,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
@@ -1192,36 +1145,33 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.27.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "511a08c03c1960e08a883f4cffcacd219b758354"
+ "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
- "reference": "511a08c03c1960e08a883f4cffcacd219b758354",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.27-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1257,7 +1207,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
},
"funding": [
{
@@ -1273,36 +1223,33 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.27.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
- "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.27-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1341,7 +1288,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
},
"funding": [
{
@@ -1357,24 +1304,24 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.27.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
- "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
@@ -1384,12 +1331,9 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.27-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1424,7 +1368,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
},
"funding": [
{
@@ -1440,20 +1384,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/process",
- "version": "v6.2.8",
+ "version": "v6.4.19",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "75ed64103df4f6615e15a7fe38b8111099f47416"
+ "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/75ed64103df4f6615e15a7fe38b8111099f47416",
- "reference": "75ed64103df4f6615e15a7fe38b8111099f47416",
+ "url": "https://api.github.com/repos/symfony/process/zipball/7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3",
+ "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3",
"shasum": ""
},
"require": {
@@ -1485,7 +1429,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v6.2.8"
+ "source": "https://github.com/symfony/process/tree/v6.4.19"
},
"funding": [
{
@@ -1501,40 +1445,38 @@
"type": "tidelift"
}
],
- "time": "2023-03-09T16:20:02+00:00"
+ "time": "2025-02-04T13:35:48+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.2.1",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "a8c9cedf55f314f3a186041d19537303766df09a"
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a",
- "reference": "a8c9cedf55f314f3a186041d19537303766df09a",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
"shasum": ""
},
"require": {
"php": ">=8.1",
- "psr/container": "^2.0"
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
- "suggest": {
- "symfony/service-implementation": ""
- },
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.3-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.5-dev"
}
},
"autoload": {
@@ -1570,7 +1512,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.2.1"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -1586,38 +1528,39 @@
"type": "tidelift"
}
],
- "time": "2023-03-01T10:32:47+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/string",
- "version": "v6.2.8",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef"
+ "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef",
- "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef",
+ "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82",
+ "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"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.0"
+ "symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/error-handler": "^5.4|^6.0",
- "symfony/http-client": "^5.4|^6.0",
- "symfony/intl": "^6.2",
- "symfony/translation-contracts": "^2.0|^3.0",
- "symfony/var-exporter": "^5.4|^6.0"
+ "symfony/emoji": "^7.1",
+ "symfony/error-handler": "^6.4|^7.0",
+ "symfony/http-client": "^6.4|^7.0",
+ "symfony/intl": "^6.4|^7.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
+ "symfony/var-exporter": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -1656,7 +1599,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.2.8"
+ "source": "https://github.com/symfony/string/tree/v7.2.0"
},
"funding": [
{
@@ -1672,42 +1615,42 @@
"type": "tidelift"
}
],
- "time": "2023-03-20T16:06:02+00:00"
+ "time": "2024-11-13T13:31:26+00:00"
},
{
"name": "symfony/translation-contracts",
- "version": "v2.5.2",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
- "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe"
+ "reference": "4667ff3bd513750603a09c8dedbea942487fb07c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe",
- "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c",
+ "reference": "4667ff3bd513750603a09c8dedbea942487fb07c",
"shasum": ""
},
"require": {
- "php": ">=7.2.5"
- },
- "suggest": {
- "symfony/translation-implementation": ""
+ "php": ">=8.1"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.5-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Translation\\": ""
- }
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -1734,7 +1677,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2"
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -1750,38 +1693,41 @@
"type": "tidelift"
}
],
- "time": "2022-06-27T16:58:25+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "twig/twig",
- "version": "v3.5.1",
+ "version": "v3.20.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "a6e0510cc793912b451fd40ab983a1d28f611c15"
+ "reference": "3468920399451a384bef53cf7996965f7cd40183"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/a6e0510cc793912b451fd40ab983a1d28f611c15",
- "reference": "a6e0510cc793912b451fd40ab983a1d28f611c15",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183",
+ "reference": "3468920399451a384bef53cf7996965f7cd40183",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
+ "php": ">=8.1.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
- "psr/container": "^1.0",
- "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+ "phpstan/phpstan": "^2.0",
+ "psr/container": "^1.0|^2.0",
+ "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.5-dev"
- }
- },
"autoload": {
+ "files": [
+ "src/Resources/core.php",
+ "src/Resources/debug.php",
+ "src/Resources/escaper.php",
+ "src/Resources/string_loader.php"
+ ],
"psr-4": {
"Twig\\": "src/"
}
@@ -1814,7 +1760,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.5.1"
+ "source": "https://github.com/twigphp/Twig/tree/v3.20.0"
},
"funding": [
{
@@ -1826,21 +1772,21 @@
"type": "tidelift"
}
],
- "time": "2023-02-08T07:49:20+00:00"
+ "time": "2025-02-13T08:34:43+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "dev",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
- "platform-dev": [],
+ "platform-dev": {},
"platform-overrides": {
- "php": "8.1.0"
+ "php": "8.3"
},
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/_build/maintainer_guide.rst b/_build/maintainer_guide.rst
index fcee70f8f90..9758b4e7397 100644
--- a/_build/maintainer_guide.rst
+++ b/_build/maintainer_guide.rst
@@ -39,14 +39,14 @@ contributes again, it's OK to mention some of the minor issues to educate them.
$ gh merge 11059
- Working on symfony/symfony-docs (branch 5.4)
+ Working on symfony/symfony-docs (branch 6.2)
Merging Pull Request 11059: dmaicher/patch-3
...
# This is important!! Say NO to push the changes now
Push the changes now? (Y/n) n
- Now, push with: git push gh "5.4" refs/notes/github-comments
+ Now, push with: git push gh "6.2" refs/notes/github-comments
# Now, open your editor and make the needed changes ...
@@ -54,7 +54,7 @@ contributes again, it's OK to mention some of the minor issues to educate them.
# Use "Minor reword", "Minor tweak", etc. as the commit message
# now run the 'push' command shown above by 'gh' (it's different each time)
- $ git push gh "5.4" refs/notes/github-comments
+ $ git push gh "6.2" refs/notes/github-comments
Merging Pull Requests
---------------------
diff --git a/_build/redirection_map b/_build/redirection_map
index 295311d1532..ee14c191025 100644
--- a/_build/redirection_map
+++ b/_build/redirection_map
@@ -414,6 +414,7 @@
/security/entity_provider /security/user_provider
/session/avoid_session_start /session
/session/sessions_directory /session
+/session/configuring_ttl /session#session-configure-ttl
/frontend/encore/legacy-apps /frontend/encore/legacy-applications
/configuration/external_parameters /configuration/environment_variables
/contributing/code/patches /contributing/code/pull_requests
@@ -429,6 +430,7 @@
/email/spool /mailer
/email/testing /mailer
/contributing/community/other /contributing/community
+/contributing/code/core_team /contributing/core_team
/profiler/storage /profiler
/setup/composer /setup
/security/security_checker /setup
@@ -524,9 +526,10 @@
/testing/functional_tests_assertions /testing#testing-application-assertions
/components https://symfony.com/components
/components/index https://symfony.com/components
-/serializer/normalizers /components/serializer#normalizers
+/serializer/normalizers /serializer#serializer-built-in-normalizers
/logging/monolog_regex_based_excludes /logging/monolog_exclude_http_codes
/security/named_encoders /security/named_hashers
+/components/inflector /string#inflector
/security/experimental_authenticators /security
/security/user_provider /security/user_providers
/security/reset_password /security/passwords#reset-password
@@ -555,3 +558,19 @@
/notifier/chatters /notifier#sending-chat-messages
/notifier/texters /notifier#sending-sms
/notifier/events /notifier#notifier-events
+/email /mailer
+/frontend/assetic /frontend
+/frontend/assetic/index /frontend
+/controller/argument_value_resolver /controller/value_resolver
+/frontend/ux https://symfony.com/bundles/StimulusBundle/current/index.html
+/messenger/handler_results /messenger#messenger-getting-handler-results
+/messenger/dispatch_after_current_bus /messenger#messenger-transactional-messages
+/messenger/multiple_buses /messenger#messenger-multiple-buses
+/frontend/encore/server-data /frontend/server-data
+/components/string /string
+/testing/http_authentication /testing#testing_logging_in_users
+/doctrine/registration_form /security#security-make-registration-form
+/form/form_dependencies /form/create_custom_field_type
+/doctrine/reverse_engineering /doctrine#doctrine-adding-mapping
+/components/serializer /serializer
+/serializer/custom_encoder /serializer/encoders#serializer-custom-encoder
diff --git a/_build/spelling_word_list.txt b/_build/spelling_word_list.txt
deleted file mode 100644
index 70240ceb6d1..00000000000
--- a/_build/spelling_word_list.txt
+++ /dev/null
@@ -1,345 +0,0 @@
-accessor
-Akamai
-analytics
-Ansi
-Ansible
-Assetic
-async
-authenticator
-authenticators
-autocompleted
-autocompletion
-autoconfiguration
-autoconfigure
-autoconfigured
-autoconfigures
-autoconfiguring
-autoload
-autoloaded
-autoloader
-autoloaders
-autoloading
-autoprefixing
-autowire
-autowireable
-autowired
-autowiring
-backend
-backends
-balancer
-balancers
-bcrypt
-benchmarking
-Bitbucket
-bitmask
-bitmasks
-bitwise
-Blackfire
-boolean
-booleans
-Brasseur
-browserslist
-buildpack
-buildpacks
-bundler
-cacheable
-Caddy
-callables
-camelCase
-casted
-changelog
-changeset
-charset
-charsets
-checkboxes
-classmap
-classname
-clearers
-cloner
-cloners
-codebase
-config
-configs
-configurator
-configurators
-contrib
-cron
-cronjobs
-cryptographic
-cryptographically
-Ctrl
-ctype
-cURL
-customizable
-customizations
-Cygwin
-dataset
-datepicker
-decrypt
-denormalization
-denormalize
-denormalized
-denormalizing
-deprecations
-deserialization
-deserialize
-deserialized
-deserializing
-destructor
-dev
-dn
-DNS
-docblock
-Dotenv
-downloader
-Doxygen
-DSN
-Dunglas
-easter
-Eberlei
-emilie
-enctype
-entrypoints
-enum
-env
-escaper
-escpaer
-extensibility
-extractable
-eZPublish
-Fabien
-failover
-filesystem
-filesystems
-formatter
-formatters
-frontend
-getter
-getters
-GitHub
-gmail
-Gmail
-Goutte
-grapheme
-hardcode
-hardcoded
-hardcodes
-hardcoding
-hasser
-hassers
-headshot
-HInclude
-hostname
-https
-iconv
-igbinary
-incrementing
-ini
-inlined
-inlining
-installable
-instantiation
-interoperable
-intl
-Intl
-invokable
-IPv
-isser
-issers
-Jpegoptim
-jQuery
-js
-Karlton
-kb
-kB
-Kévin
-Ki
-KiB
-kibibyte
-Kubernetes
-Kudu
-labelled
-latin
-Ldap
-libketama
-licensor
-lifecycle
-liip
-linter
-localhost
-Loggly
-Logplex
-lookups
-loopback
-lorenzo
-Luhn
-macOS
-matcher
-matchers
-mbstring
-mebibyte
-memcache
-memcached
-MiB
-michelle
-minification
-minified
-minifier
-minifies
-minify
-minifying
-misconfiguration
-misconfigured
-misgendering
-Monolog
-mutator
-nagle
-namespace
-namespaced
-namespaces
-namespacing
-natively
-nd
-netmasks
-nginx
-normalizer
-normalizers
-npm
-nyholm
-OAuth
-OPcache
-overcomplicate
-Packagist
-parallelizes
-parsers
-PHP
-PHPUnit
-PID
-plaintext
-polyfill
-polyfills
-postcss
-Potencier
-pre
-preconfigured
-predefines
-Predis
-preload
-preloaded
-preloading
-prepend
-prepended
-prepending
-prepends
-preprocessed
-preprocessors
-Procfile
-profiler
-programmatically
-prototyped
-rebase
-reconfiguring
-reconnection
-redirections
-refactorization
-regexes
-renderer
-resolvers
-responder
-reStructuredText
-reusability
-runtime
-sandboxing
-schemas
-screencast
-semantical
-serializable
-serializer
-sexualized
-Silex
-sluggable
-socio
-specificities
-SQLite
-stacktrace
-stacktraces
-storages
-stringified
-stylesheet
-stylesheets
-subclasses
-subdirectories
-subdirectory
-sublcasses
-sublicense
-sublincense
-subrequests
-subtree
-superclass
-superglobal
-superglobals
-symfony
-Symfony
-symlink
-symlinks
-syntaxes
-templating
-testability
-th
-theming
-throbber
-timestampable
-timezones
-TLS
-tmpfs
-tobias
-todo
-Tomayko
-Toolbelt
-tooltip
-Traversable
-triaging
-UI
-uid
-unary
-unauthenticate
-uncacheable
-uncached
-uncomment
-uncommented
-undelete
-unhandled
-unicode
-Unix
-unmapped
-unminified
-unported
-unregister
-unrendered
-unserialize
-unserialized
-unserializing
-unsubmitted
-untracked
-uploader
-URI
-validator
-validators
-variadic
-VirtualBox
-Vue
-webpack
-webpacked
-webpackJsonp
-webserver
-whitespace
-whitespaces
-woh
-Wordpress
-Xdebug
-xkcd
-Xliff
-XML
-XPath
-yaml
-yay
diff --git a/_images/components/messenger/basic_cycle.png b/_images/components/messenger/basic_cycle.png
new file mode 100644
index 00000000000..a0558968cbb
Binary files /dev/null and b/_images/components/messenger/basic_cycle.png differ
diff --git a/_images/components/messenger/overview.svg b/_images/components/messenger/overview.svg
index 94737e7a6da..4b82c203756 100644
--- a/_images/components/messenger/overview.svg
+++ b/_images/components/messenger/overview.svg
@@ -1 +1 @@
-
+
diff --git a/_images/components/scheduler/generate_consume.png b/_images/components/scheduler/generate_consume.png
new file mode 100644
index 00000000000..269281266a5
Binary files /dev/null and b/_images/components/scheduler/generate_consume.png differ
diff --git a/_images/components/scheduler/scheduler_cycle.png b/_images/components/scheduler/scheduler_cycle.png
new file mode 100644
index 00000000000..18addb37d91
Binary files /dev/null and b/_images/components/scheduler/scheduler_cycle.png differ
diff --git a/_images/components/var_dumper/10-uninitialized.png b/_images/components/var_dumper/10-uninitialized.png
new file mode 100644
index 00000000000..735731b83b5
Binary files /dev/null and b/_images/components/var_dumper/10-uninitialized.png differ
diff --git a/_images/components/workflow/blogpost_metadata.png b/_images/components/workflow/blogpost_metadata.png
new file mode 100644
index 00000000000..783f51c6ccf
Binary files /dev/null and b/_images/components/workflow/blogpost_metadata.png differ
diff --git a/_images/profiler/web-interface.png b/_images/profiler/web-interface.png
index 2a1bc8a0650..b107f6427d7 100644
Binary files a/_images/profiler/web-interface.png and b/_images/profiler/web-interface.png differ
diff --git a/_images/components/serializer/serializer_workflow.svg b/_images/serializer/serializer_workflow.svg
similarity index 100%
rename from _images/components/serializer/serializer_workflow.svg
rename to _images/serializer/serializer_workflow.svg
diff --git a/_images/sources/README.md b/_images/sources/README.md
index 467d4024010..84810a9783d 100644
--- a/_images/sources/README.md
+++ b/_images/sources/README.md
@@ -96,7 +96,7 @@ only the asciicast file).
[1]: http://dia-installer.de/
[2]: https://fonts.google.com/specimen/PT+Sans+Narrow
-[3]: https://symfony.com/doc/current/contributing/code/core_team.html
+[3]: https://symfony.com/doc/current/contributing/core_team.html
[4]: https://github.com/asciinema/asciinema
[5]: https://github.com/asciinema/agg
[6]: https://www.jetbrains.com/lp/mono/
diff --git a/_images/sources/components/messenger/overview.dia b/_images/sources/components/messenger/overview.dia
index 55ee153439e..b0e2edaeab2 100644
Binary files a/_images/sources/components/messenger/overview.dia and b/_images/sources/components/messenger/overview.dia differ
diff --git a/_images/sources/components/serializer/serializer_workflow.dia b/_images/sources/serializer/serializer_workflow.dia
similarity index 100%
rename from _images/sources/components/serializer/serializer_workflow.dia
rename to _images/sources/serializer/serializer_workflow.dia
diff --git a/_includes/_annotation_loader_tip.rst.inc b/_includes/_annotation_loader_tip.rst.inc
deleted file mode 100644
index 0f4267b07f5..00000000000
--- a/_includes/_annotation_loader_tip.rst.inc
+++ /dev/null
@@ -1,19 +0,0 @@
-.. note::
-
- In order to use the annotation loader, you should have installed the
- ``doctrine/annotations`` and ``doctrine/cache`` packages with Composer.
-
-.. tip::
-
- Annotation classes aren't loaded automatically, so you must load them
- using a class loader like this::
-
- use Composer\Autoload\ClassLoader;
- use Doctrine\Common\Annotations\AnnotationRegistry;
-
- /** @var ClassLoader $loader */
- $loader = require __DIR__.'/../vendor/autoload.php';
-
- AnnotationRegistry::registerLoader([$loader, 'loadClass']);
-
- return $loader;
diff --git a/best_practices.rst b/best_practices.rst
index cc38287365e..2c393cae9c6 100644
--- a/best_practices.rst
+++ b/best_practices.rst
@@ -214,9 +214,6 @@ Doctrine supports several metadata formats, but it's recommended to use PHP
attributes because they are by far the most convenient and agile way of setting
up and looking for mapping information.
-If your PHP version doesn't support attributes yet, use annotations, which is
-similar but requires installing some extra dependencies in your project.
-
Controllers
-----------
@@ -234,43 +231,37 @@ nothing more than a few lines of *glue-code*, so you are not coupling the
important parts of your application.
.. _best-practice-controller-annotations:
+.. _best-practice-controller-attributes:
-Use Attributes or Annotations to Configure Routing, Caching, and Security
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Use Attributes to Configure Routing, Caching, and Security
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Using attributes or annotations for routing, caching, and security simplifies
+Using attributes for routing, caching, and security simplifies
configuration. You don't need to browse several files created with different
formats (YAML, XML, PHP): all the configuration is just where you require it,
and it only uses one format.
-Don't Use Annotations to Configure the Controller Template
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``@Template`` annotation is useful, but also involves some *magic*.
-Moreover, most of the time ``@Template`` is used without any parameters, which
-makes it more difficult to know which template is being rendered. It also hides
-the fact that a controller should always return a ``Response`` object.
-
Use Dependency Injection to Get Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you extend the base ``AbstractController``, you can only access to the most
+If you extend the base ``AbstractController``, you can only get access to the most
common services (e.g ``twig``, ``router``, ``doctrine``, etc.), directly from the
container via ``$this->container->get()``.
Instead, you must use dependency injection to fetch services by
:ref:`type-hinting action method arguments ` or
constructor arguments.
-Use ParamConverters If They Are Convenient
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Use Entity Value Resolvers If They Are Convenient
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you're using :doc:`Doctrine `, then you can *optionally* use the
-`ParamConverter`_ to automatically query for an entity and pass it as an argument
-to your controller. It will also show a 404 page if no entity can be found.
+If you're using :doc:`Doctrine `, then you can *optionally* use
+the :ref:`EntityValueResolver ` to
+automatically query for an entity and pass it as an argument to your
+controller. It will also show a 404 page if no entity can be found.
If the logic to get an entity from a route variable is more complex, instead of
-configuring the ParamConverter, it's better to make the Doctrine query inside
-the controller (e.g. by calling to a :doc:`Doctrine repository method `).
+configuring the EntityValueResolver, it's better to make the Doctrine query
+inside the controller (e.g. by calling to a :doc:`Doctrine repository method `).
Templates
---------
@@ -298,7 +289,7 @@ Define your Forms as PHP Classes
Creating :ref:`forms in classes ` allows reusing
them in different parts of the application. Besides, not creating forms in
-controllers simplify the code and maintenance of the controllers.
+controllers simplifies the code and maintenance of the controllers.
Add Form Buttons in Templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -380,30 +371,27 @@ Use the ``auto`` Password Hasher
The :ref:`auto password hasher ` automatically
selects the best possible encoder/hasher depending on your PHP installation.
-Starting from Symfony 5.3, the default auto hasher is ``bcrypt``.
+Currently, the default auto hasher is ``bcrypt``.
Use Voters to Implement Fine-grained Security Restrictions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If your security logic is complex, you should create custom
:doc:`security voters ` instead of defining long expressions
-inside the ``#[Security]`` attribute (or in the ``@Security`` annotation if your
-PHP version doesn't support attributes yet).
+inside the ``#[Security]`` attribute.
Web Assets
----------
-Use Webpack Encore to Process Web Assets
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. _use-webpack-encore-to-process-web-assets:
-Web assets are things like CSS, JavaScript, and image files that make the
-frontend of your site look and work great. `Webpack`_ is the leading JavaScript
-module bundler that compiles, transforms and packages assets for usage in a browser.
+Use AssetMapper to Manage Web Assets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-:doc:`Webpack Encore ` is a JavaScript library that gets rid of most
-of Webpack complexity without hiding any of its features or distorting its usage
-and philosophy. It was created for Symfony applications, but it works
-for any application using any technology.
+Web assets are the CSS, JavaScript, and image files that make the frontend of
+your site look and work great. :doc:`AssetMapper ` lets
+you write modern JavaScript and CSS without the complexity of using a bundler
+such as `Webpack`_ (directly or via :doc:`Webpack Encore `).
Tests
-----
@@ -426,7 +414,7 @@ checks that all application URLs load successfully::
/**
* @dataProvider urlProvider
*/
- public function testPageIsSuccessful($url)
+ public function testPageIsSuccessful($url): void
{
$client = self::createClient();
$client->request('GET', $url);
@@ -434,7 +422,7 @@ checks that all application URLs load successfully::
$this->assertResponseIsSuccessful();
}
- public function urlProvider()
+ public function urlProvider(): \Generator
{
yield ['/'];
yield ['/posts'];
@@ -466,7 +454,6 @@ you must set up a redirection.
.. _`Symfony Demo`: https://github.com/symfony/demo
.. _`download Symfony`: https://symfony.com/download
.. _`Composer`: https://getcomposer.org/
-.. _`ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
.. _`feature toggles`: https://en.wikipedia.org/wiki/Feature_toggle
.. _`smoke testing`: https://en.wikipedia.org/wiki/Smoke_testing_(software)
.. _`Webpack`: https://webpack.js.org/
diff --git a/bundles.rst b/bundles.rst
index 02db1dd5d23..878bee3af4a 100644
--- a/bundles.rst
+++ b/bundles.rst
@@ -3,7 +3,7 @@
The Bundle System
=================
-.. caution::
+.. warning::
In Symfony versions prior to 4.0, it was recommended to organize your own
application code using bundles. This is :ref:`no longer recommended ` and bundles
@@ -22,13 +22,15 @@ file::
return [
// 'all' means that the bundle is enabled for any Symfony environment
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
- Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
- Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
- Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
- Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
- Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
+ // ...
+
+ // this bundle is enabled only in 'dev'
+ Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
+ // ...
+
// this bundle is enabled only in 'dev' and 'test', so you can't use it in 'prod'
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
+ // ...
];
.. tip::
@@ -41,28 +43,32 @@ Creating a Bundle
-----------------
This section creates and enables a new bundle to show there are only a few steps required.
-The new bundle is called AcmeTestBundle, where the ``Acme`` portion is an example
+The new bundle is called AcmeBlogBundle, where the ``Acme`` portion is an example
name that should be replaced by some "vendor" name that represents you or your
-organization (e.g. ABCTestBundle for some company named ``ABC``).
+organization (e.g. AbcBlogBundle for some company named ``Abc``).
-Start by creating a ``src/Acme/TestBundle/`` directory and adding a new file
-called ``AcmeTestBundle.php``::
+Start by creating a new class called ``AcmeBlogBundle``::
- // src/Acme/TestBundle/AcmeTestBundle.php
- namespace App\Acme\TestBundle;
+ // src/AcmeBlogBundle.php
+ namespace Acme\BlogBundle;
- use Symfony\Component\HttpKernel\Bundle\Bundle;
+ use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
- class AcmeTestBundle extends Bundle
+ class AcmeBlogBundle extends AbstractBundle
{
}
+.. warning::
+
+ If your bundle must be compatible with previous Symfony versions you have to
+ extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\Bundle` instead.
+
.. tip::
- The name AcmeTestBundle follows the standard
+ The name AcmeBlogBundle follows the standard
:ref:`Bundle naming conventions `. You could
- also choose to shorten the name of the bundle to simply TestBundle by naming
- this class TestBundle (and naming the file ``TestBundle.php``).
+ also choose to shorten the name of the bundle to simply BlogBundle by naming
+ this class BlogBundle (and naming the file ``BlogBundle.php``).
This empty class is the only piece you need to create the new bundle. Though
commonly empty, this class is powerful and can be used to customize the behavior
@@ -71,10 +77,12 @@ of the bundle. Now that you've created the bundle, enable it::
// config/bundles.php
return [
// ...
- App\Acme\TestBundle\AcmeTestBundle::class => ['all' => true],
+ Acme\BlogBundle\AcmeBlogBundle::class => ['all' => true],
];
-And while it doesn't do anything yet, AcmeTestBundle is now ready to be used.
+And while it doesn't do anything yet, AcmeBlogBundle is now ready to be used.
+
+.. _bundles-directory-structure:
Bundle Directory Structure
--------------------------
@@ -83,35 +91,71 @@ The directory structure of a bundle is meant to help to keep code consistent
between all Symfony bundles. It follows a set of conventions, but is flexible
to be adjusted if needed:
-``Controller/``
- the controllers of the bundle (e.g. ``RandomController.php``).
-
-``DependencyInjection/``
- Holds certain Dependency Injection Extension classes, which may import service
- configuration, register compiler passes or more (this directory is not
- necessary).
-
-``Resources/config/``
- Houses configuration, including routing configuration (e.g. ``routing.yaml``).
+``assets/``
+ Contains the web asset sources like JavaScript and TypeScript files, CSS and
+ Sass files, but also images and other assets related to the bundle that are
+ not in ``public/`` (e.g. Stimulus controllers).
-``Resources/views/``
- Holds templates organized by controller name (e.g. ``Random/index.html.twig``).
+``config/``
+ Houses configuration, including routing configuration (e.g. ``routes.php``).
-``Resources/public/``
+``public/``
Contains web assets (images, compiled CSS and JavaScript files, etc.) and is
copied or symbolically linked into the project ``public/`` directory via the
``assets:install`` console command.
-``Tests/``
+``src/``
+ Contains all PHP classes related to the bundle logic (e.g. ``Controller/CategoryController.php``).
+
+``templates/``
+ Holds templates organized by controller name (e.g. ``category/show.html.twig``).
+
+``tests/``
Holds all tests for the bundle.
-A bundle can be as small or large as the feature it implements. It contains
-only the files you need and nothing else.
+``translations/``
+ Holds translations organized by domain and locale (e.g. ``AcmeBlogBundle.en.xlf``).
+
+.. _bundles-legacy-directory-structure:
+
+.. warning::
+
+ The recommended bundle structure was changed in Symfony 5, read the
+ `Symfony 4.4 bundle documentation`_ for information about the old
+ structure.
+
+ When using the new ``AbstractBundle`` class, the bundle defaults to the
+ new structure. Override the ``Bundle::getPath()`` method to change to
+ the old structure::
+
+ class AcmeBlogBundle extends AbstractBundle
+ {
+ public function getPath(): string
+ {
+ return __DIR__;
+ }
+ }
+
+.. tip::
-As you move through the guides, you'll learn how to persist objects to a
-database, create and validate forms, create translations for your application,
-write tests and much more. Each of these has their own place and role within
-the bundle.
+ It's recommended to use the `PSR-4`_ autoload standard: use the namespace as key,
+ and the location of the bundle's main class (relative to ``composer.json``)
+ as value. As the main class is located in the ``src/`` directory of the bundle:
+
+ .. code-block:: json
+
+ {
+ "autoload": {
+ "psr-4": {
+ "Acme\\BlogBundle\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Acme\\BlogBundle\\Tests\\": "tests/"
+ }
+ }
+ }
Learn more
----------
@@ -123,3 +167,5 @@ Learn more
* :doc:`/bundles/prepend_extension`
.. _`third-party bundles`: https://github.com/search?q=topic%3Asymfony-bundle&type=Repositories
+.. _`Symfony 4.4 bundle documentation`: https://symfony.com/doc/4.4/bundles.html#bundle-directory-structure
+.. _`PSR-4`: https://www.php-fig.org/psr/psr-4/
diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst
index d2819e42fdb..37dc386b8e4 100644
--- a/bundles/best_practices.rst
+++ b/bundles/best_practices.rst
@@ -78,16 +78,22 @@ The following is the recommended directory structure of an AcmeBlogBundle:
├── LICENSE
└── README.md
-This directory structure requires to configure the bundle path to its root
-directory as follows::
+.. note::
+
+ This directory structure is used by default when your bundle class extends
+ the recommended :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`.
+ If your bundle extends the :class:`Symfony\\Component\\HttpKernel\\Bundle\\Bundle`
+ class, you have to override the ``getPath()`` method as follows::
- class AcmeBlogBundle extends Bundle
- {
- public function getPath(): string
+ use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+ class AcmeBlogBundle extends Bundle
{
- return \dirname(__DIR__);
+ public function getPath(): string
+ {
+ return \dirname(__DIR__);
+ }
}
- }
**The following files are mandatory**, because they ensure a structure convention
that automated tools can rely on:
@@ -125,8 +131,8 @@ Configuration (routes, services, etc.) ``config/``
Web Assets (compiled CSS and JS, images) ``public/``
Web Asset sources (``.scss``, ``.ts``, Stimulus) ``assets/``
Translation files ``translations/``
-Validation (when not using annotations) ``config/validation/``
-Serialization (when not using annotations) ``config/serialization/``
+Validation (when not using attributes) ``config/validation/``
+Serialization (when not using attributes) ``config/serialization/``
Templates ``templates/``
Unit and Functional Tests ``tests/``
=================================================== ========================================
@@ -165,13 +171,7 @@ If the bundle includes Doctrine ORM entities and/or ODM documents, it's
recommended to define their mapping using XML files stored in
``config/doctrine/``. This allows to override that mapping using the
:doc:`standard Symfony mechanism to override bundle parts `.
-This is not possible when using annotations/attributes to define the mapping.
-
-.. caution::
-
- The recommended bundle structure was changed in Symfony 5, read the
- `Symfony 4.4 bundle documentation`_ for information about the old
- structure.
+This is not possible when using attributes to define the mapping.
Tests
-----
@@ -246,7 +246,7 @@ with Symfony Flex to install a specific Symfony version:
# recommended to have a better output and faster download time)
composer update --prefer-dist --no-progress
-.. caution::
+.. warning::
If you want to cache your Composer dependencies, **do not** cache the
``vendor/`` directory as this has side-effects. Instead cache
@@ -298,7 +298,7 @@ following standardized instructions in your ``README.md`` file.
Open a command console, enter your project directory and execute:
```console
- $ composer require
+ composer require
```
Applications that don't use Symfony Flex
@@ -310,7 +310,7 @@ following standardized instructions in your ``README.md`` file.
following command to download the latest stable version of this bundle:
```console
- $ composer require
+ composer require
```
### Step 2: Enable the Bundle
@@ -339,9 +339,9 @@ following standardized instructions in your ``README.md`` file.
Open a command console, enter your project directory and execute:
- .. code-block:: bash
+ .. code-block:: terminal
- $ composer require
+ composer require
Applications that don't use Symfony Flex
----------------------------------------
@@ -354,7 +354,7 @@ following standardized instructions in your ``README.md`` file.
.. code-block:: terminal
- $ composer require
+ composer require
Step 2: Enable the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -397,10 +397,14 @@ Translation Files
-----------------
If a bundle provides message translations, they must be defined in the XLIFF
-format; the domain should be named after the bundle name (``acme_blog``).
+format; the domain should be named after the bundle name (``AcmeBlog``).
A bundle must not override existing messages from another bundle.
+The translation domain must match the translation file names. For example,
+if the translation domain is ``AcmeBlog``, the English translation file name
+should be ``AcmeBlog.en.xlf``.
+
Configuration
-------------
@@ -444,7 +448,7 @@ The end user can provide values in any configuration file:
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
- return static function (ContainerConfigurator $container) {
+ return static function (ContainerConfigurator $container): void {
$container->parameters()
->set('acme_blog.author.email', 'fabien@example.com')
;
@@ -565,4 +569,3 @@ Learn more
.. _`valid license identifier`: https://spdx.org/licenses/
.. _`GitHub Actions`: https://docs.github.com/en/free-pro-team@latest/actions
.. _`Travis CI`: https://docs.travis-ci.com/
-.. _`Symfony 4.4 bundle documentation`: https://symfony.com/doc/4.4/bundles.html#bundle-directory-structure
diff --git a/bundles/configuration.rst b/bundles/configuration.rst
index a30b6310ec1..dedfada2ea2 100644
--- a/bundles/configuration.rst
+++ b/bundles/configuration.rst
@@ -42,15 +42,114 @@ as integration of other related components:
// config/packages/framework.php
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework) {
+ return static function (FrameworkConfig $framework): void {
$framework->form()->enabled(true);
};
+There are two different ways of creating friendly configuration for a bundle:
+
+#. :ref:`Using the main bundle class `:
+ this is recommended for new bundles and for bundles following the
+ :ref:`recommended directory structure `;
+#. :ref:`Using the Bundle extension class `:
+ this was the traditional way of doing it, but nowadays it's only recommended for
+ bundles following the :ref:`legacy directory structure `.
+
+.. _using-the-bundle-class:
+.. _bundle-friendly-config-bundle-class:
+
+Using the AbstractBundle Class
+------------------------------
+
+In bundles extending the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
+class, you can add all the logic related to processing the configuration in that class::
+
+ // src/AcmeSocialBundle.php
+ namespace Acme\SocialBundle;
+
+ use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
+ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+ use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
+
+ class AcmeSocialBundle extends AbstractBundle
+ {
+ public function configure(DefinitionConfigurator $definition): void
+ {
+ $definition->rootNode()
+ ->children()
+ ->arrayNode('twitter')
+ ->children()
+ ->integerNode('client_id')->end()
+ ->scalarNode('client_secret')->end()
+ ->end()
+ ->end() // twitter
+ ->end()
+ ;
+ }
+
+ public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
+ {
+ // the "$config" variable is already merged and processed so you can
+ // use it directly to configure the service container (when defining an
+ // extension class, you also have to do this merging and processing)
+ $container->services()
+ ->get('acme_social.twitter_client')
+ ->arg(0, $config['twitter']['client_id'])
+ ->arg(1, $config['twitter']['client_secret'])
+ ;
+ }
+ }
+
+.. note::
+
+ The ``configure()`` and ``loadExtension()`` methods are called only at compile time.
+
+.. tip::
+
+ The ``AbstractBundle::configure()`` method also allows to import the
+ configuration definition from one or more files::
+
+ // src/AcmeSocialBundle.php
+ namespace Acme\SocialBundle;
+
+ // ...
+ class AcmeSocialBundle extends AbstractBundle
+ {
+ public function configure(DefinitionConfigurator $definition): void
+ {
+ $definition->import('../config/definition.php');
+ // you can also use glob patterns
+ //$definition->import('../config/definition/*.php');
+ }
+
+ // ...
+ }
+
+ .. code-block:: php
+
+ // config/definition.php
+ use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
+
+ return static function (DefinitionConfigurator $definition): void {
+ $definition->rootNode()
+ ->children()
+ ->scalarNode('foo')->defaultValue('bar')->end()
+ ->end()
+ ;
+ };
+
+.. _bundle-friendly-config-extension:
+
Using the Bundle Extension
--------------------------
+This is the traditional way of creating friendly configuration for bundles. For new
+bundles it's recommended to :ref:`use the main bundle class `,
+but the traditional way of creating an extension class still works.
+
Imagine you are creating a new bundle - AcmeSocialBundle - which provides
-integration with Twitter. To make your bundle configurable to the user, you
+integration with X/Twitter. To make your bundle configurable to the user, you
can add some configuration that looks like this:
.. configuration-block::
@@ -85,7 +184,7 @@ can add some configuration that looks like this:
// config/packages/acme_social.php
use Symfony\Config\AcmeSocialConfig;
- return static function (AcmeSocialConfig $acmeSocial) {
+ return static function (AcmeSocialConfig $acmeSocial): void {
$acmeSocial->twitter()
->clientId(123)
->clientSecret('your_secret');
@@ -110,7 +209,7 @@ load correct services and parameters inside an "Extension" class.
If a bundle provides an Extension class, then you should *not* generally
override any service container parameters from that bundle. The idea
- is that if an Extension class is present, every setting that should be
+ is that if an extension class is present, every setting that should be
configurable should be present in the configuration made available by
that class. In other words, the extension class defines all the public
configuration settings for which backward compatibility will be maintained.
@@ -175,7 +274,7 @@ of your bundle's configuration.
The ``Configuration`` class to handle the sample configuration looks like::
- // src/Acme/SocialBundle/DependencyInjection/Configuration.php
+ // src/DependencyInjection/Configuration.php
namespace Acme\SocialBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
@@ -183,7 +282,7 @@ The ``Configuration`` class to handle the sample configuration looks like::
class Configuration implements ConfigurationInterface
{
- public function getConfigTreeBuilder()
+ public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('acme_social');
@@ -216,8 +315,8 @@ This class can now be used in your ``load()`` method to merge configurations and
force validation (e.g. if an additional option was passed, an exception will be
thrown)::
- // src/Acme/SocialBundle/DependencyInjection/AcmeSocialExtension.php
- public function load(array $configs, ContainerBuilder $container)
+ // src/DependencyInjection/AcmeSocialExtension.php
+ public function load(array $configs, ContainerBuilder $container): void
{
$configuration = new Configuration();
@@ -236,7 +335,7 @@ For example, imagine your bundle has the following example config:
.. code-block:: xml
-
+
-
+
@@ -253,13 +352,13 @@ For example, imagine your bundle has the following example config:
In your extension, you can load this and dynamically set its arguments::
- // src/Acme/SocialBundle/DependencyInjection/AcmeSocialExtension.php
- // ...
+ // src/DependencyInjection/AcmeSocialExtension.php
+ namespace Acme\SocialBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
- public function load(array $configs, ContainerBuilder $container)
+ public function load(array $configs, ContainerBuilder $container): void
{
$loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__).'/Resources/config'));
$loader->load('services.xml');
@@ -267,7 +366,7 @@ In your extension, you can load this and dynamically set its arguments::
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
- $definition = $container->getDefinition('acme.social.twitter_client');
+ $definition = $container->getDefinition('acme_social.twitter_client');
$definition->replaceArgument(0, $config['twitter']['client_id']);
$definition->replaceArgument(1, $config['twitter']['client_secret']);
}
@@ -279,7 +378,7 @@ In your extension, you can load this and dynamically set its arguments::
:class:`Symfony\\Component\\HttpKernel\\DependencyInjection\\ConfigurableExtension`
to do this automatically for you::
- // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
+ // src/DependencyInjection/HelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -288,7 +387,7 @@ In your extension, you can load this and dynamically set its arguments::
class AcmeHelloExtension extends ConfigurableExtension
{
// note that this method is called loadInternal and not load
- protected function loadInternal(array $mergedConfig, ContainerBuilder $container)
+ protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void
{
// ...
}
@@ -304,7 +403,7 @@ In your extension, you can load this and dynamically set its arguments::
(e.g. by overriding configurations and using :phpfunction:`isset` to check
for the existence of a value). Be aware that it'll be very hard to support XML::
- public function load(array $configs, ContainerBuilder $container)
+ public function load(array $configs, ContainerBuilder $container): void
{
$config = [];
// let resources override the previous set value
@@ -330,7 +429,7 @@ The ``config:dump-reference`` command dumps the default configuration of a
bundle in the console using the Yaml format.
As long as your bundle's configuration is located in the standard location
-(``YourBundle\DependencyInjection\Configuration``) and does not have
+(``/src/DependencyInjection/Configuration``) and does not have
a constructor, it will work automatically. If you
have something different, your ``Extension`` class must override the
:method:`Extension::getConfiguration() `
@@ -364,14 +463,15 @@ URL nor does it need to exist). By default, the namespace for a bundle is
``http://example.org/schema/dic/DI_ALIAS``, where ``DI_ALIAS`` is the DI alias of
the extension. You might want to change this to a more professional URL::
- // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
+ // src/DependencyInjection/AcmeHelloExtension.php
+ namespace Acme\HelloBundle\DependencyInjection;
// ...
class AcmeHelloExtension extends Extension
{
// ...
- public function getNamespace()
+ public function getNamespace(): string
{
return 'http://acme_company.com/schema/dic/hello';
}
@@ -393,19 +493,20 @@ namespace is then replaced with the XSD validation base path returned from
method. This namespace is then followed by the rest of the path from the base
path to the file itself.
-By convention, the XSD file lives in the ``Resources/config/schema/``, but you
+By convention, the XSD file lives in ``config/schema/`` directory, but you
can place it anywhere you like. You should return this path as the base path::
- // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
+ // src/DependencyInjection/AcmeHelloExtension.php
+ namespace Acme\HelloBundle\DependencyInjection;
// ...
class AcmeHelloExtension extends Extension
{
// ...
- public function getXsdValidationBasePath()
+ public function getXsdValidationBasePath(): string
{
- return __DIR__.'/../Resources/config/schema';
+ return __DIR__.'/../config/schema';
}
}
diff --git a/bundles/extension.rst b/bundles/extension.rst
index 74659cd98b6..d2792efc477 100644
--- a/bundles/extension.rst
+++ b/bundles/extension.rst
@@ -6,12 +6,74 @@ file used by the application but in the bundles themselves. This article
explains how to create and load service files using the bundle directory
structure.
+There are two different ways of doing it:
+
+#. :ref:`Load your services in the main bundle class `:
+ this is recommended for new bundles and for bundles following the
+ :ref:`recommended directory structure `;
+#. :ref:`Create an extension class to load the service configuration files `:
+ this was the traditional way of doing it, but nowadays it's only recommended for
+ bundles following the :ref:`legacy directory structure `.
+
+.. _bundle-load-services-bundle-class:
+
+Loading Services Directly in your Bundle Class
+----------------------------------------------
+
+In bundles extending the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
+class, you can define the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::loadExtension`
+method to load service definitions from configuration files::
+
+ // ...
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
+ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+ use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
+
+ class AcmeHelloBundle extends AbstractBundle
+ {
+ public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
+ {
+ // load an XML, PHP or YAML file
+ $container->import('../config/services.xml');
+
+ // you can also add or replace parameters and services
+ $container->parameters()
+ ->set('acme_hello.phrase', $config['phrase'])
+ ;
+
+ if ($config['scream']) {
+ $container->services()
+ ->get('acme_hello.printer')
+ ->class(ScreamingPrinter::class)
+ ;
+ }
+ }
+ }
+
+This method works similar to the ``Extension::load()`` method explained below,
+but it uses a new simpler API to define and import service configuration.
+
+.. note::
+
+ Contrary to the ``$configs`` parameter in ``Extension::load()``, the
+ ``$config`` parameter is already merged and processed by the
+ ``AbstractBundle``.
+
+.. note::
+
+ The ``loadExtension()`` is called only at compile time.
+
+.. _bundle-load-services-extension:
+
Creating an Extension Class
---------------------------
-In order to load service configuration, you have to create a Dependency
-Injection (DI) Extension for your bundle. By default, the Extension class must
-follow these conventions (but later you'll learn how to skip them if needed):
+This is the traditional way of loading service definitions in bundles. For new
+bundles it's recommended to :ref:`load your services in the main bundle class `,
+but the traditional way of creating an extension class still works.
+
+A dependency injection extension is defined as a class that follows these
+conventions (later you'll learn how to skip them if needed):
* It has to live in the ``DependencyInjection`` namespace of the bundle;
@@ -20,13 +82,13 @@ follow these conventions (but later you'll learn how to skip them if needed):
:class:`Symfony\\Component\\DependencyInjection\\Extension\\Extension` class;
* The name is equal to the bundle name with the ``Bundle`` suffix replaced by
- ``Extension`` (e.g. the Extension class of the AcmeBundle would be called
+ ``Extension`` (e.g. the extension class of the AcmeBundle would be called
``AcmeExtension`` and the one for AcmeHelloBundle would be called
``AcmeHelloExtension``).
This is how the extension of an AcmeHelloBundle should look like::
- // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
+ // src/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -34,7 +96,7 @@ This is how the extension of an AcmeHelloBundle should look like::
class AcmeHelloExtension extends Extension
{
- public function load(array $configs, ContainerBuilder $container)
+ public function load(array $configs, ContainerBuilder $container): void
{
// ... you'll load the files here later
}
@@ -50,10 +112,11 @@ method to return the instance of the extension::
// ...
use Acme\HelloBundle\DependencyInjection\UnconventionalExtensionClass;
+ use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
class AcmeHelloBundle extends Bundle
{
- public function getContainerExtension()
+ public function getContainerExtension(): ?ExtensionInterface
{
return new UnconventionalExtensionClass();
}
@@ -69,7 +132,7 @@ class name to underscores (e.g. ``AcmeHelloExtension``'s DI alias is
``acme_hello``).
Using the ``load()`` Method
----------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the ``load()`` method, all services and parameters related to this extension
will be loaded. This method doesn't get the actual container instance, but a
@@ -83,17 +146,17 @@ but it is more common if you put these definitions in a configuration file
(using the YAML, XML or PHP format).
For instance, assume you have a file called ``services.xml`` in the
-``Resources/config/`` directory of your bundle, your ``load()`` method looks like::
+``config/`` directory of your bundle, your ``load()`` method looks like::
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
// ...
- public function load(array $configs, ContainerBuilder $container)
+ public function load(array $configs, ContainerBuilder $container): void
{
$loader = new XmlFileLoader(
$container,
- new FileLocator(__DIR__.'/../Resources/config')
+ new FileLocator(__DIR__.'/../../config')
);
$loader->load('services.xml');
}
@@ -115,15 +178,15 @@ they are compiled when generating the application cache to improve the overall
performance. Define the list of annotated classes to compile in the
``addAnnotatedClassesToCompile()`` method::
- public function load(array $configs, ContainerBuilder $container)
+ public function load(array $configs, ContainerBuilder $container): void
{
// ...
$this->addAnnotatedClassesToCompile([
// you can define the fully qualified class names...
- 'App\\Controller\\DefaultController',
+ 'Acme\\BlogBundle\\Controller\\AuthorController',
// ... but glob patterns are also supported:
- '**Bundle\\Controller\\',
+ 'Acme\\BlogBundle\\Form\\**',
// ...
]);
@@ -138,7 +201,7 @@ Patterns are transformed into the actual class namespaces using the classmap
generated by Composer. Therefore, before using these patterns, you must generate
the full classmap executing the ``dump-autoload`` command of Composer.
-.. caution::
+.. warning::
This technique can't be used when the classes to compile use the ``__DIR__``
or ``__FILE__`` constants, because their values will change when loading
diff --git a/bundles/override.rst b/bundles/override.rst
index 1e4926a1c76..f25bd785373 100644
--- a/bundles/override.rst
+++ b/bundles/override.rst
@@ -12,14 +12,14 @@ Templates
Third-party bundle templates can be overridden in the
``/templates/bundles//`` directory. The new templates
-must use the same name and path (relative to ``/Resources/views/``) as
+must use the same name and path (relative to ``/templates/``) as
the original templates.
-For example, to override the ``Resources/views/Registration/confirmed.html.twig``
-template from the FOSUserBundle, create this template:
-``/templates/bundles/FOSUserBundle/Registration/confirmed.html.twig``
+For example, to override the ``templates/registration/confirmed.html.twig``
+template from the AcmeUserBundle, create this template:
+``/templates/bundles/AcmeUserBundle/registration/confirmed.html.twig``
-.. caution::
+.. warning::
If you add a template in a new location, you *may* need to clear your
cache (``php bin/console cache:clear``), even if you are in debug mode.
@@ -32,9 +32,9 @@ extend from the original template, not from the overridden one:
.. code-block:: twig
- {# templates/bundles/FOSUserBundle/Registration/confirmed.html.twig #}
+ {# templates/bundles/AcmeUserBundle/registration/confirmed.html.twig #}
{# the special '!' prefix avoids errors when extending from an overridden template #}
- {% extends "@!FOSUser/Registration/confirmed.html.twig" %}
+ {% extends "@!AcmeUser/registration/confirmed.html.twig" %}
{% block some_block %}
...
@@ -162,7 +162,7 @@ For this reason, you can override any bundle translation file from the main
``translations/`` directory, as long as the new file uses the same domain.
For example, to override the translations defined in the
-``Resources/translations/FOSUserBundle.es.yml`` file of the FOSUserBundle,
-create a ``/translations/FOSUserBundle.es.yml`` file.
+``translations/AcmeUserBundle.es.yaml`` file of the AcmeUserBundle,
+create a ``/translations/AcmeUserBundle.es.yaml`` file.
.. _`the Doctrine documentation`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/inheritance-mapping.html#overrides
diff --git a/bundles/prepend_extension.rst b/bundles/prepend_extension.rst
index 35c277ec0e6..e4099d9f81a 100644
--- a/bundles/prepend_extension.rst
+++ b/bundles/prepend_extension.rst
@@ -31,7 +31,7 @@ To give an Extension the power to do this, it needs to implement
{
// ...
- public function prepend(ContainerBuilder $container)
+ public function prepend(ContainerBuilder $container): void
{
// ...
}
@@ -52,7 +52,7 @@ a configuration setting in multiple bundles as well as disable a flag in multipl
in case a specific other bundle is not registered::
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
- public function prepend(ContainerBuilder $container)
+ public function prepend(ContainerBuilder $container): void
{
// get all bundles
$bundles = $container->getParameter('kernel.bundles');
@@ -61,18 +61,16 @@ in case a specific other bundle is not registered::
// disable AcmeGoodbyeBundle in bundles
$config = ['use_acme_goodbye' => false];
foreach ($container->getExtensions() as $name => $extension) {
- switch ($name) {
- case 'acme_something':
- case 'acme_other':
- // set use_acme_goodbye to false in the config of
- // acme_something and acme_other
- //
- // note that if the user manually configured
- // use_acme_goodbye to true in config/services.yaml
- // then the setting would in the end be true and not false
- $container->prependExtensionConfig($name, $config);
- break;
- }
+ match ($name) {
+ // set use_acme_goodbye to false in the config of
+ // acme_something and acme_other
+ //
+ // note that if the user manually configured
+ // use_acme_goodbye to true in config/services.yaml
+ // then the setting would in the end be true and not false
+ 'acme_something', 'acme_other' => $container->prependExtensionConfig($name, $config),
+ default => null
+ };
}
}
@@ -141,7 +139,7 @@ registered and the ``entity_manager_name`` setting for ``acme_hello`` is set to
// config/packages/acme_something.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
- return static function (ContainerConfigurator $container) {
+ return static function (ContainerConfigurator $container): void {
$container->extension('acme_something', [
// ...
'use_acme_goodbye' => false,
@@ -153,6 +151,70 @@ registered and the ``entity_manager_name`` setting for ``acme_hello`` is set to
]);
};
+Prepending Extension in the Bundle Class
+----------------------------------------
+
+You can also prepend extension configuration directly in your
+Bundle class if you extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
+class and define the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::prependExtension`
+method::
+
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
+ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+ use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
+
+ class FooBundle extends AbstractBundle
+ {
+ public function prependExtension(ContainerConfigurator $containerConfigurator, ContainerBuilder $containerBuilder): void
+ {
+ // prepend
+ $containerBuilder->prependExtensionConfig('framework', [
+ 'cache' => ['prefix_seed' => 'foo/bar'],
+ ]);
+
+ // prepend config from a file
+ $containerConfigurator->import('../config/packages/cache.php');
+ }
+ }
+
+.. note::
+
+ The ``prependExtension()`` method, like ``prepend()``, is called only at compile time.
+
+.. versionadded:: 7.1
+
+ Starting from Symfony 7.1, calling the :method:`Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator::import`
+ method inside ``prependExtension()`` will prepend the given configuration.
+ In previous Symfony versions, this method appended the configuration.
+
+Alternatively, you can use the ``prepend`` parameter of the
+:method:`Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator::extension`
+method::
+
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
+ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+ use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
+
+ class FooBundle extends AbstractBundle
+ {
+ public function prependExtension(ContainerConfigurator $containerConfigurator, ContainerBuilder $containerBuilder): void
+ {
+ // ...
+
+ $containerConfigurator->extension('framework', [
+ 'cache' => ['prefix_seed' => 'foo/bar'],
+ ], prepend: true);
+
+ // ...
+ }
+ }
+
+.. versionadded:: 7.1
+
+ The ``prepend`` parameter of the
+ :method:`Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator::extension`
+ method was added in Symfony 7.1.
+
More than one Bundle using PrependExtensionInterface
----------------------------------------------------
diff --git a/cache.rst b/cache.rst
index c073a98387f..83bb5b4cedc 100644
--- a/cache.rst
+++ b/cache.rst
@@ -10,7 +10,7 @@ The following example shows a typical usage of the cache::
use Symfony\Contracts\Cache\ItemInterface;
// The callable will only be executed on a cache miss.
- $value = $pool->get('my_cache_key', function (ItemInterface $item) {
+ $value = $pool->get('my_cache_key', function (ItemInterface $item): string {
$item->expiresAfter(3600);
// ... do some HTTP request or heavy computations
@@ -24,14 +24,9 @@ The following example shows a typical usage of the cache::
// ... and to remove the cache key
$pool->delete('my_cache_key');
-Symfony supports Cache Contracts, PSR-6/16 and Doctrine Cache interfaces.
+Symfony supports Cache Contracts and PSR-6/16 interfaces.
You can read more about these at the :doc:`component documentation `.
-.. deprecated:: 5.4
-
- Support for Doctrine Cache was deprecated in Symfony 5.4
- and it will be removed in Symfony 6.0.
-
.. _cache-configuration-with-frameworkbundle:
Configuring Cache with FrameworkBundle
@@ -92,7 +87,7 @@ adapter (template) they use by using the ``app`` and ``system`` key like:
// config/packages/cache.php
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework) {
+ return static function (FrameworkConfig $framework): void {
$framework->cache()
->app('cache.adapter.filesystem')
->system('cache.adapter.system')
@@ -108,7 +103,6 @@ The Cache component comes with a series of adapters pre-configured:
* :doc:`cache.adapter.apcu `
* :doc:`cache.adapter.array `
-* :doc:`cache.adapter.doctrine ` (deprecated)
* :doc:`cache.adapter.doctrine_dbal `
* :doc:`cache.adapter.filesystem `
* :doc:`cache.adapter.memcached `
@@ -117,10 +111,6 @@ The Cache component comes with a series of adapters pre-configured:
* :doc:`cache.adapter.redis `
* :ref:`cache.adapter.redis_tag_aware ` (Redis adapter optimized to work with tags)
-.. versionadded:: 5.2
-
- ``cache.adapter.redis_tag_aware`` has been introduced in Symfony 5.2.
-
.. note::
There's also a special ``cache.adapter.system`` adapter. It's recommended to
@@ -143,12 +133,7 @@ Some of these adapters could be configured via shortcuts.
default_psr6_provider: 'app.my_psr6_service'
default_redis_provider: 'redis://localhost'
default_memcached_provider: 'memcached://localhost'
- default_pdo_provider: 'app.my_pdo_service'
-
- services:
- app.my_pdo_service:
- class: \PDO
- arguments: ['pgsql:host=localhost']
+ default_pdo_provider: 'pgsql:host=localhost'
.. code-block:: xml
@@ -169,24 +154,17 @@ Some of these adapters could be configured via shortcuts.
default-psr6-provider="app.my_psr6_service"
default-redis-provider="redis://localhost"
default-memcached-provider="memcached://localhost"
- default-pdo-provider="app.my_pdo_service"
+ default-pdo-provider="pgsql:host=localhost"
/>
-
-
-
- pgsql:host=localhost
-
-
.. code-block:: php
// config/packages/cache.php
- use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework, ContainerConfigurator $container) {
+ return static function (FrameworkConfig $framework): void {
$framework->cache()
// Only used with cache.adapter.filesystem
->directory('%kernel.cache_dir%/pools')
@@ -195,19 +173,13 @@ Some of these adapters could be configured via shortcuts.
->defaultPsr6Provider('app.my_psr6_service')
->defaultRedisProvider('redis://localhost')
->defaultMemcachedProvider('memcached://localhost')
- ->defaultPdoProvider('app.my_pdo_service')
- ;
-
- $container->services()
- ->set('app.my_pdo_service', \PDO::class)
- ->args(['pgsql:host=localhost'])
+ ->defaultPdoProvider('pgsql:host=localhost')
;
};
-.. deprecated:: 5.4
+.. versionadded:: 7.1
- The ``default_doctrine_provider`` option was deprecated in Symfony 5.4 and
- it will be removed in Symfony 6.0.
+ Using a DSN as the provider for the PDO adapter was introduced in Symfony 7.1.
.. _cache-create-pools:
@@ -295,7 +267,7 @@ You can also create more customized pools:
// config/packages/cache.php
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework) {
+ return static function (FrameworkConfig $framework): void {
$cache = $framework->cache();
$cache->defaultMemcachedProvider('memcached://localhost');
@@ -338,15 +310,16 @@ with either :class:`Symfony\\Contracts\\Cache\\CacheInterface` or
``Psr\Cache\CacheItemPoolInterface``::
use Symfony\Contracts\Cache\CacheInterface;
+ // ...
// from a controller method
- public function listProducts(CacheInterface $customThingCache)
+ public function listProducts(CacheInterface $customThingCache): Response
{
// ...
}
// in a service
- public function __construct(CacheInterface $customThingCache)
+ public function __construct(private CacheInterface $customThingCache)
{
// ...
}
@@ -394,7 +367,7 @@ with either :class:`Symfony\\Contracts\\Cache\\CacheInterface` or
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
- return function(ContainerConfigurator $container) {
+ return function(ContainerConfigurator $container): void {
$container->services()
// ...
@@ -475,7 +448,7 @@ and use that when configuring the pool.
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Config\FrameworkConfig;
- return static function (ContainerBuilder $container, FrameworkConfig $framework) {
+ return static function (ContainerBuilder $container, FrameworkConfig $framework): void {
$framework->cache()
->pool('cache.my_redis')
->adapters(['cache.adapter.redis'])
@@ -554,7 +527,7 @@ Symfony stores the item automatically in all the missing pools.
// config/packages/cache.php
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework) {
+ return static function (FrameworkConfig $framework): void {
$framework->cache()
->pool('my_cache_pool')
->defaultLifetime(31536000) // One year
@@ -579,23 +552,21 @@ the same tag could be invalidated with one function call::
class SomeClass
{
- private $myCachePool;
-
// using autowiring to inject the cache pool
- public function __construct(TagAwareCacheInterface $myCachePool)
- {
- $this->myCachePool = $myCachePool;
+ public function __construct(
+ private TagAwareCacheInterface $myCachePool,
+ ) {
}
- public function someMethod()
+ public function someMethod(): void
{
- $value0 = $this->myCachePool->get('item_0', function (ItemInterface $item) {
+ $value0 = $this->myCachePool->get('item_0', function (ItemInterface $item): string {
$item->tag(['foo', 'bar']);
return 'debug';
});
- $value1 = $this->myCachePool->get('item_1', function (ItemInterface $item) {
+ $value1 = $this->myCachePool->get('item_1', function (ItemInterface $item): string {
$item->tag('foo');
return 'debug';
@@ -619,6 +590,7 @@ to enable this feature. This could be added by using the following configuration
pools:
my_cache_pool:
adapter: cache.adapter.redis_tag_aware
+ tags: true
.. code-block:: xml
@@ -635,7 +607,7 @@ to enable this feature. This could be added by using the following configuration
@@ -647,11 +619,11 @@ to enable this feature. This could be added by using the following configuration
// config/packages/cache.php
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework) {
+ return static function (FrameworkConfig $framework): void {
$framework->cache()
->pool('my_cache_pool')
->tags(true)
- ->adapters(['cache.adapter.redis'])
+ ->adapters(['cache.adapter.redis_tag_aware'])
;
};
@@ -701,7 +673,7 @@ achieved by specifying the adapter.
// config/packages/cache.php
use Symfony\Config\FrameworkConfig;
- return static function (FrameworkConfig $framework) {
+ return static function (FrameworkConfig $framework): void {
$framework->cache()
->pool('my_cache_pool')
->tags('tag_pool')
@@ -753,19 +725,42 @@ Clear all custom pools:
$ php bin/console cache:pool:clear cache.app_clearer
+Clear all cache pools:
+
+.. code-block:: terminal
+
+ $ php bin/console cache:pool:clear --all
+
+Clear all cache pools except some:
+
+.. code-block:: terminal
+
+ $ php bin/console cache:pool:clear --all --exclude=my_cache_pool --exclude=another_cache_pool
+
Clear all caches everywhere:
.. code-block:: terminal
$ php bin/console cache:pool:clear cache.global_clearer
-Encrypting the Cache
---------------------
+Clear cache by tag(s):
+
+.. code-block:: terminal
+
+ # invalidate tag1 from all taggable pools
+ $ php bin/console cache:pool:invalidate-tags tag1
+
+ # invalidate tag1 & tag2 from all taggable pools
+ $ php bin/console cache:pool:invalidate-tags tag1 tag2
-.. versionadded:: 5.1
+ # invalidate tag1 & tag2 from cache.app pool
+ $ php bin/console cache:pool:invalidate-tags tag1 tag2 --pool=cache.app
- The :class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller`
- class was introduced in Symfony 5.1.
+ # invalidate tag1 & tag2 from cache1 & cache2 pools
+ $ php bin/console cache:pool:invalidate-tags tag1 tag2 -p cache1 -p cache2
+
+Encrypting the Cache
+--------------------
To encrypt the cache using ``libsodium``, you can use the
:class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller`.
@@ -835,7 +830,7 @@ Then, register the ``SodiumMarshaller`` service using this key:
//->addArgument(['env(base64:CACHE_DECRYPTION_KEY)', 'env(base64:OLD_CACHE_DECRYPTION_KEY)'])
->addArgument(new Reference('.inner'));
-.. caution::
+.. danger::
This will encrypt the values of the cache items, but not the cache keys. Be
careful not to leak sensitive data in the keys.
@@ -848,10 +843,6 @@ cache items encrypted with the old key have expired, you can completely remove
Computing Cache Values Asynchronously
-------------------------------------
-.. versionadded:: 5.2
-
- The feature to compute cache values asynchronously was introduced in Symfony 5.2.
-
The Cache component uses the `probabilistic early expiration`_ algorithm to
protect against the :ref:`cache stampede ` problem.
This means that some cache items are elected for early-expiration while they are
@@ -894,15 +885,13 @@ In the following example, the value is requested from a controller::
use App\Cache\CacheComputation;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
- use Symfony\Component\Routing\Annotation\Route;
+ use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
class CacheController extends AbstractController
{
- /**
- * @Route("/cache", name="cache")
- */
+ #[Route('/cache', name: 'cache')]
public function index(CacheInterface $asyncCache): Response
{
// pass to the cache the service method that refreshes the item
diff --git a/components/asset.rst b/components/asset.rst
index e515b41395c..d6d3f485859 100644
--- a/components/asset.rst
+++ b/components/asset.rst
@@ -179,25 +179,17 @@ listed in the manifest::
echo $package->getUrl('not-found.css');
// error:
-.. versionadded:: 5.4
-
- The ``$strictMode`` option was introduced in Symfony 5.4.
-
If your JSON file is not on your local filesystem but is accessible over HTTP,
-use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\RemoteJsonManifestVersionStrategy`
+use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\JsonManifestVersionStrategy`
with the :doc:`HttpClient component `::
use Symfony\Component\Asset\Package;
- use Symfony\Component\Asset\VersionStrategy\RemoteJsonManifestVersionStrategy;
+ use Symfony\Component\Asset\VersionStrategy\JsonManifestVersionStrategy;
use Symfony\Component\HttpClient\HttpClient;
$httpClient = HttpClient::create();
$manifestUrl = 'https://cdn.example.com/rev-manifest.json';
- $package = new Package(new RemoteJsonManifestVersionStrategy($manifestUrl, $httpClient));
-
-.. versionadded:: 5.1
-
- The ``RemoteJsonManifestVersionStrategy`` was introduced in Symfony 5.1.
+ $package = new Package(new JsonManifestVersionStrategy($manifestUrl, $httpClient));
Custom Version Strategies
.........................
diff --git a/components/browser_kit.rst b/components/browser_kit.rst
index 12c2a63a7c7..8cf0772298c 100644
--- a/components/browser_kit.rst
+++ b/components/browser_kit.rst
@@ -4,13 +4,6 @@ The BrowserKit Component
The BrowserKit component simulates the behavior of a web browser, allowing
you to make requests, click on links and submit forms programmatically.
-.. note::
-
- In Symfony versions prior to 4.3, the BrowserKit component could only make
- internal requests to your application. Starting from Symfony 4.3, this
- component can also :ref:`make HTTP requests to any public site `
- when using it in combination with the :doc:`HttpClient component `.
-
Installation
------------
@@ -45,7 +38,7 @@ This method accepts a request and should return a response::
class Client extends AbstractBrowser
{
- protected function doRequest($request)
+ protected function doRequest($request): Response
{
// ... convert request into a response
@@ -86,10 +79,6 @@ convert the request parameters into a JSON string and set the needed HTTP header
// this encodes parameters as JSON and sets the required CONTENT_TYPE and HTTP_ACCEPT headers
$crawler = $client->jsonRequest('GET', '/', ['some_parameter' => 'some_value']);
-.. versionadded:: 5.3
-
- The ``jsonRequest()`` method was introduced in Symfony 5.3.
-
The :method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::xmlHttpRequest` method,
which defines the same arguments as the ``request()`` method, is a shortcut to
make AJAX requests::
@@ -123,6 +112,24 @@ provides access to the link properties (e.g. ``$link->getMethod()``,
$link = $crawler->selectLink('Go elsewhere...')->link();
$client->click($link);
+The :method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::click` and
+:method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::clickLink` methods
+can take an optional ``serverParameters`` argument. This
+parameter allows to send additional information like headers when clicking
+on a link::
+
+ use Acme\Client;
+
+ $client = new Client();
+ $client->request('GET', '/product/123');
+
+ // works both with `click()`...
+ $link = $crawler->selectLink('Go elsewhere...')->link();
+ $client->click($link, ['X-Custom-Header' => 'Some data']);
+
+ // ... and `clickLink()`
+ $crawler = $client->clickLink('Go elsewhere...', ['X-Custom-Header' => 'Some data']);
+
Submitting Forms
~~~~~~~~~~~~~~~~
@@ -136,7 +143,7 @@ field values, etc.) before submitting it::
$crawler = $client->request('GET', 'https://github.com/login');
// find the form with the 'Log in' button and submit it
- // 'Log in' can be the text content, id, value or name of a