From 01ca38dac8964f2e06eb18428854e9f3561a5a17 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Wed, 22 May 2024 21:44:11 +0200 Subject: [PATCH 001/427] [Stopwatch] Add ROOT constant to make it easier to reference --- performance.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/performance.rst b/performance.rst index ca34e95ee37..ffeff6608c1 100644 --- a/performance.rst +++ b/performance.rst @@ -382,10 +382,16 @@ All events that don't belong to any named section are added to the special secti called ``__root__``. This way you can get all stopwatch events, even if you don't know their names, as follows:: - foreach($this->stopwatch->getSectionEvents('__root__') as $event) { + use Symfony\Component\Stopwatch\Stopwatch; + + foreach($this->stopwatch->getSectionEvents(Stopwatch::ROOT) as $event) { echo (string) $event; } +.. versionadded:: 7.2 + + The ``Stopwatch::ROOT`` constant as a shortcut for ``__root__`` was introduced in Symfony 7.2. + Learn more ---------- From 6331dc5d6b6b52425220e5dec44f75be657ea2d7 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Wed, 22 May 2024 21:49:28 +0200 Subject: [PATCH 002/427] [Stopwatch] Add getLastPeriod method to StopwatchEvent --- performance.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/performance.rst b/performance.rst index ca34e95ee37..634ad8572ea 100644 --- a/performance.rst +++ b/performance.rst @@ -362,6 +362,13 @@ method does, which stops an event and then restarts it immediately:: // Lap information is stored as "periods" within the event: // $event->getPeriods(); + // Gets the last event period: + // $event->getLastPeriod(); + +.. versionadded:: 7.2 + + The ``getLastPeriod`` method was introduced in Symfony 7.2. + Profiling Sections .................. From 5bcaf58a7608ad467dffc3be35721d9e3286b4c1 Mon Sep 17 00:00:00 2001 From: Tim <5579551+Timherlaud@users.noreply.github.com> Date: Wed, 22 May 2024 16:31:48 +0200 Subject: [PATCH 003/427] 19909 [FrameworkBundle] Add support for setting headers --- templates.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/templates.rst b/templates.rst index b6ae333cee1..d1c714d4225 100644 --- a/templates.rst +++ b/templates.rst @@ -705,6 +705,11 @@ provided by Symfony: site_name: 'ACME' theme: 'dark' + # optionally you can define HTTP headers to add to the response + headers: + Content-Type: 'text/html' + foo: 'bar' + .. code-block:: xml @@ -734,6 +739,11 @@ provided by Symfony: ACME dark + + + + text/html + @@ -764,11 +774,20 @@ provided by Symfony: 'context' => [ 'site_name' => 'ACME', 'theme' => 'dark', + ], + + // optionally you can define HTTP headers to add to the response + 'headers' => [ + 'Content-Type' => 'text/html', ] ]) ; }; +.. versionadded:: 7.2 + + The ``headers`` option was introduced in Symfony 7.2. + Checking if a Template Exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From a9a6f77c095d34d3bb2c6b7e65fd26fb7f2e371d Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Fri, 24 May 2024 15:50:07 +0200 Subject: [PATCH 004/427] Update examples to symfony 7.2 --- contributing/code/pull_requests.rst | 2 +- contributing/code/tests.rst | 2 +- setup.rst | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contributing/code/pull_requests.rst b/contributing/code/pull_requests.rst index 7c9ab2579a5..28a6dbc8169 100644 --- a/contributing/code/pull_requests.rst +++ b/contributing/code/pull_requests.rst @@ -132,7 +132,7 @@ work: branch (you can find them on the `Symfony releases page`_). E.g. if you found a bug introduced in ``v5.1.10``, you need to work on ``5.4``. -* ``7.1``, if you are adding a new feature. +* ``7.2``, if you are adding a new feature. The only exception is when a new :doc:`major Symfony version ` (5.0, 6.0, etc.) comes out every two years. Because of the diff --git a/contributing/code/tests.rst b/contributing/code/tests.rst index 08f6bc5df12..060e3eda02b 100644 --- a/contributing/code/tests.rst +++ b/contributing/code/tests.rst @@ -32,7 +32,7 @@ tests, such as Doctrine, Twig and Monolog. To do so, .. code-block:: terminal - $ COMPOSER_ROOT_VERSION=7.1.x-dev composer update + $ COMPOSER_ROOT_VERSION=7.2.x-dev composer update .. _running: diff --git a/setup.rst b/setup.rst index 90a89e78e8a..5cf3d2f90ab 100644 --- a/setup.rst +++ b/setup.rst @@ -48,10 +48,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_directory --version="7.1.*" --webapp + $ symfony new my_project_directory --version="7.2.*" --webapp # run this if you are building a microservice, console application or API - $ symfony new my_project_directory --version="7.1.*" + $ symfony new my_project_directory --version="7.2.*" The only difference between these two commands is the number of packages installed by default. The ``--webapp`` option installs extra packages to give @@ -63,12 +63,12 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/skeleton:"7.1.*" my_project_directory + $ composer create-project symfony/skeleton:"7.2.*" my_project_directory $ cd my_project_directory $ composer require webapp # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"7.1.*" my_project_directory + $ composer create-project symfony/skeleton:"7.2.*" my_project_directory No matter which command you run to create the Symfony application. All of them will create a new ``my_project_directory/`` directory, download some dependencies From 92d1b5a8728b7c83930e497a7c86e1f0b6abcb1f Mon Sep 17 00:00:00 2001 From: Yannick Date: Tue, 21 May 2024 23:52:53 +0200 Subject: [PATCH 005/427] [Validator] feat : add password strength estimator related documentation --- reference/constraints/PasswordStrength.rst | 9 ++++ .../get_or_override_estimate_strength.rst | 48 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 validation/passwordStrength/get_or_override_estimate_strength.rst diff --git a/reference/constraints/PasswordStrength.rst b/reference/constraints/PasswordStrength.rst index 989ffddd100..a44fd70fd4e 100644 --- a/reference/constraints/PasswordStrength.rst +++ b/reference/constraints/PasswordStrength.rst @@ -128,3 +128,12 @@ The default message supplied when the password does not reach the minimum requir ])] protected $rawPassword; } + +Learn more +---------- + +.. toctree:: + :maxdepth: 1 + :glob: + + /validation/passwordStrength/* diff --git a/validation/passwordStrength/get_or_override_estimate_strength.rst b/validation/passwordStrength/get_or_override_estimate_strength.rst new file mode 100644 index 00000000000..9cd24c1b818 --- /dev/null +++ b/validation/passwordStrength/get_or_override_estimate_strength.rst @@ -0,0 +1,48 @@ +How to Get or Override the Default Password Strength Estimation Algorithm +========================================================================= + +Within the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` a `dedicated function`_ is used to estimate the strength of the given password. This function can be retrieved directly from the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` class and can also be overridden. + +Get the default Password strength +--------------------------------- + +In case of need to retrieve the actual strength of a password (e.g. compute the score and display it when the user has defined a password), the ``estimateStrength`` `dedicated function`_ of the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` is a public static function, therefore this function can be retrieved directly from the `PasswordStrengthValidator` class.:: + + use Symfony\Component\Validator\Constraints\PasswordStrengthValidator; + + $passwordEstimatedStrength = PasswordStrengthValidator::estimateStrength($password); + + +Override the default Password strength estimation algorithm +----------------------------------------------------------- + +If you need to override the default password strength estimation algorithm, you can pass a ``Closure`` to the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` constructor. This can be done using the :doc:`/service_container/service_closures`. + +First, create a custom password strength estimation algorithm within a dedicated callable class.:: + + namespace App\Validator; + + class CustomPasswordStrengthEstimator + { + /** + * @param string $password + * + * @return PasswordStrength::STRENGTH_* + */ + public function __invoke(string $password): int + { + // Your custom password strength estimation algorithm + } + } + +Then, configure the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` service to use the custom password strength estimation algorithm.:: + + # config/services.yaml + services: + custom_password_strength_estimator: + class: App\Validator\CustomPasswordStrengthEstimator + + Symfony\Component\Validator\Constraints\PasswordStrengthValidator: + arguments: [!service_closure '@custom_password_strength_estimator'] + +.. _`dedicated function`: https://github.com/symfony/symfony/blob/85db734e06e8cb32365810958326d48084bf48ba/src/Symfony/Component/Validator/Constraints/PasswordStrengthValidator.php#L53-L90 From f6b69918adf973068635a9f39e1e4be5c1f4dc40 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 28 May 2024 10:43:26 +0200 Subject: [PATCH 006/427] Move the docs to the constraint doc --- reference/constraints/PasswordStrength.rst | 87 +++++++++++++++++-- .../get_or_override_estimate_strength.rst | 48 ---------- 2 files changed, 81 insertions(+), 54 deletions(-) delete mode 100644 validation/passwordStrength/get_or_override_estimate_strength.rst diff --git a/reference/constraints/PasswordStrength.rst b/reference/constraints/PasswordStrength.rst index a44fd70fd4e..671b5f495ef 100644 --- a/reference/constraints/PasswordStrength.rst +++ b/reference/constraints/PasswordStrength.rst @@ -129,11 +129,86 @@ The default message supplied when the password does not reach the minimum requir protected $rawPassword; } -Learn more ----------- +Customizing the Password Strength Estimation +-------------------------------------------- -.. toctree:: - :maxdepth: 1 - :glob: +.. versionadded:: 7.2 - /validation/passwordStrength/* + The feature to customize the password strength estimation was introduced in Symfony 7.2. + +By default, this constraint calculates the strength of a password based on its +length and the number of unique characters used. You can get the calculated +password strength (e.g. to display it in the user interface) using the following +static function:: + + use Symfony\Component\Validator\Constraints\PasswordStrengthValidator; + + $passwordEstimatedStrength = PasswordStrengthValidator::estimateStrength($password); + +If you need to override the default password strength estimation algorithm, you +can pass a ``Closure`` to the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` +constructor (e.g. using the :doc:`service closures `). + +First, create a custom password strength estimation algorithm within a dedicated +callable class:: + + namespace App\Validator; + + class CustomPasswordStrengthEstimator + { + /** + * @return PasswordStrength::STRENGTH_* + */ + public function __invoke(string $password): int + { + // Your custom password strength estimation algorithm + } + } + +Then, configure the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` +service to use your own estimator: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + custom_password_strength_estimator: + class: App\Validator\CustomPasswordStrengthEstimator + + Symfony\Component\Validator\Constraints\PasswordStrengthValidator: + arguments: [!service_closure '@custom_password_strength_estimator'] + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\Validator\Constraints\PasswordStrengthValidator; + + return function (ContainerConfigurator $container): void { + $services = $container->services(); + + $services->set('custom_password_strength_estimator', CustomPasswordStrengthEstimator::class); + + $services->set(PasswordStrengthValidator::class) + ->args([service_closure('custom_password_strength_estimator')]); + }; diff --git a/validation/passwordStrength/get_or_override_estimate_strength.rst b/validation/passwordStrength/get_or_override_estimate_strength.rst deleted file mode 100644 index 9cd24c1b818..00000000000 --- a/validation/passwordStrength/get_or_override_estimate_strength.rst +++ /dev/null @@ -1,48 +0,0 @@ -How to Get or Override the Default Password Strength Estimation Algorithm -========================================================================= - -Within the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` a `dedicated function`_ is used to estimate the strength of the given password. This function can be retrieved directly from the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` class and can also be overridden. - -Get the default Password strength ---------------------------------- - -In case of need to retrieve the actual strength of a password (e.g. compute the score and display it when the user has defined a password), the ``estimateStrength`` `dedicated function`_ of the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` is a public static function, therefore this function can be retrieved directly from the `PasswordStrengthValidator` class.:: - - use Symfony\Component\Validator\Constraints\PasswordStrengthValidator; - - $passwordEstimatedStrength = PasswordStrengthValidator::estimateStrength($password); - - -Override the default Password strength estimation algorithm ------------------------------------------------------------ - -If you need to override the default password strength estimation algorithm, you can pass a ``Closure`` to the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` constructor. This can be done using the :doc:`/service_container/service_closures`. - -First, create a custom password strength estimation algorithm within a dedicated callable class.:: - - namespace App\Validator; - - class CustomPasswordStrengthEstimator - { - /** - * @param string $password - * - * @return PasswordStrength::STRENGTH_* - */ - public function __invoke(string $password): int - { - // Your custom password strength estimation algorithm - } - } - -Then, configure the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator` service to use the custom password strength estimation algorithm.:: - - # config/services.yaml - services: - custom_password_strength_estimator: - class: App\Validator\CustomPasswordStrengthEstimator - - Symfony\Component\Validator\Constraints\PasswordStrengthValidator: - arguments: [!service_closure '@custom_password_strength_estimator'] - -.. _`dedicated function`: https://github.com/symfony/symfony/blob/85db734e06e8cb32365810958326d48084bf48ba/src/Symfony/Component/Validator/Constraints/PasswordStrengthValidator.php#L53-L90 From cd3690d3738ff210cd2144f97186c2acce20e38f Mon Sep 17 00:00:00 2001 From: A goazil Date: Tue, 30 Apr 2024 09:52:48 +0200 Subject: [PATCH 007/427] [Notifier] add Primotexto bridge chore: add versionadded directive --- notifier.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/notifier.rst b/notifier.rst index 04ca5a2d4a4..01dfaf17cc6 100644 --- a/notifier.rst +++ b/notifier.rst @@ -138,6 +138,9 @@ Service `Plivo`_ **Install**: ``composer require symfony/plivo-notifier`` \ **DSN**: ``plivo://AUTH_ID:AUTH_TOKEN@default?from=FROM`` \ **Webhook support**: No +`Primotexto`_ **Install**: ``composer require symfony/primotexto-notifier`` \ + **DSN**: ``primotexto://API_KEY@default?from=FROM`` \ + **Webhook support**: No `Redlink`_ **Install**: ``composer require symfony/redlink-notifier`` \ **DSN**: ``redlink://API_KEY:APP_KEY@default?from=SENDER_NAME&version=API_VERSION`` \ **Webhook support**: No @@ -203,6 +206,10 @@ Service **Webhook support**: No ================== ==================================================================================================================================== +.. versionadded:: 7.2 + + The ``Primotexto`` integration was introduced in Symfony 7.2. + .. tip:: Some third party transports, when using the API, support status callbacks @@ -1119,6 +1126,7 @@ is dispatched. Listeners receive a .. _`OvhCloud`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/OvhCloud/README.md .. _`PagerDuty`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/PagerDuty/README.md .. _`Plivo`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Plivo/README.md +.. _`Primotexto`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Primotexto/README.md .. _`Pushover`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Pushover/README.md .. _`Pushy`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Pushy/README.md .. _`Redlink`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Redlink/README.md From dc23e2e0399768c26c495ed8e2cf481843801d57 Mon Sep 17 00:00:00 2001 From: Maximilian Beckers Date: Tue, 4 Jun 2024 12:01:10 +0200 Subject: [PATCH 008/427] [Validator] BicValidator add strict mode to validate bics in strict mode --- reference/constraints/Bic.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index 69ce35248f3..a6a745e3a76 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -121,4 +121,24 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc +``mode`` +~~~~~~~~ + +**type**: ``string`` **default**: ``strict`` + +The mode in which the BIC is validated can be defined with this option. Valid values are: + +* ``strict`` uses the input BIC and validates it without modification. +* ``case-insensitive`` converts the input value to uppercase before validating the BIC. + +.. tip:: + + The possible values of this option are also defined as PHP constants of + :class:`Symfony\\Component\\Validator\\Constraints\\BIC` + (e.g. ``BIC::VALIDATION_MODE_CASE_INSENSITIVE``). + +.. versionadded:: 7.2 + + The ``mode`` option was introduced in Symfony 7.2. + .. _`Business Identifier Code (BIC)`: https://en.wikipedia.org/wiki/Business_Identifier_Code From 1484f9dc53b784ac79b1b5cb3f7fd000f07ac92c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 5 Jun 2024 11:40:33 +0200 Subject: [PATCH 009/427] Minor tweaks --- reference/constraints/Bic.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index a6a745e3a76..3f05e5eac25 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -126,10 +126,10 @@ Parameter Description **type**: ``string`` **default**: ``strict`` -The mode in which the BIC is validated can be defined with this option. Valid values are: +This option defines how the BIC is validated: -* ``strict`` uses the input BIC and validates it without modification. -* ``case-insensitive`` converts the input value to uppercase before validating the BIC. +* ``strict`` validates the given value without any modification; +* ``case-insensitive`` converts the given value to uppercase before validating it. .. tip:: From 0624d24867ba378c160c0c56fa3127490ca2b065 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 13 Jun 2024 16:48:16 +0200 Subject: [PATCH 010/427] [ExpressionLanguage] Document the null-coalesce operator changes --- reference/formats/expression_language.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/reference/formats/expression_language.rst b/reference/formats/expression_language.rst index c7ce82fb751..818870452a5 100644 --- a/reference/formats/expression_language.rst +++ b/reference/formats/expression_language.rst @@ -124,11 +124,10 @@ returns the right-hand side. Expressions can chain multiple coalescing operators * ``foo[3] ?? 'no'`` * ``foo.baz ?? foo['baz'] ?? 'no'`` -.. note:: +.. versionadded:: 7.2 - The main difference with the `null-coalescing operator in PHP`_ is that - ExpressionLanguage will throw an exception when trying to access a - non-existent variable. + Starting from Symfony 7.2, no exception is thrown when trying to access a + non-existent variable. This is the same behavior as the `null-coalescing operator in PHP`_. .. _component-expression-functions: From 00854911226a5f2ec7299e0e0345fcaacba110ac Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 13 Jun 2024 17:34:08 +0200 Subject: [PATCH 011/427] [Translation] Document `lint:translations` command --- translation.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index 891f00845cb..0fbd155cfd7 100644 --- a/translation.rst +++ b/translation.rst @@ -1343,7 +1343,7 @@ Symfony processes all the application translation files as part of the process that compiles the application code before executing it. If there's an error in any translation file, you'll see an error message explaining the problem. -If you prefer, you can also validate the contents of any YAML and XLIFF +If you prefer, you can also validate the syntax of any YAML and XLIFF translation file using the ``lint:yaml`` and ``lint:xliff`` commands: .. code-block:: terminal @@ -1384,6 +1384,22 @@ adapted to the format required by GitHub, but you can force that format too: $ php vendor/bin/yaml-lint translations/ +The ``lint:yaml`` and ``lint:xliff`` commands validate the YAML and XML syntax +of the translation files, but not their contents. Use the following command +to check that the translation contents are also correct: + + .. code-block:: terminal + + # checks the contents of all the translation catalogues in all locales + $ php bin/console lint:translations + + # checks the contents of the translation catalogues for Italian (it) and Japanese (ja) locales + $ php bin/console lint:translations --locales=it --locales=ja + +.. versionadded:: 7.2 + + The ``lint:translations`` command was introduced in Symfony 7.2. + Pseudo-localization translator ------------------------------ From 29bdb1612d2a3d7387cad50228cbe226623ea4ec Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 17 Jun 2024 10:36:30 +0200 Subject: [PATCH 012/427] Update the version constraints --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index 5cf3d2f90ab..d8196e71b7b 100644 --- a/setup.rst +++ b/setup.rst @@ -48,10 +48,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_directory --version="7.2.*" --webapp + $ symfony new my_project_directory --version="7.2.x-dev" --webapp # run this if you are building a microservice, console application or API - $ symfony new my_project_directory --version="7.2.*" + $ symfony new my_project_directory --version="7.2.x-dev" The only difference between these two commands is the number of packages installed by default. The ``--webapp`` option installs extra packages to give @@ -63,12 +63,12 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/skeleton:"7.2.*" my_project_directory + $ composer create-project symfony/skeleton:"7.2.x-dev" my_project_directory $ cd my_project_directory $ composer require webapp # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"7.2.*" my_project_directory + $ composer create-project symfony/skeleton:"7.2.x-dev" my_project_directory No matter which command you run to create the Symfony application. All of them will create a new ``my_project_directory/`` directory, download some dependencies From 15dcd7e221ae7caca0cec61f56b2adab1cdd9b55 Mon Sep 17 00:00:00 2001 From: Patrick Landolt Date: Sun, 9 Jun 2024 18:19:11 +0200 Subject: [PATCH 013/427] [Mailer] Add mailomat mailer --- mailer.rst | 10 ++++++++++ webhook.rst | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/mailer.rst b/mailer.rst index d7bccb11d86..502644a741a 100644 --- a/mailer.rst +++ b/mailer.rst @@ -106,6 +106,7 @@ Service Install with Webhook su `Infobip`_ ``composer require symfony/infobip-mailer`` `Mailgun`_ ``composer require symfony/mailgun-mailer`` yes `Mailjet`_ ``composer require symfony/mailjet-mailer`` yes +`Mailomat`_ ``composer require symfony/mailomat-mailer`` yes `MailPace`_ ``composer require symfony/mail-pace-mailer`` `MailerSend`_ ``composer require symfony/mailer-send-mailer`` `Mandrill`_ ``composer require symfony/mailchimp-mailer`` @@ -119,6 +120,10 @@ Service Install with Webhook su The Azure and Resend integrations were introduced in Symfony 7.1. +.. versionadded:: 7.2 + + The Mailomat integration was introduced in Symfony 7.2. + .. note:: As a convenience, Symfony also provides support for Gmail (``composer @@ -201,6 +206,10 @@ party provider: | | - HTTP n/a | | | - API ``mailjet+api://ACCESS_KEY:SECRET_KEY@default`` | +------------------------+---------------------------------------------------------+ +| `Mailomat`_ | - SMTP ``mailomat+smtp://USERNAME:PASSWORD@default`` | +| | - HTTP n/a | +| | - API ``mailomat+api://KEY@default`` | ++------------------------+---------------------------------------------------------+ | `MailPace`_ | - SMTP ``mailpace+api://API_TOKEN@default`` | | | - HTTP n/a | | | - API ``mailpace+api://API_TOKEN@default`` | @@ -1979,6 +1988,7 @@ the :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait`:: .. _`Mailgun`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md .. _`Mailjet`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailjet/README.md .. _`Markdown syntax`: https://commonmark.org/ +.. _`Mailomat`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailomat/README.md .. _`MailPace`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/MailPace/README.md .. _`OpenSSL PHP extension`: https://www.php.net/manual/en/book.openssl.php .. _`PEM encoded`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail diff --git a/webhook.rst b/webhook.rst index 38f3a4b1004..52633ae83e5 100644 --- a/webhook.rst +++ b/webhook.rst @@ -27,6 +27,7 @@ Brevo ``mailer.webhook.request_parser.brevo`` MailerSend ``mailer.webhook.request_parser.mailersend`` Mailgun ``mailer.webhook.request_parser.mailgun`` Mailjet ``mailer.webhook.request_parser.mailjet`` +Mailomat ``mailer.webhook.request_parser.mailomat`` Postmark ``mailer.webhook.request_parser.postmark`` Resend ``mailer.webhook.request_parser.resend`` Sendgrid ``mailer.webhook.request_parser.sendgrid`` @@ -36,6 +37,10 @@ Sendgrid ``mailer.webhook.request_parser.sendgrid`` The support for ``Resend`` and ``MailerSend`` were introduced in Symfony 7.1. +.. versionadded:: 7.2 + + The ``Mailomat`` integration was introduced in Symfony 7.2. + .. note:: Install the third-party mailer provider you want to use as described in the From 7cdfb52930f9097fef14ed56a3c8d6624461cb52 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 19 Jun 2024 09:20:04 +0200 Subject: [PATCH 014/427] [FrameworkBundle] Simplified the MicroKernelTrait setup --- configuration/micro_kernel_trait.rst | 107 +++++++++++++++------------ 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index b67335514a1..23aa677cf20 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -16,9 +16,7 @@ via Composer: .. code-block:: terminal - $ composer require symfony/config symfony/http-kernel \ - symfony/http-foundation symfony/routing \ - symfony/dependency-injection symfony/framework-bundle + $ composer symfony/framework-bundle symfony/runtime Next, create an ``index.php`` file that defines the kernel class and runs it: @@ -34,19 +32,12 @@ Next, create an ``index.php`` file that defines the kernel class and runs it: use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\Attribute\Route; - require __DIR__.'/vendor/autoload.php'; + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; class Kernel extends BaseKernel { use MicroKernelTrait; - public function registerBundles(): array - { - return [ - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - ]; - } - protected function configureContainer(ContainerConfigurator $container): void { // PHP equivalent of config/packages/framework.yaml @@ -64,11 +55,9 @@ Next, create an ``index.php`` file that defines the kernel class and runs it: } } - $kernel = new Kernel('dev', true); - $request = Request::createFromGlobals(); - $response = $kernel->handle($request); - $response->send(); - $kernel->terminate($request, $response); + return static function (array $context) { + return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); + } .. code-block:: php @@ -80,19 +69,12 @@ Next, create an ``index.php`` file that defines the kernel class and runs it: use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; - require __DIR__.'/vendor/autoload.php'; + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; class Kernel extends BaseKernel { use MicroKernelTrait; - public function registerBundles(): array - { - return [ - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - ]; - } - protected function configureContainer(ContainerConfigurator $container): void { // PHP equivalent of config/packages/framework.yaml @@ -114,17 +96,9 @@ Next, create an ``index.php`` file that defines the kernel class and runs it: } } - $kernel = new Kernel('dev', true); - $request = Request::createFromGlobals(); - $response = $kernel->handle($request); - $response->send(); - $kernel->terminate($request, $response); - -.. note:: - - In addition to the ``index.php`` file, you'll need to create a directory called - ``config/`` in your project (even if it's empty because you define the configuration - options inside the ``configureContainer()`` method). + return static function (array $context) { + return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); + } That's it! To test it, start the :doc:`Symfony Local Web Server `: @@ -135,6 +109,23 @@ That's it! To test it, start the :doc:`Symfony Local Web Server Then see the JSON response in your browser: http://localhost:8000/random/10 +.. tip:: + + If your kernel only defines a single controller, you can use an invokable method:: + + class Kernel extends BaseKernel + { + use MicroKernelTrait; + + // ... + + #[Route('/random/{limit}', name: 'random_number')] + public function __invoke(int $limit): JsonResponse + { + // ... + } + } + The Methods of a "Micro" Kernel ------------------------------- @@ -142,7 +133,26 @@ When you use the ``MicroKernelTrait``, your kernel needs to have exactly three m that define your bundles, your services and your routes: **registerBundles()** - This is the same ``registerBundles()`` that you see in a normal kernel. + This is the same ``registerBundles()`` that you see in a normal kernel. By + default, the micro kernel only registers the ``FrameworkBundle``. If you need + to register more bundles, override this method:: + + use Symfony\Bundle\FrameworkBundle\FrameworkBundle; + use Symfony\Bundle\TwigBundle\TwigBundle; + // ... + + class Kernel extends BaseKernel + { + use MicroKernelTrait; + + // ... + + public function registerBundles(): array + { + yield new FrameworkBundle(); + yield new TwigBundle(); + } + } **configureContainer(ContainerConfigurator $container)** This method builds and configures the container. In practice, you will use @@ -151,9 +161,13 @@ that define your bundles, your services and your routes: services directly in PHP or load external configuration files (shown below). **configureRoutes(RoutingConfigurator $routes)** - Your job in this method is to add routes to the application. The - ``RoutingConfigurator`` has methods that make adding routes in PHP more - fun. You can also load external routing files (shown below). + In this method, you can use the ``RoutingConfigurator`` object to define routes + in your application and associate them to the controllers defined in this very + same file. + + However, it's more convenient to define the controller routes using PHP attributes, + as shown above. That's why this method is commonly used only to load external + routing files (e.g. from bundles) as shown below. Adding Interfaces to "Micro" Kernel ----------------------------------- @@ -231,7 +245,10 @@ Now it looks like this:: namespace App; use App\DependencyInjection\AppExtension; + use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; + use Symfony\Bundle\TwigBundle\TwigBundle; + use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\HttpKernel\Kernel as BaseKernel; @@ -241,18 +258,14 @@ Now it looks like this:: { use MicroKernelTrait; - public function registerBundles(): array + public function registerBundles(): iterable { - $bundles = [ - new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new \Symfony\Bundle\TwigBundle\TwigBundle(), - ]; + yield FrameworkBundle(); + yield TwigBundle(); if ('dev' === $this->getEnvironment()) { - $bundles[] = new \Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); + yield WebProfilerBundle(); } - - return $bundles; } protected function build(ContainerBuilder $containerBuilder): void From d68d6abc1120c766b42498468a6667695ee16805 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 25 Jun 2024 09:43:08 +0200 Subject: [PATCH 015/427] [Validator] Add the format option to the Ulid constraint to allow accepting different ULID formats --- reference/constraints/Ulid.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst index ed7dfe7ed96..4ba5ec3a3f5 100644 --- a/reference/constraints/Ulid.rst +++ b/reference/constraints/Ulid.rst @@ -73,6 +73,20 @@ Basic Usage Options ------- +``format`` +~~~~~~~~~~ + +**type**: ``string`` **default**: ``Ulid::FORMAT_BASE_32`` + +The format of the ULID to validate. The following formats are available: + +* ``Ulid::FORMAT_BASE_32``: The ULID is encoded in base32 (default) +* ``Ulid::FORMAT_BASE_58``: The ULID is encoded in base58 + +.. versionadded:: 7.2 + + The ``format`` option was introduced in Symfony 7.2. + .. include:: /reference/constraints/_groups-option.rst.inc ``message`` From ea63cd7d932c1b77ee589938dda2d3e03c0a9aca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 25 Jun 2024 10:49:40 +0200 Subject: [PATCH 016/427] [Messenger] Document the --format option of messenger:stats command --- messenger.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/messenger.rst b/messenger.rst index 3dab2caac52..785cc022136 100644 --- a/messenger.rst +++ b/messenger.rst @@ -688,6 +688,14 @@ of some or all transports: # shows stats only for some transports $ php bin/console messenger:stats my_transport_name other_transport_name + # you can also output the stats in JSON format + $ php bin/console messenger:stats --format=json + $ php bin/console messenger:stats my_transport_name other_transport_name --format=json + +.. versionadded:: 7.2 + + The ``format`` option was introduced in Symfony 7.2. + .. note:: In order for this command to work, the configured transport's receiver must implement From 688db2816b0892982b0e2b2ab02fa9cf6a7f0573 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 14 Jun 2024 16:56:00 +0200 Subject: [PATCH 017/427] [Validator] Add the Yaml constraint --- components/yaml.rst | 2 + reference/constraints/Yaml.rst | 152 +++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 reference/constraints/Yaml.rst diff --git a/components/yaml.rst b/components/yaml.rst index 5f724e0572c..2698aae8233 100644 --- a/components/yaml.rst +++ b/components/yaml.rst @@ -214,6 +214,8 @@ During the parsing of the YAML contents, all the ``_`` characters are removed from the numeric literal contents, so there is not a limit in the number of underscores you can include or the way you group contents. +.. _yaml-flags: + Advanced Usage: Flags --------------------- diff --git a/reference/constraints/Yaml.rst b/reference/constraints/Yaml.rst new file mode 100644 index 00000000000..49b65f251e8 --- /dev/null +++ b/reference/constraints/Yaml.rst @@ -0,0 +1,152 @@ +Yaml +==== + +Validates that a value has valid `YAML`_ syntax. + +.. versionadded:: 7.2 + + The ``Yaml`` constraint was introduced in Symfony 7.2. + +========== =================================================================== +Applies to :ref:`property or method ` +Class :class:`Symfony\\Component\\Validator\\Constraints\\Yaml` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\YamlValidator` +========== =================================================================== + +Basic Usage +----------- + +The ``Yaml`` constraint can be applied to a property or a "getter" method: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/Report.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Report + { + #[Assert\Yaml( + message: "Your configuration doesn't have valid YAML syntax." + )] + private string $customConfiguration; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\Report: + properties: + customConfiguration: + - Yaml: + message: Your configuration doesn't have valid YAML syntax. + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Report.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class Report + { + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('customConfiguration', new Assert\Yaml([ + 'message' => 'Your configuration doesn\'t have valid YAML syntax.', + ])); + } + } + +Options +------- + +``flags`` +~~~~~~~~~ + +**type**: ``integer`` **default**: ``0`` + +This option enables optional features of the YAML parser when validating contents. +Its value is a combination of one or more of the :ref:`flags defined by the Yaml component `: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/Report.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Yaml\Yaml; + + class Report + { + #[Assert\Yaml( + message: "Your configuration doesn't have valid YAML syntax.", + flags: Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_DATETIME, + )] + private string $customConfiguration; + } + + .. code-block:: php + + // src/Entity/Report.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Yaml\Yaml; + + class Report + { + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('customConfiguration', new Assert\Yaml([ + 'message' => 'Your configuration doesn\'t have valid YAML syntax.', + 'flags' => Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_DATETIME, + ])); + } + } + +``message`` +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is not valid YAML.`` + +This message shown if the underlying data is not a valid YAML value. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ error }}`` The full error message from the YAML parser +``{{ line }}`` The line where the YAML syntax error happened +=============== ============================================================== + +.. include:: /reference/constraints/_groups-option.rst.inc + +.. include:: /reference/constraints/_payload-option.rst.inc + +.. _`YAML`: https://en.wikipedia.org/wiki/YAML From c3fdc75c27551e2a09bb5298b1d47e7e759ac60c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 26 Jun 2024 09:01:07 +0200 Subject: [PATCH 018/427] [ExpressionLanguage] Add support for comments --- reference/formats/expression_language.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reference/formats/expression_language.rst b/reference/formats/expression_language.rst index 818870452a5..e88ac7f6c24 100644 --- a/reference/formats/expression_language.rst +++ b/reference/formats/expression_language.rst @@ -20,6 +20,11 @@ The component supports: * **booleans** - ``true`` and ``false`` * **null** - ``null`` * **exponential** - also known as scientific (e.g. ``1.99E+3`` or ``1e-2``) +* **comments** - using ``/*`` and ``*/`` (e.g. ``/* this is a comment */``) + +.. versionadded:: 7.2 + + The support for comments inside expressions was introduced in Symfony 7.2. .. caution:: From 39be3e699885a57f91a2b30a4f34855465f1ec03 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 26 Jun 2024 09:55:47 +0200 Subject: [PATCH 019/427] [DependencyInjection] Add `#[WhenNot]` attribute --- reference/attributes.rst | 1 + service_container.rst | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/reference/attributes.rst b/reference/attributes.rst index 4428dc4c587..d744cb9a9b4 100644 --- a/reference/attributes.rst +++ b/reference/attributes.rst @@ -43,6 +43,7 @@ Dependency Injection * :ref:`TaggedLocator ` * :ref:`Target ` * :ref:`When ` +* :ref:`WhenNot ` EventDispatcher ~~~~~~~~~~~~~~~ diff --git a/service_container.rst b/service_container.rst index ebc01b1fc8a..bc8e5f123b1 100644 --- a/service_container.rst +++ b/service_container.rst @@ -260,6 +260,32 @@ as a service in some environments:: // ... } +If you want to exclude a service from being registered in a specific +environment, you can use the ``#[WhenNot]`` attribute:: + + use Symfony\Component\DependencyInjection\Attribute\WhenNot; + + // SomeClass is registered in all environments except "dev" + + #[WhenNot(env: 'dev')] + class SomeClass + { + // ... + } + + // you can apply more than one WhenNot attribute to the same class + + #[WhenNot(env: 'dev')] + #[WhenNot(env: 'test')] + class AnotherClass + { + // ... + } + +.. versionadded:: 7.2 + + The ``#[WhenNot]`` attribute was introduced in Symfony 7.2. + .. _services-constructor-injection: Injecting Services/Config into a Service From c4e8ace5ce8e095c4c6a67a1db20d979a003195b Mon Sep 17 00:00:00 2001 From: sakul95 <60596924+sakul95@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:10:25 +0200 Subject: [PATCH 020/427] [Notifier] Add Sipgate bridge --- notifier.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/notifier.rst b/notifier.rst index 1a19c135a7c..3ecb8878fb4 100644 --- a/notifier.rst +++ b/notifier.rst @@ -159,6 +159,9 @@ Service `Sinch`_ **Install**: ``composer require symfony/sinch-notifier`` \ **DSN**: ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` \ **Webhook support**: No +`Sipgate`_ **Install**: ``composer require symfony/sipgate-notifier`` \ + **DSN**: ``sipgate://TOKEN_ID:TOKEN@default?senderId=SENDER_ID`` \ + **Webhook support**: No `SmsSluzba`_ **Install**: ``composer require symfony/sms-sluzba-notifier`` \ **DSN**: ``sms-sluzba://USERNAME:PASSWORD@default`` \ **Webhook support**: No @@ -214,6 +217,10 @@ Service The ``Smsbox``, ``SmsSluzba``, ``SMSense``, ``LOX24`` and ``Unifonic`` integrations were introduced in Symfony 7.1. +.. versionadded:: 7.2 + + The ``Sipgate`` integration was introduced in Symfony 7.2. + .. deprecated:: 7.1 The `Sms77`_ integration is deprecated since @@ -1131,6 +1138,7 @@ is dispatched. Listeners receive a .. _`Seven.io`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sevenio/README.md .. _`SimpleTextin`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SimpleTextin/README.md .. _`Sinch`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sinch/README.md +.. _`Sipgate`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sipgate/README.md .. _`Slack`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Slack/README.md .. _`Sms77`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sms77/README.md .. _`SmsBiuras`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SmsBiuras/README.md From 9f4e5a5fb5418489978f0b30e5803e4eaec80baf Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Sun, 7 Jul 2024 13:56:54 +0200 Subject: [PATCH 021/427] Remove the Gitter bridge --- notifier.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 5fe86724fe1..cbc23655124 100644 --- a/notifier.rst +++ b/notifier.rst @@ -351,7 +351,6 @@ Service Package D `Discord`_ ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` `FakeChat`_ ``symfony/fake-chat-notifier`` ``fakechat+email://default?to=TO&from=FROM`` or ``fakechat+logger://default`` `Firebase`_ ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` -`Gitter`_ ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` `GoogleChat`_ ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` `LINE Notify`_ ``symfony/line-notify-notifier`` ``linenotify://TOKEN@default`` `LinkedIn`_ ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` @@ -1105,7 +1104,6 @@ is dispatched. Listeners receive a .. _`Firebase`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Firebase/README.md .. _`FreeMobile`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/FreeMobile/README.md .. _`GatewayApi`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GatewayApi/README.md -.. _`Gitter`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Gitter/README.md .. _`GoIP`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GoIP/README.md .. _`GoogleChat`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md .. _`Infobip`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Infobip/README.md From 03173f88b1d74cb64a5ae1042bbdd19a3d515531 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Jul 2024 09:39:04 +0200 Subject: [PATCH 022/427] Add a note explaining the removal of Gitter --- notifier.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notifier.rst b/notifier.rst index cbc23655124..d959b4a73d0 100644 --- a/notifier.rst +++ b/notifier.rst @@ -370,6 +370,11 @@ Service Package D The ``Bluesky`` integration was introduced in Symfony 7.1. +.. deprecated:: 7.2 + + The ``Gitter`` integration was removed in Symfony 7.2 because that service + no longer provides an API. + .. caution:: By default, if you have the :doc:`Messenger component ` installed, From 7928e4d7b21c7e860492c7ee6e9dbcd4a1f2e1ef Mon Sep 17 00:00:00 2001 From: Tim Herlaud Date: Wed, 10 Jul 2024 09:17:34 +0200 Subject: [PATCH 023/427] [String] Add TruncateMode mode to truncate methods --- string.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/string.rst b/string.rst index c58a736da89..c956d33b9af 100644 --- a/string.rst +++ b/string.rst @@ -394,11 +394,16 @@ Methods to Join, Split, Truncate and Reverse u('Lorem Ipsum')->truncate(3); // 'Lor' u('Lorem Ipsum')->truncate(80); // 'Lorem Ipsum' // the second argument is the character(s) added when a string is cut + // the third argument is TruncateMode::Char by default // (the total length includes the length of this character(s)) - u('Lorem Ipsum')->truncate(8, '…'); // 'Lorem I…' - // if the third argument is false, the last word before the cut is kept - // even if that generates a string longer than the desired length - u('Lorem Ipsum')->truncate(8, '…', cut: false); // 'Lorem Ipsum' + u('Lorem Ipsum')->truncate(8, '…'); // 'Lorem I…' + // use options to keep complete words + u('Lorem ipsum dolor sit amet')->truncate(10, '...', TruncateMode::WordBefore); // 'Lorem...' + u('Lorem ipsum dolor sit amet')->truncate(14, '...', TruncateMode::WordAfter); // 'Lorem ipsum...' + +.. versionadded:: 7.2 + + The TruncateMode argument for truncate function was introduced in Symfony 7.2. :: From b607d25adaad279a4c0b974713f3f627c00cff7c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 10 Jul 2024 17:09:38 +0200 Subject: [PATCH 024/427] Reword --- string.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/string.rst b/string.rst index 72dfb5c4ae7..cd104b1f947 100644 --- a/string.rst +++ b/string.rst @@ -394,16 +394,20 @@ Methods to Join, Split, Truncate and Reverse u('Lorem Ipsum')->truncate(3); // 'Lor' u('Lorem Ipsum')->truncate(80); // 'Lorem Ipsum' // the second argument is the character(s) added when a string is cut - // the third argument is TruncateMode::Char by default // (the total length includes the length of this character(s)) + // (note that '…' is a single character that includes three dots; it's not '...') u('Lorem Ipsum')->truncate(8, '…'); // 'Lorem I…' - // use options to keep complete words - u('Lorem ipsum dolor sit amet')->truncate(10, '...', TruncateMode::WordBefore); // 'Lorem...' - u('Lorem ipsum dolor sit amet')->truncate(14, '...', TruncateMode::WordAfter); // 'Lorem ipsum...' + // the third optional argument defines how to cut words when the length is exceeded + // the default value is TruncateMode::Char which cuts the string at the exact given length + u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::Char); // 'Lorem ip' + // returns up to the last complete word that fits in the given length without surpassing it + u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::WordBefore); // 'Lorem' + // returns up to the last complete word that fits in the given length, surpassing it if needed + u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::WordAfter); // 'Lorem ipsum' .. versionadded:: 7.2 - The TruncateMode argument for truncate function was introduced in Symfony 7.2. + The ``TruncateMode`` argument for truncate function was introduced in Symfony 7.2. :: From 3236182336c79d9d3ea5a28a2c21550067b636a0 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 10 Jul 2024 20:06:51 +0200 Subject: [PATCH 025/427] - --- string.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/string.rst b/string.rst index cd104b1f947..f2856976986 100644 --- a/string.rst +++ b/string.rst @@ -407,7 +407,7 @@ Methods to Join, Split, Truncate and Reverse .. versionadded:: 7.2 - The ``TruncateMode`` argument for truncate function was introduced in Symfony 7.2. + The ``TruncateMode`` parameter for truncate function was introduced in Symfony 7.2. :: From e983455bc391256a77f5397efe650393e9c58c04 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 17 Jul 2024 15:13:29 +0200 Subject: [PATCH 026/427] [Validator] Add the `WordCount` constraint --- reference/constraints/WordCount.rst | 150 ++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 2 files changed, 151 insertions(+) create mode 100644 reference/constraints/WordCount.rst diff --git a/reference/constraints/WordCount.rst b/reference/constraints/WordCount.rst new file mode 100644 index 00000000000..74c79216898 --- /dev/null +++ b/reference/constraints/WordCount.rst @@ -0,0 +1,150 @@ +WordCount +========= + +.. versionadded:: 7.2 + + The ``WordCount`` constraint was introduced in Symfony 7.2. + +Validates that a string (or an object implementing the ``Stringable`` PHP interface) +contains a given number of words. Internally, this constraint uses the +:phpclass:`IntlBreakIterator` class to count the words depending on your locale. + +========== ======================================================================= +Applies to :ref:`property or method ` +Class :class:`Symfony\\Component\\Validator\\Constraints\\WordCount` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\WordCountValidator` +========== ======================================================================= + +Basic Usage +----------- + +If you wanted to ensure that the ``content`` property of a ``BlogPostDTO`` +class contains between 100 and 200 words, you could do the following: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/BlogPostDTO.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class BlogPostDTO + { + #[Assert\WordCount(min: 100, max: 200)] + protected string $content; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\BlogPostDTO: + properties: + content: + - WordCount: + min: 100 + max: 200 + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/BlogPostDTO.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class BlogPostDTO + { + // ... + + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('content', new Assert\WordCount([ + 'min' => 100, + 'max' => 200, + ])); + } + } + +Options +------- + +``min`` +~~~~~~~ + +**type**: ``integer`` **default**: ``null`` + +The minimum number of words that the value must contain. + +``max`` +~~~~~~~ + +**type**: ``integer`` **default**: ``null`` + +The maximum number of words that the value must contain. + +``locale`` +~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +The locale to use for counting the words by using the :phpclass:`IntlBreakIterator` +class. The default value (``null``) means that the constraint uses the current +user locale. + +.. include:: /reference/constraints/_groups-option.rst.inc + +``minMessage`` +~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.`` + +This is the message that will be shown if the value does not contain at least +the minimum number of words. + +You can use the following parameters in this message: + +================ ================================================== +Parameter Description +================ ================================================== +``{{ min }}`` The minimum number of words +``{{ count }}`` The actual number of words +================ ================================================== + +``maxMessage`` +~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.`` + +This is the message that will be shown if the value contains more than the +maximum number of words. + +You can use the following parameters in this message: + +================ ================================================== +Parameter Description +================ ================================================== +``{{ max }}`` The maximum number of words +``{{ count }}`` The actual number of words +================ ================================================== + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 9f14f418bb1..978951c9de7 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -33,6 +33,7 @@ String Constraints * :doc:`NoSuspiciousCharacters ` * :doc:`Charset ` * :doc:`MacAddress ` +* :doc:`WordCount ` Comparison Constraints ~~~~~~~~~~~~~~~~~~~~~~ From fa572ee1d7fd2cea6717ab3a52a93d30d536c04b Mon Sep 17 00:00:00 2001 From: Petrisor Ciprian Daniel Date: Fri, 19 Jul 2024 23:31:27 +0300 Subject: [PATCH 027/427] [Config] Secrets decrypt exit option --- configuration/secrets.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configuration/secrets.rst b/configuration/secrets.rst index f717456a22c..b16c36643aa 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -271,11 +271,20 @@ manually store this file somewhere and deploy it. There are 2 ways to do that: .. code-block:: terminal - $ APP_RUNTIME_ENV=prod php bin/console secrets:decrypt-to-local --force + $ APP_RUNTIME_ENV=prod php bin/console secrets:decrypt-to-local --force --exit This will write all the decrypted secrets into the ``.env.prod.local`` file. After doing this, the decryption key does *not* need to remain on the server(s). + Note the usage of the ``--exit`` option: this forces all secrets to be successfully + decrypted, otherwise a non-zero exit code is returned. + + If you wish to continue regardless of errors occurring during decryption, you may omit this option. + + .. versionadded:: 7.2 + + The ``--exit`` option was introduced in Symfony 7.2. + Rotating Secrets ---------------- From 97103298ebabb6f3fb5c015450e1d8f893149bca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 22 Jul 2024 09:03:49 +0200 Subject: [PATCH 028/427] Tweaks --- configuration/secrets.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/configuration/secrets.rst b/configuration/secrets.rst index b16c36643aa..734873b255c 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -276,14 +276,16 @@ manually store this file somewhere and deploy it. There are 2 ways to do that: This will write all the decrypted secrets into the ``.env.prod.local`` file. After doing this, the decryption key does *not* need to remain on the server(s). - Note the usage of the ``--exit`` option: this forces all secrets to be successfully - decrypted, otherwise a non-zero exit code is returned. + Note the usage of the ``--exit`` option: this ensures that all secrets are + successfully decrypted. If any error occurs during the decryption process, + the command will return a non-zero exit code, indicating a failure. - If you wish to continue regardless of errors occurring during decryption, you may omit this option. + If you wish to continue regardless of errors occurring during decryption, + you may omit this option. .. versionadded:: 7.2 - The ``--exit`` option was introduced in Symfony 7.2. + The ``--exit`` option was introduced in Symfony 7.2. Rotating Secrets ---------------- From 8e1d67b18758832865b51fd28066018cfc34b9ac Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 22 Jul 2024 15:16:47 +0200 Subject: [PATCH 029/427] drop the --exit option --- configuration/secrets.rst | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/configuration/secrets.rst b/configuration/secrets.rst index 734873b255c..f717456a22c 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -271,22 +271,11 @@ manually store this file somewhere and deploy it. There are 2 ways to do that: .. code-block:: terminal - $ APP_RUNTIME_ENV=prod php bin/console secrets:decrypt-to-local --force --exit + $ APP_RUNTIME_ENV=prod php bin/console secrets:decrypt-to-local --force This will write all the decrypted secrets into the ``.env.prod.local`` file. After doing this, the decryption key does *not* need to remain on the server(s). - Note the usage of the ``--exit`` option: this ensures that all secrets are - successfully decrypted. If any error occurs during the decryption process, - the command will return a non-zero exit code, indicating a failure. - - If you wish to continue regardless of errors occurring during decryption, - you may omit this option. - - .. versionadded:: 7.2 - - The ``--exit`` option was introduced in Symfony 7.2. - Rotating Secrets ---------------- From f5f16af36ded58edf37af2be3fe6f078d7c6b64b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 25 Jul 2024 09:54:38 +0200 Subject: [PATCH 030/427] add the $token argument to checkPostAuth() --- security/user_checkers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/user_checkers.rst b/security/user_checkers.rst index d62cc0bea32..1e1dcaf3e55 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -40,7 +40,7 @@ displayed to the user:: } } - public function checkPostAuth(UserInterface $user): void + public function checkPostAuth(UserInterface $user, TokenInterface $token): void { if (!$user instanceof AppUser) { return; From aec2ec5ef61cca979c9d830a6fd22d6a64446ab4 Mon Sep 17 00:00:00 2001 From: Marcin Nowak Date: Fri, 26 Jul 2024 14:12:16 +0200 Subject: [PATCH 031/427] Added information about clock parameter in ArrayAdapter --- components/cache/adapters/array_cache_adapter.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/cache/adapters/array_cache_adapter.rst b/components/cache/adapters/array_cache_adapter.rst index f903771e468..a6a72514361 100644 --- a/components/cache/adapters/array_cache_adapter.rst +++ b/components/cache/adapters/array_cache_adapter.rst @@ -24,5 +24,10 @@ method:: // the maximum number of items that can be stored in the cache. When the limit // is reached, cache follows the LRU model (least recently used items are deleted) - $maxItems = 0 + $maxItems = 0, + + // implementation of Psr\Clock\ClockInterface (e.g. Symfony\Component\Clock\Clock) + // or null. If clock is provided, cache items lifetime will be calculated + // based on time provided by this clock + $clock = null ); From 87acbbcce5954cd05f16824d8db91b42fe954318 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 26 Jul 2024 14:29:19 +0200 Subject: [PATCH 032/427] fix the syntax of PHP code blocks --- configuration/micro_kernel_trait.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 23aa677cf20..c9739679f69 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -57,7 +57,7 @@ Next, create an ``index.php`` file that defines the kernel class and runs it: return static function (array $context) { return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); - } + }; .. code-block:: php @@ -98,7 +98,7 @@ Next, create an ``index.php`` file that defines the kernel class and runs it: return static function (array $context) { return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); - } + }; That's it! To test it, start the :doc:`Symfony Local Web Server `: From f1c8808ee481a65b1e10453e362b54b98c3ae4cc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 26 Jul 2024 17:03:46 +0200 Subject: [PATCH 033/427] [Cache] Igbinary extension is no longer used by default when available --- components/cache.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/cache.rst b/components/cache.rst index f5a76f2119d..939627b1807 100644 --- a/components/cache.rst +++ b/components/cache.rst @@ -208,16 +208,27 @@ Symfony uses *marshallers* (classes which implement the cache items before storing them. The :class:`Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller` uses PHP's -``serialize()`` or ``igbinary_serialize()`` if the `Igbinary extension`_ is installed. -There are other *marshallers* that can encrypt or compress the data before storing it:: +``serialize()`` function by default, but you can optionally use the ``igbinary_serialize()`` +function from the `Igbinary extension`_: use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DefaultMarshaller; use Symfony\Component\Cache\DeflateMarshaller; $marshaller = new DeflateMarshaller(new DefaultMarshaller()); + // you can optionally use the Igbinary extension if you have it installed + // $marshaller = new DeflateMarshaller(new DefaultMarshaller(useIgbinarySerialize: true)); + $cache = new RedisAdapter(new \Redis(), 'namespace', 0, $marshaller); +There are other *marshallers* that can encrypt or compress the data before storing it. + +.. versionadded:: 7.2 + + In Symfony versions prior to 7.2, the ``igbinary_serialize()`` function was + used by default when the Igbinary extension was installed. Starting from + Symfony 7.2, you have to enable Igbinary support explicitly. + Advanced Usage -------------- From d2b384beacf7a749ffaf0e98b9f41315a95893a2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 30 Jul 2024 16:38:51 +0200 Subject: [PATCH 034/427] fix typo --- performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/performance.rst b/performance.rst index 70a6602873e..828333f338b 100644 --- a/performance.rst +++ b/performance.rst @@ -367,7 +367,7 @@ method does, which stops an event and then restarts it immediately:: .. versionadded:: 7.2 - The ``getLastPeriod`` method was introduced in Symfony 7.2. + The ``getLastPeriod()`` method was introduced in Symfony 7.2. Profiling Sections .................. From e2d8f0a36494d6370e0c845a18a36a84f8329ea5 Mon Sep 17 00:00:00 2001 From: Jonas Claes Date: Thu, 1 Aug 2024 19:31:56 +0200 Subject: [PATCH 035/427] Update mailer.rst --- mailer.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index 502644a741a..11acd065e52 100644 --- a/mailer.rst +++ b/mailer.rst @@ -110,6 +110,7 @@ Service Install with Webhook su `MailPace`_ ``composer require symfony/mail-pace-mailer`` `MailerSend`_ ``composer require symfony/mailer-send-mailer`` `Mandrill`_ ``composer require symfony/mailchimp-mailer`` +`Postal`_ ``composer require symfony/postal-mailer`` `Postmark`_ ``composer require symfony/postmark-mailer`` yes `Resend`_ ``composer require symfony/resend-mailer`` yes `Scaleway`_ ``composer require symfony/scaleway-mailer`` @@ -122,7 +123,7 @@ Service Install with Webhook su .. versionadded:: 7.2 - The Mailomat integration was introduced in Symfony 7.2. + The Mailomat and Postal integrations were introduced in Symfony 7.2. .. note:: @@ -214,6 +215,10 @@ party provider: | | - HTTP n/a | | | - API ``mailpace+api://API_TOKEN@default`` | +------------------------+---------------------------------------------------------+ +| `Postal`_ | - SMTP n/a | +| | - HTTP n/a | +| | - API ``postal+api://API_KEY@BASE_URL`` | ++------------------------+---------------------------------------------------------+ | `Postmark`_ | - SMTP ``postmark+smtp://ID@default`` | | | - HTTP n/a | | | - API ``postmark+api://KEY@default`` | @@ -1992,6 +1997,7 @@ the :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait`:: .. _`MailPace`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/MailPace/README.md .. _`OpenSSL PHP extension`: https://www.php.net/manual/en/book.openssl.php .. _`PEM encoded`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail +.. _`Postal`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Postal/README.md .. _`Postmark`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Postmark/README.md .. _`Resend`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Resend/README.md .. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt From 4b3fad09b8894e9d61876e1fdd8752275fe57691 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 6 Aug 2024 17:44:01 +0200 Subject: [PATCH 036/427] Add the versionadded directive --- components/cache/adapters/array_cache_adapter.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/cache/adapters/array_cache_adapter.rst b/components/cache/adapters/array_cache_adapter.rst index a6a72514361..08f8276db3d 100644 --- a/components/cache/adapters/array_cache_adapter.rst +++ b/components/cache/adapters/array_cache_adapter.rst @@ -26,8 +26,12 @@ method:: // is reached, cache follows the LRU model (least recently used items are deleted) $maxItems = 0, - // implementation of Psr\Clock\ClockInterface (e.g. Symfony\Component\Clock\Clock) - // or null. If clock is provided, cache items lifetime will be calculated - // based on time provided by this clock - $clock = null + // optional implementation of the Psr\Clock\ClockInterface that will be used + // to calculate the lifetime of cache items (for example to get predictable + // lifetimes in tests) + $clock = null, ); + +.. versionadded:: 7.2 + + The optional ``$clock`` argument was introduced in Symfony 7.2. From c7bf80275b6a65807642e860fc19af77ffd6c453 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 7 Aug 2024 11:02:10 +0200 Subject: [PATCH 037/427] [Validator] Mention `Ulid::FORMAT_RFC4122` --- reference/constraints/Ulid.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst index 4ba5ec3a3f5..a5888409960 100644 --- a/reference/constraints/Ulid.rst +++ b/reference/constraints/Ulid.rst @@ -82,6 +82,7 @@ The format of the ULID to validate. The following formats are available: * ``Ulid::FORMAT_BASE_32``: The ULID is encoded in base32 (default) * ``Ulid::FORMAT_BASE_58``: The ULID is encoded in base58 +* ``Ulid::FORMAT_RFC4122``: The ULID is encoded in the RFC 4122 format .. versionadded:: 7.2 From 9381f4be9bf1149ab63d850b84d678e2e1df6869 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 7 Aug 2024 14:20:31 +0200 Subject: [PATCH 038/427] [Validator] Add links to Ulid constraint formats --- reference/constraints/Ulid.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst index a5888409960..4094bab98f5 100644 --- a/reference/constraints/Ulid.rst +++ b/reference/constraints/Ulid.rst @@ -80,9 +80,9 @@ Options The format of the ULID to validate. The following formats are available: -* ``Ulid::FORMAT_BASE_32``: The ULID is encoded in base32 (default) -* ``Ulid::FORMAT_BASE_58``: The ULID is encoded in base58 -* ``Ulid::FORMAT_RFC4122``: The ULID is encoded in the RFC 4122 format +* ``Ulid::FORMAT_BASE_32``: The ULID is encoded in `base32`_ (default) +* ``Ulid::FORMAT_BASE_58``: The ULID is encoded in `base58`_ +* ``Ulid::FORMAT_RFC4122``: The ULID is encoded in the `RFC 4122 format`_ .. versionadded:: 7.2 @@ -111,3 +111,6 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc .. _`Universally Unique Lexicographically Sortable Identifier (ULID)`: https://github.com/ulid/spec +.. _`base32`: https://en.wikipedia.org/wiki/Base32 +.. _`base58`: https://en.wikipedia.org/wiki/Binary-to-text_encoding#Base58 +.. _`RFC 4122 format`: https://datatracker.ietf.org/doc/html/rfc4122 From 323391d8876b561f1fa12d12c86c59cf75512c89 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 13 Aug 2024 10:21:05 +0200 Subject: [PATCH 039/427] [Validator] Add `Week` constraint --- reference/constraints/Week.rst | 172 ++++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 2 files changed, 173 insertions(+) create mode 100644 reference/constraints/Week.rst diff --git a/reference/constraints/Week.rst b/reference/constraints/Week.rst new file mode 100644 index 00000000000..0aea71bee02 --- /dev/null +++ b/reference/constraints/Week.rst @@ -0,0 +1,172 @@ +Week +==== + +.. versionadded:: 7.2 + + The ``Week`` constraint was introduced in Symfony 7.2. + +Validates that a string (or an object implementing the ``Stringable`` PHP interface) +matches a given week number. The week number format is defined by `ISO-8601`_ +and should be composed of the year and the week number, separated by a hyphen +(e.g. ``2022-W01``). + +========== ======================================================================= +Applies to :ref:`property or method ` +Class :class:`Symfony\\Component\\Validator\\Constraints\\Week` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\WeekValidator` +========== ======================================================================= + +Basic Usage +----------- + +If you wanted to ensure that the ``startWeek`` property of an ``OnlineCourse`` +class is between the first and the twentieth week of the year 2022, you could do +the following: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/OnlineCourse.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class OnlineCourse + { + #[Assert\Week(min: '2022-W01', max: '2022-W20')] + protected string $startWeek; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\OnlineCourse: + properties: + startWeek: + - Week: + min: '2022-W01' + max: '2022-W20' + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/OnlineCourse.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class OnlineCourse + { + // ... + + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('startWeek', new Assert\Week([ + 'min' => '2022-W01', + 'max' => '2022-W20', + ])); + } + } + +.. note:: + + The constraint also checks that the given week exists in the calendar. For example, + ``2022-W53`` is not a valid week number for 2022, because 2022 only had 52 weeks. + +Options +------- + +``min`` +~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +The minimum week number that the value must match. + +``max`` +~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +The maximum week number that the value must match. + +.. include:: /reference/constraints/_groups-option.rst.inc + +``invalidFormatMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value does not represent a valid week in the ISO 8601 format.`` + +This is the message that will be shown if the value does not match the ISO 8601 +week format. + +``invalidWeekNumberMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The week "{{ value }}" is not a valid week.`` + +This is the message that will be shown if the value does not match a valid week +number. + +You can use the following parameters in this message: + +================ ================================================== +Parameter Description +================ ================================================== +``{{ value }}`` The value that was passed to the constraint +================ ================================================== + +``tooLowMessage`` +~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The value should not be before week "{{ min }}".`` + +This is the message that will be shown if the value is lower than the minimum +week number. + +You can use the following parameters in this message: + +================ ================================================== +Parameter Description +================ ================================================== +``{{ min }}`` The minimum week number +================ ================================================== + +``tooHighMessage`` +~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The value should not be after week "{{ max }}".`` + +This is the message that will be shown if the value is higher than the maximum +week number. + +You can use the following parameters in this message: + +================ ================================================== +Parameter Description +================ ================================================== +``{{ max }}`` The maximum week number +================ ================================================== + +.. include:: /reference/constraints/_payload-option.rst.inc + +.. _ISO-8601: https://en.wikipedia.org/wiki/ISO_8601 diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 978951c9de7..e0dbd6c4512 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -64,6 +64,7 @@ Date Constraints * :doc:`DateTime ` * :doc:`Time ` * :doc:`Timezone ` +* :doc:`Week ` Choice Constraints ~~~~~~~~~~~~~~~~~~ From 8d5b1d357df87484858a2902baf6cd0d2e8b59dd Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 19 Aug 2024 10:48:33 +0200 Subject: [PATCH 040/427] [Uid] Add support for binary, base-32 and base-58 representations in `Uuid::isValid()` --- components/uid.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index 7195d393ed3..feb58968347 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -314,6 +314,30 @@ UUID objects created with the ``Uuid`` class can use the following methods // * int < 0 if $uuid1 is less than $uuid4 $uuid1->compare($uuid4); // e.g. int(4) +If you're working with different UUIDs format and want to validate them, +you can use the ``$format`` parameter of the :method:`Symfony\\Component\\Uid\\Uuid::isValid` +method to specify the UUID format you're expecting:: + + use Symfony\Component\Uid\Uuid; + + $isValid = Uuid::isValid('90067ce4-f083-47d2-a0f4-c47359de0f97', Uuid::FORMAT_RFC_4122); // accept only RFC 4122 UUIDs + $isValid = Uuid::isValid('3aJ7CNpDMfXPZrCsn4Cgey', Uuid::FORMAT_BASE_32 | Uuid::FORMAT_BASE_58); // accept multiple formats + +The following constants are available: + +* ``Uuid::FORMAT_BINARY`` +* ``Uuid::FORMAT_BASE_32`` +* ``Uuid::FORMAT_BASE_58`` +* ``Uuid::FORMAT_RFC_4122`` + +You can also use the ``Uuid::FORMAT_ALL`` constant to accept any UUID format. +By default, only the RFC 4122 format is accepted. + +.. versionadded:: 7.2 + + The ``$format`` parameter of the :method:`Symfony\\Component\\Uid\\Uuid::isValid` + method and the related constants were introduced in Symfony 7.2. + Storing UUIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 3567f5b79a01bd878143a3016bc224559f5c4ec4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 19 Aug 2024 10:58:42 +0200 Subject: [PATCH 041/427] [Serializer] Deprecate passing a non-empty CSV escape char --- components/serializer.rst | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index 09efbf44e6c..61124e3f030 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -1064,30 +1064,35 @@ which defines the configuration options for the CsvEncoder an associative array: These are the options available: -======================= ===================================================== ========================== -Option Description Default -======================= ===================================================== ========================== -``csv_delimiter`` Sets the field delimiter separating values (one ``,`` +======================= ============================================================= ========================== +Option Description Default +======================= ============================================================= ========================== +``csv_delimiter`` Sets the field delimiter separating values (one ``,`` character only) -``csv_enclosure`` Sets the field enclosure (one character only) ``"`` -``csv_end_of_line`` Sets the character(s) used to mark the end of each ``\n`` +``csv_enclosure`` Sets the field enclosure (one character only) ``"`` +``csv_end_of_line`` Sets the character(s) used to mark the end of each ``\n`` line in the CSV file -``csv_escape_char`` Sets the escape character (at most one character) empty string -``csv_key_separator`` Sets the separator for array's keys during its ``.`` +``csv_escape_char`` Deprecated. Sets the escape character (at most one character) empty string +``csv_key_separator`` Sets the separator for array's keys during its ``.`` flattening ``csv_headers`` Sets the order of the header and data columns E.g.: if ``$data = ['c' => 3, 'a' => 1, 'b' => 2]`` and ``$options = ['csv_headers' => ['a', 'b', 'c']]`` then ``serialize($data, 'csv', $options)`` returns - ``a,b,c\n1,2,3`` ``[]``, inferred from input data's keys -``csv_escape_formulas`` Escapes fields containing formulas by prepending them ``false`` + ``a,b,c\n1,2,3`` ``[]``, inferred from input data's keys +``csv_escape_formulas`` Escapes fields containing formulas by prepending them ``false`` with a ``\t`` character -``as_collection`` Always returns results as a collection, even if only ``true`` +``as_collection`` Always returns results as a collection, even if only ``true`` one line is decoded. -``no_headers`` Setting to ``false`` will use first row as headers. ``false`` +``no_headers`` Setting to ``false`` will use first row as headers. ``false`` ``true`` generate numeric headers. -``output_utf8_bom`` Outputs special `UTF-8 BOM`_ along with encoded data ``false`` -======================= ===================================================== ========================== +``output_utf8_bom`` Outputs special `UTF-8 BOM`_ along with encoded data ``false`` +======================= ============================================================= ========================== + +.. deprecated:: 7.2 + + The ``csv_escape_char`` option and the ``CsvEncoder::ESCAPE_CHAR_KEY`` + constant were deprecated in Symfony 7.2. The ``XmlEncoder`` ~~~~~~~~~~~~~~~~~~ @@ -1304,6 +1309,11 @@ you can use "context builders" to define the context using a fluent interface:: You can also :doc:`create custom context builders ` to deal with your context values. +.. deprecated:: 7.2 + + The ``CsvEncoderContextBuilder::withEscapeChar()`` method was deprecated + in Symfony 7.2. + Skipping ``null`` Values ------------------------ From f39be7640c72c575da3320aa01ff3e7cca466660 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 19 Aug 2024 11:06:42 +0200 Subject: [PATCH 042/427] [FrameworkBundle][HttpFoundation] Deprecate `session.sid_length` and `session.sid_bits_per_character` config options --- reference/configuration/framework.rst | 8 ++++++++ session.rst | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 0921fe9ac2e..72c4b1b94f7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1874,6 +1874,10 @@ session IDs are harder to guess. If not set, ``php.ini``'s `session.sid_length`_ directive will be relied on. +.. deprecated:: 7.2 + + The ``sid_length`` option was deprecated in Symfony 7.2. + sid_bits_per_character ...................... @@ -1886,6 +1890,10 @@ most environments. If not set, ``php.ini``'s `session.sid_bits_per_character`_ directive will be relied on. +.. deprecated:: 7.2 + + The ``sid_bits_per_character`` option was deprecated in Symfony 7.2. + save_path ......... diff --git a/session.rst b/session.rst index 29d1ba364d1..77aea3bba00 100644 --- a/session.rst +++ b/session.rst @@ -400,6 +400,11 @@ Check out the Symfony config reference to learn more about the other available ``session.auto_start = 1`` This directive should be turned off in ``php.ini``, in the web server directives or in ``.htaccess``. +.. deprecated:: 7.2 + + The ``sid_length`` and ``sid_bits_per_character`` options were deprecated + in Symfony 7.2 and will be ignored in Symfony 8.0. + The session cookie is also available in :ref:`the Response object `. This is useful to get that cookie in the CLI context or when using PHP runners like Roadrunner or Swoole. From 51fdaa869c908061f2fc355442a219c57bfc2f0a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 Aug 2024 09:19:34 +0200 Subject: [PATCH 043/427] document the requests constructor argument of the RequestStack class --- components/form.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/form.rst b/components/form.rst index 7584d223032..f463ef5911b 100644 --- a/components/form.rst +++ b/components/form.rst @@ -123,8 +123,7 @@ The following snippet adds CSRF protection to the form factory:: use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage; // creates a RequestStack object using the current request - $requestStack = new RequestStack(); - $requestStack->push($request); + $requestStack = new RequestStack([$request]); $csrfGenerator = new UriSafeTokenGenerator(); $csrfStorage = new SessionTokenStorage($requestStack); @@ -135,6 +134,11 @@ The following snippet adds CSRF protection to the form factory:: ->addExtension(new CsrfExtension($csrfManager)) ->getFormFactory(); +.. versionadded:: 7.2 + + Support for passing requests to the constructor of the ``RequestStack`` + class was introduced in Symfony 7.2. + Internally, this extension will automatically add a hidden field to every form (called ``_token`` by default) whose value is automatically generated by the CSRF generator and validated when binding the form. From bad2a212bf68bdfc6479765d2ecb4123677aee4e Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Tue, 20 Aug 2024 12:01:07 +0200 Subject: [PATCH 044/427] feat(mailer): Add Sweego Mailer doc --- mailer.rst | 8 +++++++- webhook.rst | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index 11acd065e52..091e6d6e5b9 100644 --- a/mailer.rst +++ b/mailer.rst @@ -115,6 +115,7 @@ Service Install with Webhook su `Resend`_ ``composer require symfony/resend-mailer`` yes `Scaleway`_ ``composer require symfony/scaleway-mailer`` `SendGrid`_ ``composer require symfony/sendgrid-mailer`` yes +`Sweego`_ ``composer require symfony/sweego-mailer`` yes ===================== =============================================== =============== .. versionadded:: 7.1 @@ -123,7 +124,7 @@ Service Install with Webhook su .. versionadded:: 7.2 - The Mailomat and Postal integrations were introduced in Symfony 7.2. + The Mailomat, Postal and Sweego integrations were introduced in Symfony 7.2. .. note:: @@ -235,6 +236,10 @@ party provider: | | - HTTP n/a | | | - API ``sendgrid+api://KEY@default`` | +------------------------+---------------------------------------------------------+ +| `Sweego`_ | - SMTP ``sweego+smtp://LOGIN:PASSWORD@HOST:PORT`` | +| | - HTTP n/a | +| | - API ``sweego+api://API_KEY@default`` | ++------------------------+---------------------------------------------------------+ .. caution:: @@ -2004,3 +2009,4 @@ the :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait`:: .. _`S/MIME`: https://en.wikipedia.org/wiki/S/MIME .. _`Scaleway`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Scaleway/README.md .. _`SendGrid`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md +.. _`Sweego`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Sweego/README.md diff --git a/webhook.rst b/webhook.rst index 52633ae83e5..176abc49cd2 100644 --- a/webhook.rst +++ b/webhook.rst @@ -31,6 +31,7 @@ Mailomat ``mailer.webhook.request_parser.mailomat`` Postmark ``mailer.webhook.request_parser.postmark`` Resend ``mailer.webhook.request_parser.resend`` Sendgrid ``mailer.webhook.request_parser.sendgrid`` +Sweego ``mailer.webhook.request_parser.sweego`` ============== ============================================ .. versionadded:: 7.1 @@ -39,7 +40,7 @@ Sendgrid ``mailer.webhook.request_parser.sendgrid`` .. versionadded:: 7.2 - The ``Mailomat`` integration was introduced in Symfony 7.2. + The ``Mailomat`` and ``Sweego`` integrations were introduced in Symfony 7.2. .. note:: From 84da11cd0affbf26ba61eaaa02015f1b0c85854e Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 20 Aug 2024 14:46:44 +0200 Subject: [PATCH 045/427] [HttpFoundation] Add new parameters to `IpUtils::anonymize()` --- components/http_foundation.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 6c9210b894f..2cdd5a02702 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -362,6 +362,23 @@ analysis purposes. Use the ``anonymize()`` method from the $anonymousIpv6 = IpUtils::anonymize($ipv6); // $anonymousIpv6 = '2a01:198:603:10::' +If you need even more anonymization, you can use the second and third parameters +of the ``anonymize()`` method to specify the number of bytes that should be +anonymized depending on the IP address format:: + + $ipv4 = '123.234.235.236'; + $anonymousIpv4 = IpUtils::anonymize($ipv4, v4Bytes: 3); + // $anonymousIpv4 = '123.0.0.0' + + $ipv6 = '2a01:198:603:10:396e:4789:8e99:890f'; + $anonymousIpv6 = IpUtils::anonymize($ipv6, v6Bytes: 10); + // $anonymousIpv6 = '2a01:198:603::' + +.. versionadded:: 7.2 + + The ``v4Bytes`` and ``v6Bytes`` parameters of the ``anonymize()`` method + were introduced in Symfony 7.2. + Check If an IP Belongs to a CIDR Subnet ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From d00645a6062158478477d9df5324d90bae3b6502 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 22 Aug 2024 09:45:19 +0200 Subject: [PATCH 046/427] [Form] Add support for the `calendar` option in `DateType` --- reference/forms/types/date.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 515c12099a1..f9c6d67a70d 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -155,6 +155,19 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/view_timezone.rst.inc +``calendar`` +~~~~~~~~~~~~ + +**type**: ``\IntlCalendar`` **default**: ``null`` + +The calendar to use for formatting and parsing the date. The value should be +an instance of the :phpclass:`IntlCalendar` to use. By default, the Gregorian +calendar with the application default locale is used. + +.. versionadded:: 7.2 + + The ``calendar`` option was introduced in Symfony 7.2. + .. include:: /reference/forms/types/options/date_widget.rst.inc .. include:: /reference/forms/types/options/years.rst.inc From 429e193a40e93a3e521479aa1cc404c0b84c9df1 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 23 Aug 2024 09:30:27 +0200 Subject: [PATCH 047/427] [ExpressionLanguage] Add support for `<<`, `>>`, and `~` bitwise operators --- reference/formats/expression_language.rst | 72 +++++++++++++---------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/reference/formats/expression_language.rst b/reference/formats/expression_language.rst index e88ac7f6c24..ec592461a4f 100644 --- a/reference/formats/expression_language.rst +++ b/reference/formats/expression_language.rst @@ -284,6 +284,14 @@ Bitwise Operators * ``&`` (and) * ``|`` (or) * ``^`` (xor) +* ``~`` (not) +* ``<<`` (left shift) +* ``>>`` (right shift) + +.. versionadded:: 7.2 + + Support for the ``~``, ``<<`` and ``>>`` bitwise operators was introduced + in Symfony 7.2. Comparison Operators ~~~~~~~~~~~~~~~~~~~~ @@ -449,38 +457,38 @@ parentheses in your expressions (e.g. ``(1 + 2) * 4`` or ``1 + (2 * 4)``. The following table summarizes the operators and their associativity from the **highest to the lowest precedence**: -+----------------------------------------------------------+---------------+ -| Operators | Associativity | -+==========================================================+===============+ -| ``-`` , ``+`` (unary operators that add the number sign) | none | -+----------------------------------------------------------+---------------+ -| ``**`` | right | -+----------------------------------------------------------+---------------+ -| ``*``, ``/``, ``%`` | left | -+----------------------------------------------------------+---------------+ -| ``not``, ``!`` | none | -+----------------------------------------------------------+---------------+ -| ``~`` | left | -+----------------------------------------------------------+---------------+ -| ``+``, ``-`` | left | -+----------------------------------------------------------+---------------+ -| ``..`` | left | -+----------------------------------------------------------+---------------+ -| ``==``, ``===``, ``!=``, ``!==``, | left | -| ``<``, ``>``, ``>=``, ``<=``, | | -| ``not in``, ``in``, ``contains``, | | -| ``starts with``, ``ends with``, ``matches`` | | -+----------------------------------------------------------+---------------+ -| ``&`` | left | -+----------------------------------------------------------+---------------+ -| ``^`` | left | -+----------------------------------------------------------+---------------+ -| ``|`` | left | -+----------------------------------------------------------+---------------+ -| ``and``, ``&&`` | left | -+----------------------------------------------------------+---------------+ -| ``or``, ``||`` | left | -+----------------------------------------------------------+---------------+ ++-----------------------------------------------------------------+---------------+ +| Operators | Associativity | ++=================================================================+===============+ +| ``-`` , ``+``, ``~`` (unary operators that add the number sign) | none | ++-----------------------------------------------------------------+---------------+ +| ``**`` | right | ++-----------------------------------------------------------------+---------------+ +| ``*``, ``/``, ``%`` | left | ++-----------------------------------------------------------------+---------------+ +| ``not``, ``!`` | none | ++-----------------------------------------------------------------+---------------+ +| ``~`` | left | ++-----------------------------------------------------------------+---------------+ +| ``+``, ``-`` | left | ++-----------------------------------------------------------------+---------------+ +| ``..``, ``<<``, ``>>`` | left | ++-----------------------------------------------------------------+---------------+ +| ``==``, ``===``, ``!=``, ``!==``, | left | +| ``<``, ``>``, ``>=``, ``<=``, | | +| ``not in``, ``in``, ``contains``, | | +| ``starts with``, ``ends with``, ``matches`` | | ++-----------------------------------------------------------------+---------------+ +| ``&`` | left | ++-----------------------------------------------------------------+---------------+ +| ``^`` | left | ++-----------------------------------------------------------------+---------------+ +| ``|`` | left | ++-----------------------------------------------------------------+---------------+ +| ``and``, ``&&`` | left | ++-----------------------------------------------------------------+---------------+ +| ``or``, ``||`` | left | ++-----------------------------------------------------------------+---------------+ Built-in Objects and Variables ------------------------------ From d883d5659dab11da2ad39be9a380551f74682e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 23 Aug 2024 00:39:01 +0200 Subject: [PATCH 048/427] [Templating] [Template] Render a block with the `#[Template]` attribute --- templates.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/templates.rst b/templates.rst index 795ac3a7ac3..1af3de56c5b 100644 --- a/templates.rst +++ b/templates.rst @@ -632,6 +632,31 @@ This might come handy when dealing with blocks in :ref:`templates inheritance ` or when using `Turbo Streams`_. +Similarly, you can use the ``#[Template]`` attribute on the controller to specify a block +to render:: + + // src/Controller/ProductController.php + namespace App\Controller; + + use Symfony\Bridge\Twig\Attribute\Template; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; + + class ProductController extends AbstractController + { + #[Template('product.html.twig', block: 'price_block')] + public function price(): array + { + return [ + // ... + ]; + } + } + +.. versionadded:: 7.2 + + The ``#[Template]`` attribute's ``block`` argument was introduced in Symfony 7.2. + Rendering a Template in Services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From d158b5544cb173ea520724e56df2a1ba1c8c84c0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 26 Aug 2024 09:19:25 +0200 Subject: [PATCH 049/427] Minor tweak --- templates.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates.rst b/templates.rst index 1af3de56c5b..2379a3568dc 100644 --- a/templates.rst +++ b/templates.rst @@ -632,8 +632,8 @@ This might come handy when dealing with blocks in :ref:`templates inheritance ` or when using `Turbo Streams`_. -Similarly, you can use the ``#[Template]`` attribute on the controller to specify a block -to render:: +Similarly, you can use the ``#[Template]`` attribute on the controller to specify +a block to render:: // src/Controller/ProductController.php namespace App\Controller; From bec9e5faa881623aa75a03a78212315f44799a43 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 22 Aug 2024 14:16:06 +0200 Subject: [PATCH 050/427] [Validator] Add `CompoundConstraintTestCase` to ease testing Compound Constraints --- validation/custom_constraint.rst | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index 9f0ca4ca07b..4504ceb4012 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -502,6 +502,9 @@ A class constraint validator must be applied to the class itself: Testing Custom Constraints -------------------------- +Atomic Constraints +~~~~~~~~~~~~~~~~~~ + Use the :class:`Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase` class to simplify writing unit tests for your custom constraints:: @@ -545,3 +548,74 @@ class to simplify writing unit tests for your custom constraints:: // ... } } + +Compound Constraints +~~~~~~~~~~~~~~~~~~~~ + +Let's say you create a compound constraint that checks if a string meets +your minimum requirements for your password policy:: + + // src/Validator/PasswordRequirements.php + namespace App\Validator; + + use Symfony\Component\Validator\Constraints as Assert; + + #[\Attribute] + class PasswordRequirements extends Assert\Compound + { + protected function getConstraints(array $options): array + { + return [ + new Assert\NotBlank(allowNull: false), + new Assert\Length(min: 8, max: 255), + new Assert\NotCompromisedPassword(), + new Assert\Type('string'), + new Assert\Regex('/[A-Z]+/'), + ]; + } + } + +You can use the :class:`Symfony\\Component\\Validator\\Test\\CompoundConstraintTestCase` +class to check precisely which of the constraints failed to pass:: + + // tests/Validator/PasswordRequirementsTest.php + namespace App\Tests\Validator; + + use App\Validator\PasswordRequirements; + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Test\CompoundConstraintTestCase; + + /** + * @extends CompoundConstraintTestCase + */ + class PasswordRequirementsTest extends CompoundConstraintTestCase + { + public function createCompound(): Assert\Compound + { + return new PasswordRequirements(); + } + + public function testInvalidPassword(): void + { + $this->validateValue('azerty123'); + + // check all constraints pass except for the + // password leak and the uppercase letter checks + $this->assertViolationsRaisedByCompound([ + new Assert\NotCompromisedPassword(), + new Assert\Regex('/[A-Z]+/'), + ]); + } + + public function testValid(): void + { + $this->validateValue('VERYSTR0NGP4$$WORD#%!'); + + $this->assertNoViolation(); + } + } + +.. versionadded:: 7.2 + + The :class:`Symfony\\Component\\Validator\\Test\\CompoundConstraintTestCase` + class was introduced in Symfony 7.2. From 3f0fdbad1f95f056c576e2d34f1576c4fe27c720 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 26 Aug 2024 10:21:56 +0200 Subject: [PATCH 051/427] Tweaks --- reference/constraints/Week.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/reference/constraints/Week.rst b/reference/constraints/Week.rst index 0aea71bee02..26d82777636 100644 --- a/reference/constraints/Week.rst +++ b/reference/constraints/Week.rst @@ -5,10 +5,9 @@ Week The ``Week`` constraint was introduced in Symfony 7.2. -Validates that a string (or an object implementing the ``Stringable`` PHP interface) -matches a given week number. The week number format is defined by `ISO-8601`_ -and should be composed of the year and the week number, separated by a hyphen -(e.g. ``2022-W01``). +Validates that a given string (or an object implementing the ``Stringable`` PHP +interface) represents a valid week number according to the `ISO-8601`_ standard +(e.g. ``2025-W01``). ========== ======================================================================= Applies to :ref:`property or method ` @@ -87,10 +86,11 @@ the following: } } -.. note:: - - The constraint also checks that the given week exists in the calendar. For example, - ``2022-W53`` is not a valid week number for 2022, because 2022 only had 52 weeks. +This constraint not only checks that the value matches the week number pattern, +but it also verifies that the specified week actually exists in the calendar. +According to the ISO-8601 standard, years can have either 52 or 53 weeks. For example, +``2022-W53`` is not a valid because 2022 only had 52 weeks; but ``2020-W53`` is +valid because 2020 had 53 weeks. Options ------- @@ -169,4 +169,4 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -.. _ISO-8601: https://en.wikipedia.org/wiki/ISO_8601 +.. _`ISO-8601`: https://en.wikipedia.org/wiki/ISO_8601 From 34d159469bd81267e3ae9cfe8d2b65993fd148f1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 26 Aug 2024 10:57:07 +0200 Subject: [PATCH 052/427] Minor tweak --- validation/custom_constraint.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index 4504ceb4012..435b976d1d3 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -552,8 +552,8 @@ class to simplify writing unit tests for your custom constraints:: Compound Constraints ~~~~~~~~~~~~~~~~~~~~ -Let's say you create a compound constraint that checks if a string meets -your minimum requirements for your password policy:: +Consider the following compound constraint that checks if a string meets +the minimum requirements for your password policy:: // src/Validator/PasswordRequirements.php namespace App\Validator; From 41f17860c70df6743740b8c5a0aff21606cee7ac Mon Sep 17 00:00:00 2001 From: eltharin Date: Thu, 15 Aug 2024 15:21:16 +0200 Subject: [PATCH 053/427] [Scheduler] Add capability to skip missed periodic tasks, only the last schedule will be called --- scheduler.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/scheduler.rst b/scheduler.rst index c890b1a1aec..be4f2ca138d 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -889,6 +889,27 @@ This allows the system to retain the state of the schedule, ensuring that when a } } +With ``stateful`` option, All missed messages will be handled, If you nedd handle your message only once you can use the ``processOnlyLastMissedRun`` option.:: + + // src/Scheduler/SaleTaskProvider.php + namespace App\Scheduler; + + #[AsSchedule('uptoyou')] + class SaleTaskProvider implements ScheduleProviderInterface + { + public function getSchedule(): Schedule + { + $this->removeOldReports = RecurringMessage::cron('3 8 * * 1', new CleanUpOldSalesReport()); + + return $this->schedule ??= (new Schedule()) + ->with( + // ... + ) + ->stateful($this->cache) + ->processOnlyLastMissedRun(true) + } + } + To scale your schedules more effectively, you can use multiple workers. In such cases, a good practice is to add a :doc:`lock ` to prevent the same task more than once:: From 0f91311c8572b58c69097b901c7d76cf03ac993a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 26 Aug 2024 12:50:13 +0200 Subject: [PATCH 054/427] Minor tweaks --- scheduler.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scheduler.rst b/scheduler.rst index be4f2ca138d..081f4efd498 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -869,7 +869,8 @@ While this behavior may not necessarily pose a problem, there is a possibility t That's why the scheduler allows to remember the last execution date of a message via the ``stateful`` option (and the :doc:`Cache component `). -This allows the system to retain the state of the schedule, ensuring that when a worker is restarted, it resumes from the point it left off.:: +This allows the system to retain the state of the schedule, ensuring that when a +worker is restarted, it resumes from the point it left off:: // src/Scheduler/SaleTaskProvider.php namespace App\Scheduler; @@ -889,7 +890,8 @@ This allows the system to retain the state of the schedule, ensuring that when a } } -With ``stateful`` option, All missed messages will be handled, If you nedd handle your message only once you can use the ``processOnlyLastMissedRun`` option.:: +With the ``stateful`` option, all missed messages will be handled. If you need to +handle a message only once, you can use the ``processOnlyLastMissedRun`` option:: // src/Scheduler/SaleTaskProvider.php namespace App\Scheduler; @@ -910,6 +912,10 @@ With ``stateful`` option, All missed messages will be handled, If you nedd handl } } +.. versionadded:: 7.2 + + The ``processOnlyLastMissedRun`` option was introduced in Symfony 7.2. + To scale your schedules more effectively, you can use multiple workers. In such cases, a good practice is to add a :doc:`lock ` to prevent the same task more than once:: From 23838fd198c9a98731567284306d56b6c78f7e32 Mon Sep 17 00:00:00 2001 From: Thibaut THOUEMENT Date: Fri, 23 Aug 2024 22:10:10 +0200 Subject: [PATCH 055/427] [Validator] Add errorPath to Unique constraint --- reference/constraints/Unique.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index 8954f455086..7c4f78cfcc3 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -170,6 +170,15 @@ collection:: .. include:: /reference/constraints/_groups-option.rst.inc +``errorPath`` +~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +This option allows you to define a custom path for your message. +``#[Assert\Unique(fields: ['latitude', 'longitude'], errorPath: 'point_of_interest')]`` +Instead of ``0: "Error message"``, it will be : ``0.point_of_interest: "Error message"`` + ``message`` ~~~~~~~~~~~ From 03713d55356555cf5933daa8bc1cbe821ccf1591 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 26 Aug 2024 16:58:22 +0200 Subject: [PATCH 056/427] Reword --- reference/constraints/Unique.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index 7c4f78cfcc3..68754738271 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -175,9 +175,16 @@ collection:: **type**: ``string`` **default**: ``null`` -This option allows you to define a custom path for your message. -``#[Assert\Unique(fields: ['latitude', 'longitude'], errorPath: 'point_of_interest')]`` -Instead of ``0: "Error message"``, it will be : ``0.point_of_interest: "Error message"`` +.. versionadded:: 7.2 + + The ``errorPath`` option was introduced in Symfony 7.2. + +If a validation error occurs, the error message is, by default, bound to the +first element in the collection. Use this option to bind the error message to a +specific field within the first item of the collection. + +The value of this option must use any :doc:`valid PropertyAccess syntax ` +(e.g. ``'point_of_interest'``, ``'user.email'``). ``message`` ~~~~~~~~~~~ From 45ba59fd12b5db3fa49a6cb6ac38683d9119442b Mon Sep 17 00:00:00 2001 From: Ahmed Ghanem <124502255+ahmedghanem00@users.noreply.github.com> Date: Mon, 29 Jul 2024 02:56:36 +0300 Subject: [PATCH 057/427] [Notifier] Create `DesktopChannel` and `JoliNotif` bridge --- notifier.rst | 84 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index 6d506910ead..4df4590235e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -16,8 +16,8 @@ Get the Notifier installed using: .. _channels-chatters-texters-email-and-browser: -Channels: Chatters, Texters, Email, Browser and Push ----------------------------------------------------- +Channels: Chatters, Texters, Email, Browser, Push and Desktop +------------------------------------------------------------- The notifier component can send notifications to different channels. Each channel can integrate with different providers (e.g. Slack or Twilio SMS) @@ -32,6 +32,7 @@ The notifier component supports the following channels: * :ref:`Email channel ` integrates the :doc:`Symfony Mailer `; * Browser channel uses :ref:`flash messages `. * :ref:`Push channel ` sends notifications to phones and browsers via push notifications. +* :ref:`Desktop channel ` displays desktop notifications on the same host machine. .. tip:: @@ -623,6 +624,79 @@ configure the ``texter_transports``: ; }; +.. _notifier-desktop-channel: + +Desktop Channel +~~~~~~~~~~~~~~~ + +The desktop channel is used to display desktop notifications on the same host machine using +:class:`Symfony\\Component\\Notifier\\Texter` classes. Currently, Symfony +is integrated with the following providers: + +=============== ==================================== ============================================================================== +Provider Package DSN +=============== ==================================== ============================================================================== +`JoliNotif`_ ``symfony/joli-notif-notifier`` ``jolinotif://default`` +=============== ==================================== ============================================================================== + +.. versionadded: 7.2 + + The JoliNotif bridge was introduced in Symfony 7.2. + +To enable a texter, add the correct DSN in your ``.env`` file and +configure the ``texter_transports``: + +.. code-block:: bash + + # .env + JOLINOTIF=jolinotif://default + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/notifier.yaml + framework: + notifier: + texter_transports: + jolinotif: '%env(JOLINOTIF)%' + + .. code-block:: xml + + + + + + + + + %env(JOLINOTIF)% + + + + + + .. code-block:: php + + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework): void { + $framework->notifier() + ->texterTransport('jolinotif', env('JOLINOTIF')) + ; + }; + +.. versionadded:: 7.2 + + The ``Desktop`` channel was introduced in Symfony 7.2. + Configure to use Failover or Round-Robin Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -926,9 +1000,10 @@ and its ``asChatMessage()`` method:: The :class:`Symfony\\Component\\Notifier\\Notification\\SmsNotificationInterface`, -:class:`Symfony\\Component\\Notifier\\Notification\\EmailNotificationInterface` -and +:class:`Symfony\\Component\\Notifier\\Notification\\EmailNotificationInterface`, :class:`Symfony\\Component\\Notifier\\Notification\\PushNotificationInterface` +and +:class:`Symfony\\Component\\Notifier\\Notification\\DesktopNotificationInterface` also exists to modify messages sent to those channels. Customize Browser Notifications (Flash Messages) @@ -1114,6 +1189,7 @@ is dispatched. Listeners receive a .. _`Infobip`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Infobip/README.md .. _`Iqsms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Iqsms/README.md .. _`iSendPro`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Isendpro/README.md +.. _`JoliNotif`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/JoliNotif/README.md .. _`KazInfoTeh`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/KazInfoTeh/README.md .. _`LINE Notify`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LineNotify/README.md .. _`LightSms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LightSms/README.md From cc4de4e630189e65ca2e74f98b469d18d20aca28 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 28 Aug 2024 13:13:14 +0200 Subject: [PATCH 058/427] Keep a reference to not break existing links --- notifier.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/notifier.rst b/notifier.rst index 4df4590235e..5f38a078f4c 100644 --- a/notifier.rst +++ b/notifier.rst @@ -15,6 +15,7 @@ Get the Notifier installed using: $ composer require symfony/notifier .. _channels-chatters-texters-email-and-browser: +.. _channels-chatters-texters-email-browser-and-push: Channels: Chatters, Texters, Email, Browser, Push and Desktop ------------------------------------------------------------- From 0c1a63900ab6ac2aa0f3848541f11ef47b932232 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 2 Sep 2024 13:55:32 +0200 Subject: [PATCH 059/427] fix typo --- reference/constraints/Week.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Week.rst b/reference/constraints/Week.rst index 26d82777636..f107d8b4192 100644 --- a/reference/constraints/Week.rst +++ b/reference/constraints/Week.rst @@ -89,7 +89,7 @@ the following: This constraint not only checks that the value matches the week number pattern, but it also verifies that the specified week actually exists in the calendar. According to the ISO-8601 standard, years can have either 52 or 53 weeks. For example, -``2022-W53`` is not a valid because 2022 only had 52 weeks; but ``2020-W53`` is +``2022-W53`` is not valid because 2022 only had 52 weeks; but ``2020-W53`` is valid because 2020 had 53 weeks. Options From 31a33bf2d9e5929f834d25cfad93ac21852bf9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Geffroy?= <81738559+raphael-geffroy@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:53:21 +0200 Subject: [PATCH 060/427] [FrameworkBundle] Remove default value for `gc_probability` config option --- reference/configuration/framework.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 1e9e43faa0f..c3f341f578b 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1845,13 +1845,19 @@ If not set, ``php.ini``'s `session.gc_divisor`_ directive will be relied on. gc_probability .............. -**type**: ``integer`` **default**: ``1`` +**type**: ``integer`` This defines the probability that the garbage collector (GC) process is started on every session initialization. The probability is calculated by using ``gc_probability`` / ``gc_divisor``, e.g. 1/100 means there is a 1% chance that the GC process will start on each request. +If not set, ``php.ini``'s `session.gc_probability`_ directive will be relied on. + +.. versionadded:: 7.2 + + Relying on ``php.ini``'s directive as default for ``gc_probability`` was introduced in symfony 7.2. + gc_maxlifetime .............. @@ -3893,6 +3899,7 @@ The attributes can also be added to interfaces directly:: .. _`session.cookie_samesite`: https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-samesite .. _`session.cookie_secure`: https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-secure .. _`session.gc_divisor`: https://www.php.net/manual/en/session.configuration.php#ini.session.gc-divisor +.. _`session.gc_probability`: https://www.php.net/manual/en/session.configuration.php#ini.session.gc-probability .. _`session.gc_maxlifetime`: https://www.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime .. _`session.sid_length`: https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length .. _`session.sid_bits_per_character`: https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character From 5c72f37bca564690a8af6f9797f3eed7e91d0cd8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 9 Sep 2024 08:42:30 +0200 Subject: [PATCH 061/427] Minor tweak --- reference/configuration/framework.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index c3f341f578b..bdcbc4a55af 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1852,11 +1852,13 @@ started on every session initialization. The probability is calculated by using ``gc_probability`` / ``gc_divisor``, e.g. 1/100 means there is a 1% chance that the GC process will start on each request. -If not set, ``php.ini``'s `session.gc_probability`_ directive will be relied on. +If not set, Symfony will use the value of the `session.gc_probability`_ directive +in the ``php.ini`` configuration file. .. versionadded:: 7.2 - Relying on ``php.ini``'s directive as default for ``gc_probability`` was introduced in symfony 7.2. + Relying on ``php.ini``'s directive as default for ``gc_probability`` was + introduced in Symfony 7.2. gc_maxlifetime .............. From e425caf94ceb2d7336a5aff5e7832529d6ce8ebd Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 12 Sep 2024 22:39:59 -0400 Subject: [PATCH 062/427] [Mailer] add Mailtrap docs --- mailer.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index 21032732c4b..a8d0eda3072 100644 --- a/mailer.rst +++ b/mailer.rst @@ -109,6 +109,7 @@ Service Install with Webhook su `Mailomat`_ ``composer require symfony/mailomat-mailer`` yes `MailPace`_ ``composer require symfony/mail-pace-mailer`` `MailerSend`_ ``composer require symfony/mailer-send-mailer`` +`Mailtrap`_ ``composer require symfony/mailtrap-mailer`` `Mandrill`_ ``composer require symfony/mailchimp-mailer`` `Postal`_ ``composer require symfony/postal-mailer`` `Postmark`_ ``composer require symfony/postmark-mailer`` yes @@ -124,7 +125,7 @@ Service Install with Webhook su .. versionadded:: 7.2 - The Mailomat, Postal and Sweego integrations were introduced in Symfony 7.2. + The Mailomat, Mailtrap, Postal and Sweego integrations were introduced in Symfony 7.2. .. note:: @@ -216,6 +217,10 @@ party provider: | | - HTTP n/a | | | - API ``mailpace+api://API_TOKEN@default`` | +------------------------+---------------------------------------------------------+ +| `Mailtrap`_ | - SMTP ``mailtrap+smtp://PASSWORD@default`` | +| | - HTTP n/a | +| | - API ``mailtrap+api://API_TOKEN@default`` | ++------------------------+---------------------------------------------------------+ | `Postal`_ | - SMTP n/a | | | - HTTP n/a | | | - API ``postal+api://API_KEY@BASE_URL`` | @@ -1581,6 +1586,7 @@ The following transports currently support tags and metadata: * Brevo * Mailgun +* Mailtrap * Mandrill * Postmark * Sendgrid @@ -2000,6 +2006,7 @@ the :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait`:: .. _`PEM encoded`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail .. _`Postal`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Postal/README.md .. _`Postmark`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Postmark/README.md +.. _`Mailtrap`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailtrap/README.md .. _`Resend`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Resend/README.md .. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt .. _`S/MIME`: https://en.wikipedia.org/wiki/S/MIME From 4dc4e9d75724eb3874149e7a5455f81dce17cdef Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 17 Sep 2024 10:53:05 +0200 Subject: [PATCH 063/427] Minor tweak --- reference/configuration/framework.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 80c1944eea1..19f72bb6cb3 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1884,7 +1884,8 @@ If not set, ``php.ini``'s `session.sid_length`_ directive will be relied on. .. deprecated:: 7.2 - The ``sid_length`` option was deprecated in Symfony 7.2. + The ``sid_length`` option was deprecated in Symfony 7.2. No alternative is + provided as PHP 8.4 has deprecated the related option. sid_bits_per_character ...................... @@ -1900,7 +1901,8 @@ If not set, ``php.ini``'s `session.sid_bits_per_character`_ directive will be re .. deprecated:: 7.2 - The ``sid_bits_per_character`` option was deprecated in Symfony 7.2. + The ``sid_bits_per_character`` option was deprecated in Symfony 7.2. No alternative + is provided as PHP 8.4 has deprecated the related option. save_path ......... From 36a7c6dd137a8e819360be1b7e107732b0cdd04b Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 17 Sep 2024 14:31:19 +0200 Subject: [PATCH 064/427] [Uid] Add the `Uuid::FORMAT_RFC_9562` constant --- components/uid.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/uid.rst b/components/uid.rst index feb58968347..73974ef8732 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -329,6 +329,7 @@ The following constants are available: * ``Uuid::FORMAT_BASE_32`` * ``Uuid::FORMAT_BASE_58`` * ``Uuid::FORMAT_RFC_4122`` +* ``Uuid::FORMAT_RFC_9562`` (equivalent to ``Uuid::FORMAT_RFC_4122``) You can also use the ``Uuid::FORMAT_ALL`` constant to accept any UUID format. By default, only the RFC 4122 format is accepted. From 7a8d0c44f97540e3ef80df087828174f5c8ebec9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Sep 2024 09:12:56 +0200 Subject: [PATCH 065/427] [Translation] Mention the support of segment attributes in XLIFF --- reference/formats/xliff.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/reference/formats/xliff.rst b/reference/formats/xliff.rst index acb9af36014..b5dc99b4186 100644 --- a/reference/formats/xliff.rst +++ b/reference/formats/xliff.rst @@ -29,7 +29,7 @@ loaded/dumped inside a Symfony application: true user login - + original-content translated-content @@ -37,4 +37,8 @@ loaded/dumped inside a Symfony application: +.. versionadded:: 7.2 + + The support of attributes in the ```` element was introduced in Symfony 7.2. + .. _XLIFF: https://docs.oasis-open.org/xliff/xliff-core/v2.1/xliff-core-v2.1.html From d971cea1c706ff93df2c16bedfd7c0223a5514a8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Sep 2024 13:30:17 +0200 Subject: [PATCH 066/427] =?UTF-8?q?[HttpFoundation]=C2=A0Document=20the=20?= =?UTF-8?q?PRIVATE=5FSUBNETS=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deployment/proxies.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 40c2550ee2c..fc6f855451d 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -143,9 +143,17 @@ In this case, you'll need to - *very carefully* - trust *all* proxies. framework: # ... # trust *all* requests (the 'REMOTE_ADDR' string is replaced at - # run time by $_SERVER['REMOTE_ADDR']) + # runtime by $_SERVER['REMOTE_ADDR']) trusted_proxies: '127.0.0.1,REMOTE_ADDR' + # you can also use the 'PRIVATE_SUBNETS' string, which is replaced at + # runtime by the IpUtils::PRIVATE_SUBNETS constant + # trusted_proxies: '127.0.0.1,PRIVATE_SUBNETS' + +.. versionadded:: 7.2 + + The support for the ``'PRIVATE_SUBNETS'`` string was introduced in Symfony 7.2. + That's it! It's critical that you prevent traffic from all non-trusted sources. If you allow outside traffic, they could "spoof" their true IP address and other information. From 7573d4a1211c81ae08d2ca26df5311322c45bb0b Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 19 Sep 2024 10:11:30 +0200 Subject: [PATCH 067/427] [Security] Allow passport attributes in `Security::login()` --- security.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/security.rst b/security.rst index a8aa652a222..51ee9b5c3fb 100644 --- a/security.rst +++ b/security.rst @@ -1767,9 +1767,12 @@ You can log in a user programmatically using the ``login()`` method of the // you can also log in on a different firewall... $security->login($user, 'form_login', 'other_firewall'); - // ...and add badges + // ... add badges... $security->login($user, 'form_login', 'other_firewall', [(new RememberMeBadge())->enable()]); + // ... and also add passport attributes + $security->login($user, 'form_login', 'other_firewall', [(new RememberMeBadge())->enable()], ['referer' => 'https://oauth.example.com']); + // use the redirection logic applied to regular login $redirectResponse = $security->login($user); return $redirectResponse; @@ -1779,6 +1782,12 @@ You can log in a user programmatically using the ``login()`` method of the } } +.. versionadded:: 7.2 + + The support for passport attributes in the + :method:`Symfony\\Bundle\\SecurityBundle\\Security::login` method was + introduced in Symfony 7.2. + .. _security-logging-out: Logging Out From b0a91ce7a24f40b52d6732d32fc1dad28043a964 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Sep 2024 09:00:51 +0200 Subject: [PATCH 068/427] [String] Document the Spanish inflector --- string.rst | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/string.rst b/string.rst index f2856976986..cb822e1dbd1 100644 --- a/string.rst +++ b/string.rst @@ -820,11 +820,28 @@ class to convert English words from/to singular/plural with confidence:: The value returned by both methods is always an array because sometimes it's not possible to determine a unique singular/plural form for the given word. +Symfony also provides inflectors for other languages:: + + use Symfony\Component\String\Inflector\FrenchInflector; + + $inflector = new FrenchInflector(); + $result = $inflector->singularize('souris'); // ['souris'] + $result = $inflector->pluralize('hôpital'); // ['hôpitaux'] + + use Symfony\Component\String\Inflector\SpanishInflector; + + $inflector = new SpanishInflector(); + $result = $inflector->singularize('aviones'); // ['avión'] + $result = $inflector->pluralize('miércoles'); // ['miércoles'] + +.. versionadded:: 7.2 + + The ``SpanishInflector`` class was introduced in Symfony 7.2. + .. note:: - Symfony also provides a :class:`Symfony\\Component\\String\\Inflector\\FrenchInflector` - and an :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface` if - you need to implement your own inflector. + Symfony provides a :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface` + in case you need to implement your own inflector. .. _`ASCII`: https://en.wikipedia.org/wiki/ASCII .. _`Unicode`: https://en.wikipedia.org/wiki/Unicode From 3983e81d511ced672866601c191f4ec780492634 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 20 Sep 2024 16:59:19 +0200 Subject: [PATCH 069/427] fix typo --- string.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/string.rst b/string.rst index da82791c740..37f64bc4f3b 100644 --- a/string.rst +++ b/string.rst @@ -674,7 +674,7 @@ Symfony also provides inflectors for other languages:: .. note:: - Symfony provides a :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface` + Symfony provides an :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface` in case you need to implement your own inflector. .. _`ASCII`: https://en.wikipedia.org/wiki/ASCII From fdda76fe73d83158eba51bbff5798ddd38ccf1ef Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Sep 2024 12:41:59 +0200 Subject: [PATCH 070/427] [FrameworkBundle] Document the `resolve-env-vars` option of `lint:container` command --- service_container.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/service_container.rst b/service_container.rst index 9e1cdff2098..f329587eb54 100644 --- a/service_container.rst +++ b/service_container.rst @@ -1069,6 +1069,14 @@ application to production (e.g. in your continuous integration server): $ php bin/console lint:container + # optionally, you can force the resolution of environment variables; + # the command will fail if any of those environment variables are missing + $ php bin/console lint:container --resolve-env-vars + +.. versionadded:: 7.2 + + The ``--resolve-env-vars`` option was introduced in Symfony 7.2. + Performing those checks whenever the container is compiled can hurt performance. That's why they are implemented in :doc:`compiler passes ` called ``CheckTypeDeclarationsPass`` and ``CheckAliasValidityPass``, which are From a78ff470d7019a3cbf550ed3a7412340e18992e7 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sun, 22 Sep 2024 11:34:16 -0400 Subject: [PATCH 071/427] documenting non-empty parameters --- configuration.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/configuration.rst b/configuration.rst index 36dceae1b71..52dc9b98c95 100644 --- a/configuration.rst +++ b/configuration.rst @@ -382,6 +382,25 @@ a new ``locale`` parameter is added to the ``config/services.yaml`` file). They are useful when working with :ref:`Compiler Passes ` to declare some temporary parameters that won't be available later in the application. +Configuration parameters are usually validation-free, but you can ensure that +essential parameters for your application's functionality are not empty:: + + // ContainerBuilder + $container->parameterCannotBeEmpty('app.private_key', 'Did you forget to configure a non-empty value for "app.private_key" parameter?'); + +If a non-empty parameter is ``null``, an empty string ``''``, or an empty array ``[]``, +Symfony will throw an exception with the custom error message when attempting to +retrieve the value of this parameter. + +.. versionadded:: 7.2 + + Validating non-empty parameters was introduced in Symfony 7.2. + +.. note:: + + Please note that this validation will *only* occur if a non-empty parameter value + is retrieved; otherwise, no exception will be thrown. + .. seealso:: Later in this article you can read how to From 2492dd1a3dc9df692c3061009ba9d21bd9ef8b16 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 23 Sep 2024 08:56:16 +0200 Subject: [PATCH 072/427] [Console] Document the silent verbosity level --- components/console/usage.rst | 8 ++++++++ console/input.rst | 7 ++++++- console/verbosity.rst | 23 ++++++++++++++++++++--- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/components/console/usage.rst b/components/console/usage.rst index d7725e8926e..591994948b8 100644 --- a/components/console/usage.rst +++ b/components/console/usage.rst @@ -65,9 +65,17 @@ You can suppress output with: .. code-block:: terminal + # suppresses all output, including errors + $ php application.php list --silent + + # suppresses all output except errors $ php application.php list --quiet $ php application.php list -q +.. versionadded:: 7.2 + + The ``--silent`` option was introduced in Symfony 7.2. + You can get more verbose messages (if this is supported for a command) with: diff --git a/console/input.rst b/console/input.rst index 6e7fc85a055..c038ace56fc 100644 --- a/console/input.rst +++ b/console/input.rst @@ -446,12 +446,17 @@ The Console component adds some predefined options to all commands: * ``--verbose``: sets the verbosity level (e.g. ``1`` the default, ``2`` and ``3``, or you can use respective shortcuts ``-v``, ``-vv`` and ``-vvv``) -* ``--quiet``: disables output and interaction +* ``--silent``: disables all output and interaction, including errors +* ``--quiet``: disables output and interaction, but errors are still displayed * ``--no-interaction``: disables interaction * ``--version``: outputs the version number of the console application * ``--help``: displays the command help * ``--ansi|--no-ansi``: whether to force of disable coloring the output +.. versionadded:: 7.2 + + The ``--silent`` option was introduced in Symfony 7.2. + When using the ``FrameworkBundle``, two more options are predefined: * ``--env``: sets the Kernel configuration environment (defaults to ``APP_ENV``) diff --git a/console/verbosity.rst b/console/verbosity.rst index f7a1a1e5e59..9910dca0c3d 100644 --- a/console/verbosity.rst +++ b/console/verbosity.rst @@ -7,7 +7,10 @@ messages, but you can control their verbosity with the ``-q`` and ``-v`` options .. code-block:: terminal - # do not output any message (not even the command result messages) + # suppress all output, including errors + $ php bin/console some-command --silent + + # suppress all output (even the command result messages) but display errors $ php bin/console some-command -q $ php bin/console some-command --quiet @@ -23,6 +26,10 @@ messages, but you can control their verbosity with the ``-q`` and ``-v`` options # display all messages (useful to debug errors) $ php bin/console some-command -vvv +.. versionadded:: 7.2 + + The ``--silent`` option was introduced in Symfony 7.2. + The verbosity level can also be controlled globally for all commands with the ``SHELL_VERBOSITY`` environment variable (the ``-q`` and ``-v`` options still have more precedence over the value of ``SHELL_VERBOSITY``): @@ -30,6 +37,7 @@ have more precedence over the value of ``SHELL_VERBOSITY``): ===================== ========================= =========================================== Console option ``SHELL_VERBOSITY`` value Equivalent PHP constant ===================== ========================= =========================================== +``--silent`` ``-2`` ``OutputInterface::VERBOSITY_SILENT`` ``-q`` or ``--quiet`` ``-1`` ``OutputInterface::VERBOSITY_QUIET`` (none) ``0`` ``OutputInterface::VERBOSITY_NORMAL`` ``-v`` ``1`` ``OutputInterface::VERBOSITY_VERBOSE`` @@ -58,7 +66,7 @@ level. For example:: 'Password: '.$input->getArgument('password'), ]); - // available methods: ->isQuiet(), ->isVerbose(), ->isVeryVerbose(), ->isDebug() + // available methods: ->isSilent(), ->isQuiet(), ->isVerbose(), ->isVeryVerbose(), ->isDebug() if ($output->isVerbose()) { $output->writeln('User class: '.get_class($user)); } @@ -73,10 +81,19 @@ level. For example:: } } -When the quiet level is used, all output is suppressed as the default +.. versionadded:: 7.2 + + The ``isSilent()`` method was introduced in Symfony 7.2. + +When the silent or quiet level are used, all output is suppressed as the default :method:`Symfony\\Component\\Console\\Output\\Output::write` method returns without actually printing. +.. tip:: + + When using the ``silent`` verbosity, errors won't be displayed in the console + but they will still be logged through the :doc:`Symfony logger ` integration. + .. tip:: The MonologBridge provides a :class:`Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler` From ecb343bf576206de34d57a190447b1128684d8cf Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Fri, 27 Sep 2024 13:05:03 +0200 Subject: [PATCH 073/427] [Webhook] add Mailtrap webhook docs --- webhook.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webhook.rst b/webhook.rst index 176abc49cd2..e2c7083ac43 100644 --- a/webhook.rst +++ b/webhook.rst @@ -28,6 +28,7 @@ MailerSend ``mailer.webhook.request_parser.mailersend`` Mailgun ``mailer.webhook.request_parser.mailgun`` Mailjet ``mailer.webhook.request_parser.mailjet`` Mailomat ``mailer.webhook.request_parser.mailomat`` +Mailtrap ``mailer.webhook.request_parser.mailtrap`` Postmark ``mailer.webhook.request_parser.postmark`` Resend ``mailer.webhook.request_parser.resend`` Sendgrid ``mailer.webhook.request_parser.sendgrid`` @@ -40,7 +41,8 @@ Sweego ``mailer.webhook.request_parser.sweego`` .. versionadded:: 7.2 - The ``Mailomat`` and ``Sweego`` integrations were introduced in Symfony 7.2. + The ``Mailomat``, ``Mailtrap``, and ``Sweego`` integrations were introduced in + Symfony 7.2. .. note:: From 0bb5a68545d695d7bf9f9ec31843920756ffdf44 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 30 Sep 2024 09:51:52 +0200 Subject: [PATCH 074/427] [String] Add the `AbstractString::kebab()` method --- string.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/string.rst b/string.rst index f2856976986..d9fdeded470 100644 --- a/string.rst +++ b/string.rst @@ -232,6 +232,8 @@ Methods to Change Case u('Foo: Bar-baz.')->camel(); // 'fooBarBaz' // changes all graphemes/code points to snake_case u('Foo: Bar-baz.')->snake(); // 'foo_bar_baz' + // changes all graphemes/code points to kebab-case + u('Foo: Bar-baz.')->kebab(); // 'foo-bar-baz' // other cases can be achieved by chaining methods. E.g. PascalCase: u('Foo: Bar-baz.')->camel()->title(); // 'FooBarBaz' @@ -240,6 +242,10 @@ Methods to Change Case The ``localeLower()``, ``localeUpper()`` and ``localeTitle()`` methods were introduced in Symfony 7.1. +.. versionadded:: 7.2 + + The ``kebab()`` method was introduced in Symfony 7.2. + The methods of all string classes are case-sensitive by default. You can perform case-insensitive operations with the ``ignoreCase()`` method:: From d810f6caabcc1960f5e3d7ffde08a44fa2733fb1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 30 Sep 2024 10:09:10 +0200 Subject: [PATCH 075/427] Minor tweaks --- configuration.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/configuration.rst b/configuration.rst index 52dc9b98c95..5ebe952740e 100644 --- a/configuration.rst +++ b/configuration.rst @@ -385,22 +385,17 @@ a new ``locale`` parameter is added to the ``config/services.yaml`` file). Configuration parameters are usually validation-free, but you can ensure that essential parameters for your application's functionality are not empty:: - // ContainerBuilder - $container->parameterCannotBeEmpty('app.private_key', 'Did you forget to configure a non-empty value for "app.private_key" parameter?'); + /** @var ContainerBuilder $container */ + $container->parameterCannotBeEmpty('app.private_key', 'Did you forget to set a value for the "app.private_key" parameter?'); If a non-empty parameter is ``null``, an empty string ``''``, or an empty array ``[]``, -Symfony will throw an exception with the custom error message when attempting to -retrieve the value of this parameter. +Symfony will throw an exception. This validation is **not** made at compile time +but when attempting to retrieve the value of the parameter. .. versionadded:: 7.2 Validating non-empty parameters was introduced in Symfony 7.2. -.. note:: - - Please note that this validation will *only* occur if a non-empty parameter value - is retrieved; otherwise, no exception will be thrown. - .. seealso:: Later in this article you can read how to From a3815364478bdf7d2569655a1092880f06bfc94d Mon Sep 17 00:00:00 2001 From: Pierre Rineau Date: Fri, 28 Jun 2024 12:34:40 +0200 Subject: [PATCH 076/427] [Messenger] document the #[AsMessage] attribute --- messenger.rst | 49 ++++++++++++++++++++++++++++++++++++++++ reference/attributes.rst | 1 + 2 files changed, 50 insertions(+) diff --git a/messenger.rst b/messenger.rst index cecb84d9dec..8ba335b4e2b 100644 --- a/messenger.rst +++ b/messenger.rst @@ -345,6 +345,55 @@ to multiple transports: name as its only argument. For more information about stamps, see `Envelopes & Stamps`_. +.. _messenger-message-attribute: + +Configuring Routing Using Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can optionally use the `#[AsMessage]` attribute to configure message transport:: + + // src/Message/SmsNotification.php + namespace App\Message; + + use Symfony\Component\Messenger\Attribute\AsMessage; + + #[AsMessage(transport: 'async')] + class SmsNotification + { + public function __construct( + private string $content, + ) { + } + + public function getContent(): string + { + return $this->content; + } + } + +.. note:: + + If you configure routing with both configuration and attributes, the + configuration will take precedence over the attributes and override + them. This allows to override routing on a per-environment basis + for example: + + .. code-block:: yaml + + # config/packages/messenger.yaml + when@dev: + framework: + messenger: + routing: + # override class attribute + 'App\Message\SmsNotification': sync + +.. tip:: + + The `$transport` parameter can be either a `string` or an `array`: configuring multiple + transports is possible. You may also repeat the attribute if you prefer instead of using + an array. + Doctrine Entities in Messages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/attributes.rst b/reference/attributes.rst index 559893ca2e4..19a27b71793 100644 --- a/reference/attributes.rst +++ b/reference/attributes.rst @@ -79,6 +79,7 @@ HttpKernel Messenger ~~~~~~~~~ +* :ref:`AsMessage ` * :ref:`AsMessageHandler ` RemoteEvent From a8a0e2beed33617c7143fbbeaabee884f3b9f357 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 30 Sep 2024 10:25:40 +0200 Subject: [PATCH 077/427] [AssetMapper] Document the filtering options of debug:asset-map --- frontend/asset_mapper.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index f6300e7adb9..6987718381f 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -137,6 +137,28 @@ This will show you all the mapped paths and the assets inside of each: The "Logical Path" is the path to use when referencing the asset, like from a template. +The ``debug:asset-map`` command provides several options to filter results: + +.. code-block:: terminal + + # provide an asset name or dir to only show results that match it + $ php bin/console debug:asset-map bootstrap.js + $ php bin/console debug:asset-map style/ + + # provide an extension to only show that file type + $ php bin/console debug:asset-map --ext=css + + # you can also only show assets in vendor/ dir or exclude any results from it + $ php bin/console debug:asset-map --vendor + $ php bin/console debug:asset-map --no-vendor + + # you can also combine all filters (e.g. find bold web fonts in your own asset dirs) + $ php bin/console debug:asset-map bold --no-vendor --ext=woff2 + +.. versionadded:: 7.2 + + The options to filter ``debug:asset-map`` results were introduced in Symfony 7.2. + .. _importmaps-javascript: Importmaps & Writing JavaScript From 476c1c1e6795e3384f6d392036147727af627528 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 1 Oct 2024 04:12:12 -0400 Subject: [PATCH 078/427] [Mailer] mark Mailtrap as having Webhook support --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index a8d0eda3072..2954fa7217a 100644 --- a/mailer.rst +++ b/mailer.rst @@ -109,7 +109,7 @@ Service Install with Webhook su `Mailomat`_ ``composer require symfony/mailomat-mailer`` yes `MailPace`_ ``composer require symfony/mail-pace-mailer`` `MailerSend`_ ``composer require symfony/mailer-send-mailer`` -`Mailtrap`_ ``composer require symfony/mailtrap-mailer`` +`Mailtrap`_ ``composer require symfony/mailtrap-mailer`` yes `Mandrill`_ ``composer require symfony/mailchimp-mailer`` `Postal`_ ``composer require symfony/postal-mailer`` `Postmark`_ ``composer require symfony/postmark-mailer`` yes From 9ac77eefb559c3e223722db352b485c374df9f98 Mon Sep 17 00:00:00 2001 From: W0rma Date: Tue, 1 Oct 2024 13:12:01 +0200 Subject: [PATCH 079/427] [Validator] Add example for passing groups and payload to the Compound constraint --- reference/constraints/Compound.rst | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst index fc8081f5917..0d0dc933ae0 100644 --- a/reference/constraints/Compound.rst +++ b/reference/constraints/Compound.rst @@ -102,6 +102,50 @@ You can now use it anywhere you need it: } } +Validation groups and payload can be passed via constructor: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity\User; + + use App\Validator\Constraints as Assert; + + class User + { + #[Assert\PasswordRequirements( + groups: ['registration'], + payload: ['severity' => 'error'], + )] + public string $plainPassword; + } + + .. code-block:: php + + // src/Entity/User.php + namespace App\Entity\User; + + use App\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class User + { + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('plainPassword', new Assert\PasswordRequirements( + groups: ['registration'], + payload: ['severity' => 'error'], + )); + } + } + +.. versionadded:: 7.2 + + Support for passing validation groups and the payload to the constructor + of the ``Compound`` class was introduced in Symfony 7.2. + Options ------- From 743f4c6096f7d6fdd9fc968e402c486064a3b9a6 Mon Sep 17 00:00:00 2001 From: Pierre Ambroise Date: Tue, 1 Oct 2024 14:45:15 +0200 Subject: [PATCH 080/427] Document logical xor in expression language --- reference/formats/expression_language.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/reference/formats/expression_language.rst b/reference/formats/expression_language.rst index f902087d380..368c95bc2a8 100644 --- a/reference/formats/expression_language.rst +++ b/reference/formats/expression_language.rst @@ -345,6 +345,11 @@ Logical Operators * ``not`` or ``!`` * ``and`` or ``&&`` * ``or`` or ``||`` +* ``xor`` + +.. versionadded:: 7.2 + + Support for the ``xor`` logical operator was introduced in Symfony 7.2. For example:: @@ -487,6 +492,8 @@ The following table summarizes the operators and their associativity from the +-----------------------------------------------------------------+---------------+ | ``and``, ``&&`` | left | +-----------------------------------------------------------------+---------------+ +| ``xor`` | left | ++-----------------------------------------------------------------+---------------+ | ``or``, ``||`` | left | +-----------------------------------------------------------------+---------------+ From e8084a2413e3675713321e3749fe9bbbc37eea79 Mon Sep 17 00:00:00 2001 From: johan Vlaar Date: Tue, 1 Oct 2024 16:10:51 +0200 Subject: [PATCH 081/427] [Mailer][Webhook] Mandrill Webhook support --- mailer.rst | 2 +- webhook.rst | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index 2954fa7217a..3dbf8a79575 100644 --- a/mailer.rst +++ b/mailer.rst @@ -110,7 +110,7 @@ Service Install with Webhook su `MailPace`_ ``composer require symfony/mail-pace-mailer`` `MailerSend`_ ``composer require symfony/mailer-send-mailer`` `Mailtrap`_ ``composer require symfony/mailtrap-mailer`` yes -`Mandrill`_ ``composer require symfony/mailchimp-mailer`` +`Mandrill`_ ``composer require symfony/mailchimp-mailer`` yes `Postal`_ ``composer require symfony/postal-mailer`` `Postmark`_ ``composer require symfony/postmark-mailer`` yes `Resend`_ ``composer require symfony/resend-mailer`` yes diff --git a/webhook.rst b/webhook.rst index e2c7083ac43..6b79da037e4 100644 --- a/webhook.rst +++ b/webhook.rst @@ -24,6 +24,7 @@ Currently, the following third-party mailer providers support webhooks: Mailer Service Parser service name ============== ============================================ Brevo ``mailer.webhook.request_parser.brevo`` +Mandrill ``mailer.webhook.request_parser.mailchimp`` MailerSend ``mailer.webhook.request_parser.mailersend`` Mailgun ``mailer.webhook.request_parser.mailgun`` Mailjet ``mailer.webhook.request_parser.mailjet`` @@ -41,7 +42,7 @@ Sweego ``mailer.webhook.request_parser.sweego`` .. versionadded:: 7.2 - The ``Mailomat``, ``Mailtrap``, and ``Sweego`` integrations were introduced in + The ``Mandrill``, ``Mailomat``, ``Mailtrap``, and ``Sweego`` integrations were introduced in Symfony 7.2. .. note:: From 6e2045a3ed2689f9443eb062ea15a54b7261e781 Mon Sep 17 00:00:00 2001 From: W0rma Date: Wed, 2 Oct 2024 07:21:30 +0200 Subject: [PATCH 082/427] [Messenger] Describe the options of the messenger:failed:retry command --- messenger.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/messenger.rst b/messenger.rst index cecb84d9dec..9f75ce33bed 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1173,6 +1173,8 @@ to retry them: $ php bin/console messenger:failed:show 20 -vv # view and retry messages one-by-one + # for each message the command asks whether the message should be retried, + # skipped or deleted $ php bin/console messenger:failed:retry -vv # retry specific messages @@ -1191,6 +1193,11 @@ If the message fails again, it will be re-sent back to the failure transport due to the normal :ref:`retry rules `. Once the max retry has been hit, the message will be discarded permanently. +.. versionadded:: 7.2 + + The possibility to skip a message in the `messenger:failed:retry` + command was introduced in Symfony 7.2 + Multiple Failed Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 795148ee5958773c4f7be614f56358663a677380 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 2 Oct 2024 17:46:12 +0200 Subject: [PATCH 083/427] Minor tweaks --- messenger.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/messenger.rst b/messenger.rst index 9f75ce33bed..add197e8df6 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1172,9 +1172,7 @@ to retry them: # see details about a specific failure $ php bin/console messenger:failed:show 20 -vv - # view and retry messages one-by-one - # for each message the command asks whether the message should be retried, - # skipped or deleted + # for each message, this command asks whether to retry, skip, or delete $ php bin/console messenger:failed:retry -vv # retry specific messages @@ -1195,8 +1193,8 @@ retry has been hit, the message will be discarded permanently. .. versionadded:: 7.2 - The possibility to skip a message in the `messenger:failed:retry` - command was introduced in Symfony 7.2 + The option to skip a message in the ``messenger:failed:retry`` command was + introduced in Symfony 7.2 Multiple Failed Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 50ab3eed6e865d381b3ef914529a63f0a9bb5395 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Oct 2024 08:37:24 +0200 Subject: [PATCH 084/427] [Mailer] Support unicode email addresses --- mailer.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mailer.rst b/mailer.rst index 2954fa7217a..e21951df557 100644 --- a/mailer.rst +++ b/mailer.rst @@ -542,6 +542,10 @@ both strings or address objects:: // email address as a simple string ->from('fabien@example.com') + // non-ASCII characters are supported both in the local part and the domain; + // if the SMTP server doesn't support this feature, you'll see an exception + ->from('jânë.dœ@ëxãmplę.com') + // email address as an object ->from(new Address('fabien@example.com')) @@ -556,6 +560,11 @@ both strings or address objects:: // ... ; +.. versionadded:: 7.2 + + Support for non-ASCII email addresses (e.g. ``jânë.dœ@ëxãmplę.com``) + was introduced in Symfony 7.2. + .. tip:: Instead of calling ``->from()`` *every* time you create a new email, you can From 861a0968eec52f837115b5667a18df6485bd2ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jib=C3=A9=20Barth?= Date: Sun, 6 Oct 2024 19:28:44 +0200 Subject: [PATCH 085/427] [Console] Document FinishedIndicator for Progress indicator --- .../console/helpers/progressindicator.rst | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/components/console/helpers/progressindicator.rst b/components/console/helpers/progressindicator.rst index d64ec6367b7..dd18c6bdbc9 100644 --- a/components/console/helpers/progressindicator.rst +++ b/components/console/helpers/progressindicator.rst @@ -95,6 +95,26 @@ The progress indicator will now look like this: ⠹ Processing... ⢸ Processing... +Custom Finished Indicator +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once the progress indicator is finished, it keeps by default the latest indicator value. You can replace it with a your own:: + + $progressIndicator->finish('Finished', '✅'); + +Then the progress indicator will render like this: + +.. code-block:: text + + ⠏ Processing... + ⠛ Processing... + ✅ Finished + +.. versionadded:: 7.2 + + The ``finishedIndicator`` parameter for method ``finish()`` was introduced in Symfony 7.2. + + Customize Placeholders ~~~~~~~~~~~~~~~~~~~~~~ From 1b26f7681a2f4aff35adf89014767972a50a8585 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Oct 2024 10:21:40 +0200 Subject: [PATCH 086/427] Minor tweaks --- components/console/helpers/progressindicator.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/console/helpers/progressindicator.rst b/components/console/helpers/progressindicator.rst index dd18c6bdbc9..fedc8439e64 100644 --- a/components/console/helpers/progressindicator.rst +++ b/components/console/helpers/progressindicator.rst @@ -95,10 +95,8 @@ The progress indicator will now look like this: ⠹ Processing... ⢸ Processing... -Custom Finished Indicator -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once the progress indicator is finished, it keeps by default the latest indicator value. You can replace it with a your own:: +Once the progress indicator is finished, it keeps the latest indicator value by +default. You can replace it with your own:: $progressIndicator->finish('Finished', '✅'); @@ -114,7 +112,6 @@ Then the progress indicator will render like this: The ``finishedIndicator`` parameter for method ``finish()`` was introduced in Symfony 7.2. - Customize Placeholders ~~~~~~~~~~~~~~~~~~~~~~ From 2c93089f1781396bcd54b6f7f8eec403fa1c87a8 Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne Date: Sat, 28 Sep 2024 18:47:17 +0200 Subject: [PATCH 087/427] [Serializer] Deprecate ``AdvancedNameConverterInterface`` --- components/serializer.rst | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index de8f67c853d..0764612e28a 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -549,12 +549,12 @@ A custom name converter can handle such cases:: class OrgPrefixNameConverter implements NameConverterInterface { - public function normalize(string $propertyName): string + public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string { return 'org_'.$propertyName; } - public function denormalize(string $propertyName): string + public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string { // removes 'org_' prefix return str_starts_with($propertyName, 'org_') ? substr($propertyName, 4) : $propertyName; @@ -584,12 +584,6 @@ and :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer`:: $companyCopy = $serializer->deserialize($json, Company::class, 'json'); // Same data as $company -.. note:: - - You can also implement - :class:`Symfony\\Component\\Serializer\\NameConverter\\AdvancedNameConverterInterface` - to access the current class name, format and context. - .. _using-camelized-method-names-for-underscored-attributes: CamelCase to snake_case From e14e05f4eaea753f625656949d9d9fc4814510ff Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Oct 2024 10:13:16 +0200 Subject: [PATCH 088/427] Document the new `SYMFONY_*` env vars --- deployment/proxies.rst | 11 ++++++++++- reference/configuration/framework.rst | 14 ++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index fc6f855451d..cd5649d979a 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -22,7 +22,11 @@ Solution: ``setTrustedProxies()`` --------------------------------- To fix this, you need to tell Symfony which reverse proxy IP addresses to trust -and what headers your reverse proxy uses to send information: +and what headers your reverse proxy uses to send information. + +You can do that by setting the ``SYMFONY_TRUSTED_PROXIES`` and ``SYMFONY_TRUSTED_HEADERS`` +environment variables on your machine. Alternatively, you can configure them +using the following configuration options: .. configuration-block:: @@ -93,6 +97,11 @@ and what headers your reverse proxy uses to send information: ``private_ranges`` as a shortcut for private IP address ranges for the ``trusted_proxies`` option was introduced in Symfony 7.1. +.. versionadded:: 7.2 + + Support for the ``SYMFONY_TRUSTED_PROXIES`` and ``SYMFONY_TRUSTED_HEADERS`` + environment variables was introduced in Symfony 7.2. + .. caution:: Enabling the ``Request::HEADER_X_FORWARDED_HOST`` option exposes the diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 19f72bb6cb3..53edf220642 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -198,7 +198,12 @@ named ``kernel.http_method_override``. trust_x_sendfile_type_header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``boolean`` **default**: ``false`` +**type**: ``boolean`` **default**: ``%env(bool:default::SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER)%`` + +.. versionadded:: 7.2 + + In Symfony 7.2, the default value of this option was changed from ``false`` to the + value stored in the ``SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER`` environment variable. ``X-Sendfile`` is a special HTTP header that tells web servers to replace the response contents by the file that is defined in that header. This improves @@ -450,7 +455,12 @@ in debug mode. trusted_hosts ~~~~~~~~~~~~~ -**type**: ``array`` | ``string`` **default**: ``[]`` +**type**: ``array`` | ``string`` **default**: ``['%env(default::SYMFONY_TRUSTED_HOSTS)%']`` + +.. versionadded:: 7.2 + + In Symfony 7.2, the default value of this option was changed from ``[]`` to the + value stored in the ``SYMFONY_TRUSTED_HOSTS`` environment variable. A lot of different attacks have been discovered relying on inconsistencies in handling the ``Host`` header by various software (web servers, reverse From 03922de2588b2ec965cd31f40c2ecc4d9b3e0c97 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Oct 2024 16:04:31 +0200 Subject: [PATCH 089/427] [Ldap] Add support for `sasl_bind` and `whoami` LDAP operations --- components/ldap.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/components/ldap.rst b/components/ldap.rst index 89094fad0b7..d5f6bc3fdfe 100644 --- a/components/ldap.rst +++ b/components/ldap.rst @@ -74,6 +74,19 @@ distinguished name (DN) and the password of a user:: When the LDAP server allows unauthenticated binds, a blank password will always be valid. +You can also use the :method:`Symfony\\Component\\Ldap\\Ldap::saslBind` method +for binding to an LDAP server using `SASL`_:: + + // this method defines other optional arguments like $mech, $realm, $authcId, etc. + $ldap->saslBind($dn, $password); + +After binding to the LDAP server, you can use the :method:`Symfony\\Component\\Ldap\\Ldap::whoami` +method to get the distinguished name (DN) of the authenticated and authorized user. + +.. versionadded:: 7.2 + + The ``saslBind()`` and ``whoami()`` methods were introduced in Symfony 7.2. + Once bound (or if you enabled anonymous authentication on your LDAP server), you may query the LDAP server using the :method:`Symfony\\Component\\Ldap\\Ldap::query` method:: @@ -183,3 +196,5 @@ Possible operation types are ``LDAP_MODIFY_BATCH_ADD``, ``LDAP_MODIFY_BATCH_REMO ``LDAP_MODIFY_BATCH_REMOVE_ALL``, ``LDAP_MODIFY_BATCH_REPLACE``. Parameter ``$values`` must be ``NULL`` when using ``LDAP_MODIFY_BATCH_REMOVE_ALL`` operation type. + +.. _`SASL`: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer From 3df38498bba9aaede83aafad5366d6449630d437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=A6=85KoNekoD?= Date: Thu, 10 Oct 2024 11:01:05 +0300 Subject: [PATCH 090/427] feat(when constraint): add context variable --- reference/constraints/When.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/constraints/When.rst b/reference/constraints/When.rst index e1e8ac895ce..12b43fc7d63 100644 --- a/reference/constraints/When.rst +++ b/reference/constraints/When.rst @@ -163,7 +163,7 @@ validation of constraints won't be triggered. To learn more about the expression language syntax, see :doc:`/reference/formats/expression_language`. -Depending on how you use the constraint, you have access to 1 or 2 variables +Depending on how you use the constraint, you have access to 1 or 3 variables in your expression: ``this`` @@ -171,6 +171,8 @@ in your expression: ``value`` The value of the property being validated (only available when the constraint is applied to a property). +``context`` + This is the context that is used in validation The ``value`` variable can be used when you want to execute more complex validation based on its value: From 5e8fb6ebd991577c9645d1df13bdabca8cf3b922 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 10 Oct 2024 14:21:34 +0200 Subject: [PATCH 091/427] [Lock] Add NullStore --- components/lock.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/lock.rst b/components/lock.rst index 5a76223112b..69e51a1407b 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -406,6 +406,14 @@ Store Scope Blocking Ex A special ``InMemoryStore`` is available for saving locks in memory during a process, and can be useful for testing. +.. tip:: + + A special ``NullStore`` is available and persist nothing, it can be useful for testing. + +.. versionadded:: 7.2 + + The :class:`Symfony\\Component\\Lock\\Store\\NullStore` was introduced in Symfony 7.2. + .. _lock-store-flock: FlockStore From 52d4f7bc5681bbf563eff8c4db8c439e0151d279 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 10 Oct 2024 16:06:12 +0200 Subject: [PATCH 092/427] Minor reword --- components/lock.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 69e51a1407b..bf75fb49f7a 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -403,12 +403,9 @@ Store Scope Blocking Ex .. tip:: - A special ``InMemoryStore`` is available for saving locks in memory during - a process, and can be useful for testing. - -.. tip:: - - A special ``NullStore`` is available and persist nothing, it can be useful for testing. + Symfony includes two other special stores that are mostly useful for testing: + ``InMemoryStore``, which saves locks in memory during a process, and ``NullStore``, + which doesn't persist anything. .. versionadded:: 7.2 From 16bccc3a3bab72597e7ad7bf23a291a12f4b958e Mon Sep 17 00:00:00 2001 From: Benjamin Georgeault Date: Mon, 14 Oct 2024 11:27:37 +0200 Subject: [PATCH 093/427] Add missing ref in constraint map to the new Yaml constraint. --- reference/constraints/map.rst.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index e0dbd6c4512..97c049dae90 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -34,6 +34,7 @@ String Constraints * :doc:`Charset ` * :doc:`MacAddress ` * :doc:`WordCount ` +* :doc:`Yaml ` Comparison Constraints ~~~~~~~~~~~~~~~~~~~~~~ From d10abd7ad04171dd74b8032826bdb1db910894c7 Mon Sep 17 00:00:00 2001 From: pan93412 Date: Fri, 11 Oct 2024 14:19:45 +0800 Subject: [PATCH 094/427] [Notifier] Add LINE Bot notifier --- notifier.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/notifier.rst b/notifier.rst index 8b684ef2d1d..e5671eea534 100644 --- a/notifier.rst +++ b/notifier.rst @@ -341,6 +341,7 @@ Service Package D `Firebase`_ ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` `Gitter`_ ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` `GoogleChat`_ ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` +`LINE Bot`_ ``symfony/line-bot-notifier`` ``linebot://TOKEN@default?receiver=RECEIVER`` `LINE Notify`_ ``symfony/line-notify-notifier`` ``linenotify://TOKEN@default`` `LinkedIn`_ ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` `Mastodon`_ ``symfony/mastodon-notifier`` ``mastodon://ACCESS_TOKEN@HOST`` @@ -355,6 +356,10 @@ Service Package D `Zulip`_ ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL`` ====================================== ==================================== ============================================================================= +.. versionadded:: 7.2 + + The ``LINE Bot`` integration was introduced in Symfony 7.2. + .. versionadded:: 7.1 The ``Bluesky`` integration was introduced in Symfony 7.1. @@ -1100,6 +1105,7 @@ is dispatched. Listeners receive a .. _`Iqsms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Iqsms/README.md .. _`iSendPro`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Isendpro/README.md .. _`KazInfoTeh`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/KazInfoTeh/README.md +.. _`LINE Bot`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LineBot/README.md .. _`LINE Notify`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LineNotify/README.md .. _`LightSms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LightSms/README.md .. _`LinkedIn`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LinkedIn/README.md From b4b0c4c727ae35e16807717307ba37ad48b31777 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 14 Oct 2024 11:43:52 +0200 Subject: [PATCH 095/427] Minor tweak --- notifier.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index 7d4ce6ef6be..71af2ccb440 100644 --- a/notifier.rst +++ b/notifier.rst @@ -370,14 +370,14 @@ Service Package D `Zulip`_ ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL`` ====================================== ==================================== ============================================================================= -.. versionadded:: 7.2 - - The ``LINE Bot`` integration was introduced in Symfony 7.2. - .. versionadded:: 7.1 The ``Bluesky`` integration was introduced in Symfony 7.1. +.. versionadded:: 7.2 + + The ``LINE Bot`` integration was introduced in Symfony 7.2. + .. deprecated:: 7.2 The ``Gitter`` integration was removed in Symfony 7.2 because that service From e55e7cda09565450489232ab9144b752f8fe7e73 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sun, 13 Oct 2024 15:23:24 -0400 Subject: [PATCH 096/427] documenting choice_lazy option --- reference/forms/types/choice.rst | 2 ++ .../forms/types/options/choice_lazy.rst.inc | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 reference/forms/types/options/choice_lazy.rst.inc diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 55f2d016001..2d31aac890c 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -178,6 +178,8 @@ correct types will be assigned to the model. .. include:: /reference/forms/types/options/choice_loader.rst.inc +.. include:: /reference/forms/types/options/choice_lazy.rst.inc + .. include:: /reference/forms/types/options/choice_name.rst.inc .. include:: /reference/forms/types/options/choice_translation_domain_enabled.rst.inc diff --git a/reference/forms/types/options/choice_lazy.rst.inc b/reference/forms/types/options/choice_lazy.rst.inc new file mode 100644 index 00000000000..db8591a613d --- /dev/null +++ b/reference/forms/types/options/choice_lazy.rst.inc @@ -0,0 +1,31 @@ +``choice_lazy`` +~~~~~~~~~~~~~~~ + +**type**: ``boolean`` **default**: ``false`` + +The ``choice_lazy`` option is especially useful when dealing with a large set of +choices, where loading all of them at once could lead to performance issues or +significant delays:: + + use App\Entity\User; + use Symfony\Bridge\Doctrine\Form\Type\EntityType; + + $builder->add('user', EntityType::class, [ + 'class' => User::class, + 'choice_lazy' => true, + ]); + +When set to ``true``, and used in combination with the ``choice_loader`` option, +the form will only load and render the choices that are preset as default values +or submitted. This allows you to defer loading the full list of choices and can +improve the performance of your form. + +.. caution:: + + Please note that when using ``choice_lazy``, you are responsible for providing + the user interface to select choices, typically through a JavaScript plugin that + can handle the dynamic loading of choices. + +.. versionadded:: 7.2 + + The ``choice_lazy`` option was introduced in Symfony 7.2. From e9bd37b9073074b82a31789851c97b6219e79d1e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 14 Oct 2024 14:58:35 +0200 Subject: [PATCH 097/427] merge versionadded directives --- notifier.rst | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/notifier.rst b/notifier.rst index 71af2ccb440..b2329b2b28a 100644 --- a/notifier.rst +++ b/notifier.rst @@ -207,10 +207,6 @@ Service **Webhook support**: No ================== ==================================================================================================================================== -.. versionadded:: 7.2 - - The ``Primotexto`` integration was introduced in Symfony 7.2. - .. tip:: Use :doc:`Symfony configuration secrets ` to securely @@ -229,7 +225,7 @@ Service .. versionadded:: 7.2 - The ``Sipgate`` integration was introduced in Symfony 7.2. + The ``Primotexto`` and ``Sipgate`` integrations were introduced in Symfony 7.2. .. deprecated:: 7.1 From 12dfa63405ec8b7413ec69fa6df8306ce445d648 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 14 Oct 2024 15:46:52 +0200 Subject: [PATCH 098/427] Minor tweaks --- .../forms/types/options/choice_lazy.rst.inc | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/reference/forms/types/options/choice_lazy.rst.inc b/reference/forms/types/options/choice_lazy.rst.inc index db8591a613d..bdcbf178406 100644 --- a/reference/forms/types/options/choice_lazy.rst.inc +++ b/reference/forms/types/options/choice_lazy.rst.inc @@ -3,9 +3,13 @@ **type**: ``boolean`` **default**: ``false`` -The ``choice_lazy`` option is especially useful when dealing with a large set of -choices, where loading all of them at once could lead to performance issues or -significant delays:: +.. versionadded:: 7.2 + + The ``choice_lazy`` option was introduced in Symfony 7.2. + +The ``choice_lazy`` option is particularly useful when dealing with a large set +of choices, where loading them all at once could cause performance issues or +delays:: use App\Entity\User; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -15,17 +19,13 @@ significant delays:: 'choice_lazy' => true, ]); -When set to ``true``, and used in combination with the ``choice_loader`` option, -the form will only load and render the choices that are preset as default values -or submitted. This allows you to defer loading the full list of choices and can -improve the performance of your form. +When set to ``true`` and used alongside the ``choice_loader`` option, the form +will only load and render the choices that are preset as default values or +submitted. This defers the loading of the full list of choices, helping to +improve your form's performance. .. caution:: - Please note that when using ``choice_lazy``, you are responsible for providing - the user interface to select choices, typically through a JavaScript plugin that - can handle the dynamic loading of choices. - -.. versionadded:: 7.2 - - The ``choice_lazy`` option was introduced in Symfony 7.2. + Keep in mind that when using ``choice_lazy``, you are responsible for + providing the user interface for selecting choices, typically through a + JavaScript plugin capable of dynamically loading choices. From 93ca37815417a6c11b7d8807beec1d9bf111b557 Mon Sep 17 00:00:00 2001 From: Laurens Laman Date: Tue, 15 Oct 2024 14:56:21 +0200 Subject: [PATCH 099/427] Update progressindicator.rst Corrected false statement about the finishedIndicator. Make documentation more clear --- .../console/helpers/progressindicator.rst | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/components/console/helpers/progressindicator.rst b/components/console/helpers/progressindicator.rst index fedc8439e64..1d4384958e9 100644 --- a/components/console/helpers/progressindicator.rst +++ b/components/console/helpers/progressindicator.rst @@ -44,18 +44,21 @@ level of verbosity of the ``OutputInterface`` instance: | Processing... / Processing... - Processing... + ✔ Finished # OutputInterface::VERBOSITY_VERBOSE (-v) \ Processing... (1 sec) | Processing... (1 sec) / Processing... (1 sec) - Processing... (1 sec) + ✔ Finished (1 sec) # OutputInterface::VERBOSITY_VERY_VERBOSE (-vv) and OutputInterface::VERBOSITY_DEBUG (-vvv) \ Processing... (1 sec, 6.0 MiB) | Processing... (1 sec, 6.0 MiB) / Processing... (1 sec, 6.0 MiB) - Processing... (1 sec, 6.0 MiB) + ✔ Finished (1 sec, 6.0 MiB) .. tip:: @@ -94,22 +97,23 @@ The progress indicator will now look like this: ⠛ Processing... ⠹ Processing... ⢸ Processing... + ✔ Finished -Once the progress indicator is finished, it keeps the latest indicator value by -default. You can replace it with your own:: +Once the progress indicator is finished, it uses the finishedIndicator value (which defaults to ✔). You can replace it with your own:: - $progressIndicator->finish('Finished', '✅'); - -Then the progress indicator will render like this: - -.. code-block:: text + $progressIndicator = new ProgressIndicator($output, 'verbose', 100, null, '🎉'); + + try { + /* do something */ + $progressIndicator->finish('Finished'); + } catch (\Exception) { + $progressIndicator->finish('Failed', '🚨'); + } - ⠏ Processing... - ⠛ Processing... - ✅ Finished .. versionadded:: 7.2 + The ``finishedIndicator`` parameter for the constructor was introduced in Symfony 7.2. The ``finishedIndicator`` parameter for method ``finish()`` was introduced in Symfony 7.2. Customize Placeholders From d926bbb4e7cb2cd75e0f2f444a3b41dc3a1938d5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 16 Oct 2024 10:53:34 +0200 Subject: [PATCH 100/427] Reword --- messenger.rst | 102 +++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/messenger.rst b/messenger.rst index 03c429e214e..9cb6b4a6ff4 100644 --- a/messenger.rst +++ b/messenger.rst @@ -203,8 +203,23 @@ Routing Messages to a Transport Now that you have a transport configured, instead of handling a message immediately, you can configure them to be sent to a transport: +.. _messenger-message-attribute: + .. configuration-block:: + .. code-block:: php-attributes + + // src/Message/SmsNotification.php + namespace App\Message; + + use Symfony\Component\Messenger\Attribute\AsMessage; + + #[AsMessage('async')] + class SmsNotification + { + // ... + } + .. code-block:: yaml # config/packages/messenger.yaml @@ -251,15 +266,26 @@ you can configure them to be sent to a transport: ; }; +.. versionadded:: 7.2 + + The ``#[AsMessage]`` attribute was introduced in Symfony 7.2. + Thanks to this, the ``App\Message\SmsNotification`` will be sent to the ``async`` transport and its handler(s) will *not* be called immediately. Any messages not matched under ``routing`` will still be handled immediately, i.e. synchronously. .. note:: - You may use a partial PHP namespace like ``'App\Message\*'`` to match all - the messages within the matching namespace. The only requirement is that the - ``'*'`` wildcard has to be placed at the end of the namespace. + If you configure routing with both YAML/XML/PHP configuration files and + PHP attributes, the configuration always takes precedence over the class + attribute. This behavior allows you to override routing on a per-environment basis. + +.. note:: + + When configuring the routing in separate YAML/XML/PHP files, you can use a partial + PHP namespace like ``'App\Message\*'`` to match all the messages within the + matching namespace. The only requirement is that the ``'*'`` wildcard has to + be placed at the end of the namespace. You may use ``'*'`` as the message class. This will act as a default routing rule for any message not matched under ``routing``. This is useful to ensure @@ -275,6 +301,27 @@ to multiple transports: .. configuration-block:: + .. code-block:: php-attributes + + // src/Message/SmsNotification.php + namespace App\Message; + + use Symfony\Component\Messenger\Attribute\AsMessage; + + #[AsMessage(['async', 'audit'])] + class SmsNotification + { + // ... + } + + // if you prefer, you can also apply multiple attributes to the message class + #[AsMessage('async')] + #[AsMessage('audit')] + class SmsNotification + { + // ... + } + .. code-block:: yaml # config/packages/messenger.yaml @@ -345,55 +392,6 @@ to multiple transports: name as its only argument. For more information about stamps, see `Envelopes & Stamps`_. -.. _messenger-message-attribute: - -Configuring Routing Using Attributes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can optionally use the `#[AsMessage]` attribute to configure message transport:: - - // src/Message/SmsNotification.php - namespace App\Message; - - use Symfony\Component\Messenger\Attribute\AsMessage; - - #[AsMessage(transport: 'async')] - class SmsNotification - { - public function __construct( - private string $content, - ) { - } - - public function getContent(): string - { - return $this->content; - } - } - -.. note:: - - If you configure routing with both configuration and attributes, the - configuration will take precedence over the attributes and override - them. This allows to override routing on a per-environment basis - for example: - - .. code-block:: yaml - - # config/packages/messenger.yaml - when@dev: - framework: - messenger: - routing: - # override class attribute - 'App\Message\SmsNotification': sync - -.. tip:: - - The `$transport` parameter can be either a `string` or an `array`: configuring multiple - transports is possible. You may also repeat the attribute if you prefer instead of using - an array. - Doctrine Entities in Messages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 9d85b6904c11777c31263b276152ad980cbd08fc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 16 Oct 2024 16:43:56 +0200 Subject: [PATCH 101/427] Tweaks --- components/console/helpers/progressindicator.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/console/helpers/progressindicator.rst b/components/console/helpers/progressindicator.rst index 1d4384958e9..0defe7c83fd 100644 --- a/components/console/helpers/progressindicator.rst +++ b/components/console/helpers/progressindicator.rst @@ -99,9 +99,10 @@ The progress indicator will now look like this: ⢸ Processing... ✔ Finished -Once the progress indicator is finished, it uses the finishedIndicator value (which defaults to ✔). You can replace it with your own:: +Once the progress finishes, it displays a special finished indicator (which defaults +to ✔). You can replace it with your own:: - $progressIndicator = new ProgressIndicator($output, 'verbose', 100, null, '🎉'); + $progressIndicator = new ProgressIndicator($output, finishedIndicatorValue: '🎉'); try { /* do something */ @@ -110,6 +111,15 @@ Once the progress indicator is finished, it uses the finishedIndicator value (wh $progressIndicator->finish('Failed', '🚨'); } +The progress indicator will now look like this: + +.. code-block:: text + + \ Processing... + | Processing... + / Processing... + - Processing... + 🎉 Finished .. versionadded:: 7.2 From 6473d6c91f016b26b28ec8dc083fc300b0525133 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 16 Oct 2024 16:50:50 +0200 Subject: [PATCH 102/427] Finished the docs --- security/user_checkers.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/security/user_checkers.rst b/security/user_checkers.rst index 1e1dcaf3e55..ec8f49da522 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -21,6 +21,8 @@ displayed to the user:: namespace App\Security; use App\Entity\User as AppUser; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AccountExpiredException; use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException; use Symfony\Component\Security\Core\User\UserCheckerInterface; @@ -50,9 +52,17 @@ displayed to the user:: if ($user->isExpired()) { throw new AccountExpiredException('...'); } + + if (!\in_array('foo', $token->getRoleNames())) { + throw new AccessDeniedException('...'); + } } } +.. versionadded:: 7.2 + + The ``token`` argument for the ``checkPostAuth()`` method was introduced in Symfony 7.2. + Enabling the Custom User Checker -------------------------------- From f932585d967262ffcd0f2b63ac47faa043e9d3bf Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Sat, 19 Oct 2024 16:52:24 +0200 Subject: [PATCH 103/427] Add Sweego Notifier doc --- notifier.rst | 6 +++++- webhook.rst | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index b2329b2b28a..144044ebe3e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -187,6 +187,9 @@ Service `SpotHit`_ **Install**: ``composer require symfony/spot-hit-notifier`` \ **DSN**: ``spothit://TOKEN@default?from=FROM`` \ **Webhook support**: No +`Sweego`_ **Install**: ``composer require symfony/sweego-notifier`` \ + **DSN**: ``sweego://API_KEY@default?region=REGION&campaign_type=CAMPAIGN_TYPE`` \ + **Webhook support**: Yes `Telnyx`_ **Install**: ``composer require symfony/telnyx-notifier`` \ **DSN**: ``telnyx://API_KEY@default?from=FROM&messaging_profile_id=MESSAGING_PROFILE_ID`` \ **Webhook support**: No @@ -225,7 +228,7 @@ Service .. versionadded:: 7.2 - The ``Primotexto`` and ``Sipgate`` integrations were introduced in Symfony 7.2. + The ``Primotexto``, ``Sipgate`` and ``Sweego`` integrations were introduced in Symfony 7.2. .. deprecated:: 7.1 @@ -1239,6 +1242,7 @@ is dispatched. Listeners receive a .. _`SMSense`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SMSense/README.md .. _`SmsSluzba`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SmsSluzba/README.md .. _`SpotHit`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SpotHit/README.md +.. _`Sweego`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sweego/README.md .. _`Telegram`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Telegram/README.md .. _`Telnyx`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Telnyx/README.md .. _`TurboSms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/TurboSms/README.md diff --git a/webhook.rst b/webhook.rst index 6b79da037e4..aba95cffb04 100644 --- a/webhook.rst +++ b/webhook.rst @@ -166,6 +166,7 @@ Currently, the following third-party SMS transports support webhooks: SMS service Parser service name ============ ========================================== Twilio ``notifier.webhook.request_parser.twilio`` +Sweego ``notifier.webhook.request_parser.sweego`` Vonage ``notifier.webhook.request_parser.vonage`` ============ ========================================== From ef9baef15df2f02bec0221f78cbab3151695f542 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Mon, 21 Oct 2024 08:56:56 +0200 Subject: [PATCH 104/427] fix param name for lint:translations --- translation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index 4663d9d7c15..a1d012f3b38 100644 --- a/translation.rst +++ b/translation.rst @@ -1405,7 +1405,7 @@ to check that the translation contents are also correct: $ php bin/console lint:translations # checks the contents of the translation catalogues for Italian (it) and Japanese (ja) locales - $ php bin/console lint:translations --locales=it --locales=ja + $ php bin/console lint:translations --locale=it --locale=ja .. versionadded:: 7.2 From b8e5d0c59bf7a287687317026f56b7f5cd8d1f03 Mon Sep 17 00:00:00 2001 From: Jawira Portugal Date: Sun, 27 Oct 2024 19:23:45 +0100 Subject: [PATCH 105/427] Add --prefix and --no-fill to translation page --- translation.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/translation.rst b/translation.rst index a1d012f3b38..2bbce00977a 100644 --- a/translation.rst +++ b/translation.rst @@ -467,8 +467,33 @@ The ``translation:extract`` command looks for missing translations in: $ composer require nikic/php-parser +By default, the ``translation:extract`` command extracts new messages in +*message/translation* pairs, with the translation populated with the same +text as the message, prefixed by ``__``. You can customize this prefix using +the ``--prefix`` option. + +If you want to leave new translations empty, use the ``--no-fill`` option. +When enabled, only messages are created, and the translation strings are left +empty. This is particularly useful when using external translation tools, as +it ensures untranslated strings are easily identifiable without any pre-filled +content. Note that when ``--no-fill`` is used, the ``--prefix`` option has +no effect. + +.. code-block:: terminal + + # changes default prefix + $ php bin/console translation:extract --force --prefix="NEW_" fr + + # leaves new translations empty + $ php bin/console translation:extract --force --no-fill fr + +.. versionadded:: 7.2 + + The ``--no-fill`` option was introduced in Symfony 7.2. + .. _translation-resource-locations: + Translation Resource/File Names and Locations --------------------------------------------- From 65a14d07553951cf305069d4d56485898d8121b6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 28 Oct 2024 17:59:56 +0100 Subject: [PATCH 106/427] Minor tweaks --- translation.rst | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/translation.rst b/translation.rst index 2bbce00977a..a41b305dc8b 100644 --- a/translation.rst +++ b/translation.rst @@ -467,24 +467,23 @@ The ``translation:extract`` command looks for missing translations in: $ composer require nikic/php-parser -By default, the ``translation:extract`` command extracts new messages in -*message/translation* pairs, with the translation populated with the same -text as the message, prefixed by ``__``. You can customize this prefix using -the ``--prefix`` option. - -If you want to leave new translations empty, use the ``--no-fill`` option. -When enabled, only messages are created, and the translation strings are left -empty. This is particularly useful when using external translation tools, as -it ensures untranslated strings are easily identifiable without any pre-filled -content. Note that when ``--no-fill`` is used, the ``--prefix`` option has -no effect. +By default, when the ``translation:extract`` command creates new entries in the +trnaslation file, it uses the same content as both the source and the pending +translation. The only difference is that the pending translation is prefixed by +``__``. You can customize this prefix using the ``--prefix`` option: .. code-block:: terminal - # changes default prefix $ php bin/console translation:extract --force --prefix="NEW_" fr - # leaves new translations empty +Alternatively, you can use the ``--no-fill`` option to leave the pending translation +completely empty when creating new entries in the translation catalog. This is +particularly useful when using external translation tools, as it makes it easier +to spot untranslated strings: + +.. code-block:: terminal + + # when using the --no-fill option, the --prefix option is ignored $ php bin/console translation:extract --force --no-fill fr .. versionadded:: 7.2 @@ -493,7 +492,6 @@ no effect. .. _translation-resource-locations: - Translation Resource/File Names and Locations --------------------------------------------- From 562893be94672b5987b74521d8abebac4d618d30 Mon Sep 17 00:00:00 2001 From: Jawira Portugal Date: Mon, 28 Oct 2024 22:10:26 +0100 Subject: [PATCH 107/427] fix typo --- translation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index a41b305dc8b..0e5f09d342e 100644 --- a/translation.rst +++ b/translation.rst @@ -468,7 +468,7 @@ The ``translation:extract`` command looks for missing translations in: $ composer require nikic/php-parser By default, when the ``translation:extract`` command creates new entries in the -trnaslation file, it uses the same content as both the source and the pending +translation file, it uses the same content as both the source and the pending translation. The only difference is that the pending translation is prefixed by ``__``. You can customize this prefix using the ``--prefix`` option: From e033e433ab3d65e88fc5470662ecc485fc3117a6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 29 Oct 2024 10:07:55 +0100 Subject: [PATCH 108/427] [Notifier] Add some examples to the new Desktop channel notifications --- notifier.rst | 71 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/notifier.rst b/notifier.rst index 144044ebe3e..b28bb541475 100644 --- a/notifier.rst +++ b/notifier.rst @@ -33,8 +33,14 @@ The notifier component supports the following channels: services like Slack and Telegram; * :ref:`Email channel ` integrates the :doc:`Symfony Mailer `; * Browser channel uses :ref:`flash messages `. -* :ref:`Push channel ` sends notifications to phones and browsers via push notifications. -* :ref:`Desktop channel ` displays desktop notifications on the same host machine. +* :ref:`Push channel ` sends notifications to phones and + browsers via push notifications. +* :ref:`Desktop channel ` displays desktop notifications + on the same host machine. + +.. versionadded:: 7.2 + + The ``Desktop`` channel was introduced in Symfony 7.2. .. _notifier-sms-channel: @@ -635,9 +641,9 @@ configure the ``texter_transports``: Desktop Channel ~~~~~~~~~~~~~~~ -The desktop channel is used to display desktop notifications on the same host machine using -:class:`Symfony\\Component\\Notifier\\Texter` classes. Currently, Symfony -is integrated with the following providers: +The desktop channel is used to display local desktop notifications on the same +host machine using :class:`Symfony\\Component\\Notifier\\Texter` classes. Currently, +Symfony is integrated with the following providers: =============== ==================================== ============================================================================== Provider Package DSN @@ -645,18 +651,23 @@ Provider Package DSN `JoliNotif`_ ``symfony/joli-notif-notifier`` ``jolinotif://default`` =============== ==================================== ============================================================================== -.. versionadded: 7.2 +.. versionadded:: 7.2 The JoliNotif bridge was introduced in Symfony 7.2. -To enable a texter, add the correct DSN in your ``.env`` file and -configure the ``texter_transports``: +If you are using :ref:`Symfony Flex `, installing that package will +also create the necessary environment variable and configuration. Otherwise, you'll +need to add the following manually: + +1) Add the correct DSN in your ``.env`` file: .. code-block:: bash # .env JOLINOTIF=jolinotif://default +2) Update the Notifier configuration to add a new texter transport: + .. configuration-block:: .. code-block:: yaml @@ -699,9 +710,49 @@ configure the ``texter_transports``: ; }; -.. versionadded:: 7.2 +Now you can send notifications to your desktop as follows:: - The ``Desktop`` channel was introduced in Symfony 7.2. + // src/Notifier/SomeService.php + use Symfony\Component\Notifier\Message\DesktopMessage; + use Symfony\Component\Notifier\TexterInterface; + // ... + + class SomeService + { + public function __construct( + private TexterInterface $texter, + ) { + } + + public function notifyNewSubscriber(User $user): void + { + $message = new DesktopMessage( + 'New subscription! 🎉', + sprintf('%s is a new subscriber', $user->getFullName()) + ); + + $texter->send($message); + } + } + +These notifications can be customized further, and depending on your operating system, +they may support features like custom sounds, icons, and more:: + + use Symfony\Component\Notifier\Bridge\JoliNotif\JoliNotifOptions; + // ... + + $options = (new JoliNotifOptions()) + ->setIconPath('/path/to/icons/error.png') + ->setExtraOption('sound', 'sosumi') + ->setExtraOption('url', 'https://example.com'); + + $message = new DesktopMessage('Production is down', <<send($message); Configure to use Failover or Round-Robin Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From d20ac34ac17254dc48a74ced515948a825ceae35 Mon Sep 17 00:00:00 2001 From: Raffaele Carelle Date: Mon, 4 Nov 2024 09:48:23 +0100 Subject: [PATCH 109/427] add stringNode documentation --- components/config/definition.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/config/definition.rst b/components/config/definition.rst index 929246fa915..05f64497a66 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -83,6 +83,12 @@ reflect the real structure of the configuration values:: ->scalarNode('default_connection') ->defaultValue('mysql') ->end() + ->stringNode('username') + ->defaultValue('root') + ->end() + ->stringNode('password') + ->defaultValue('root') + ->end() ->end() ; @@ -100,6 +106,7 @@ node definition. Node types are available for: * scalar (generic type that includes booleans, strings, integers, floats and ``null``) * boolean +* string * integer * float * enum (similar to scalar, but it only allows a finite set of values) From 970d37b45d9b609376ce7c77f8a8384d954f509f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 7 Nov 2024 16:47:56 +0100 Subject: [PATCH 110/427] Add the versionadded directives --- components/config/definition.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/config/definition.rst b/components/config/definition.rst index 05f64497a66..4e99fb4f6a7 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -92,6 +92,10 @@ reflect the real structure of the configuration values:: ->end() ; +.. versionadded:: 7.2 + + The ``stringNode()`` method was introduced in Symfony 7.2. + The root node itself is an array node, and has children, like the boolean node ``auto_connect`` and the scalar node ``default_connection``. In general: after defining a node, a call to ``end()`` takes you one step up in the @@ -116,6 +120,10 @@ node definition. Node types are available for: and are created with ``node($name, $type)`` or their associated shortcut ``xxxxNode($name)`` method. +.. versionadded:: + + Support for ``string`` types was introduced in Symfony 7.2. + Numeric Node Constraints ~~~~~~~~~~~~~~~~~~~~~~~~ From 7eb2264b2f1dff013aed0a9ffd32c6974f3f1270 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 8 Nov 2024 14:45:59 +0100 Subject: [PATCH 111/427] fix versionadded directive --- components/config/definition.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/config/definition.rst b/components/config/definition.rst index 4e99fb4f6a7..0db9923a340 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -120,9 +120,9 @@ node definition. Node types are available for: and are created with ``node($name, $type)`` or their associated shortcut ``xxxxNode($name)`` method. -.. versionadded:: +.. versionadded:: 7.2 - Support for ``string`` types was introduced in Symfony 7.2. + Support for the ``string`` type was introduced in Symfony 7.2. Numeric Node Constraints ~~~~~~~~~~~~~~~~~~~~~~~~ From f40f01b78d41fbf7ee52a6f5aba26d866f08129d Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Mon, 11 Nov 2024 17:22:23 +0100 Subject: [PATCH 112/427] [Validator] Improve type for the `mode` property of the `Bic` constraint --- reference/constraints/Bic.rst | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index 3f05e5eac25..313de3bdbbf 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -124,18 +124,13 @@ Parameter Description ``mode`` ~~~~~~~~ -**type**: ``string`` **default**: ``strict`` +**type**: ``string`` **default**: ``BIC::VALIDATION_MODE_STRICT`` -This option defines how the BIC is validated: +This option defines how the BIC is validated. Available constants are defined +in the :class:`Symfony\\Component\\Validator\\Constraints\\BIC` class. -* ``strict`` validates the given value without any modification; -* ``case-insensitive`` converts the given value to uppercase before validating it. - -.. tip:: - - The possible values of this option are also defined as PHP constants of - :class:`Symfony\\Component\\Validator\\Constraints\\BIC` - (e.g. ``BIC::VALIDATION_MODE_CASE_INSENSITIVE``). +* ``BIC::VALIDATION_MODE_STRICT`` validates the given value without any modification; +* ``BIC::VALIDATION_MODE_CASE_INSENSITIVE`` converts the given value to uppercase before validating it. .. versionadded:: 7.2 From bc8c2d222b0f89f92f630ac4de7e5674f9e11a35 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 13 Nov 2024 17:10:23 +0100 Subject: [PATCH 113/427] Minor tweaks --- reference/constraints/Bic.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index 313de3bdbbf..6cde4a11bac 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -124,13 +124,13 @@ Parameter Description ``mode`` ~~~~~~~~ -**type**: ``string`` **default**: ``BIC::VALIDATION_MODE_STRICT`` +**type**: ``string`` **default**: ``Bic::VALIDATION_MODE_STRICT`` -This option defines how the BIC is validated. Available constants are defined -in the :class:`Symfony\\Component\\Validator\\Constraints\\BIC` class. +This option defines how the BIC is validated. The possible values are available +as constants in the :class:`Symfony\\Component\\Validator\\Constraints\\Bic` class: -* ``BIC::VALIDATION_MODE_STRICT`` validates the given value without any modification; -* ``BIC::VALIDATION_MODE_CASE_INSENSITIVE`` converts the given value to uppercase before validating it. +* ``Bic::VALIDATION_MODE_STRICT`` validates the given value without any modification; +* ``Bic::VALIDATION_MODE_CASE_INSENSITIVE`` converts the given value to uppercase before validating it. .. versionadded:: 7.2 From 40058d823673436e935308a05acd87db028fbb7c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 14 Nov 2024 08:39:36 +0100 Subject: [PATCH 114/427] the TypeInfo component is no longer experimental --- components/type_info.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index 30ae11aa222..f46c8f8ab3a 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -11,11 +11,6 @@ This component provides: * A way to get types from PHP elements such as properties, method arguments, return types, and raw strings. -.. caution:: - - This component is :doc:`experimental ` and - could be changed at any time without prior notice. - Installation ------------ From 8b9ca6f5e9c1c4964cebc08b35de6344f5902870 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 16 Nov 2024 10:22:58 +0100 Subject: [PATCH 115/427] remove documentation about no longer existing getBaseType() method --- components/type_info.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index f46c8f8ab3a..bbc7d0ea8dc 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -58,12 +58,6 @@ based on reflection or a simple string:: // Type instances have several helper methods - // returns the main type (e.g. in this example it returns an "array" Type instance); - // for nullable types (e.g. string|null) it returns the non-null type (e.g. string) - // and for compound types (e.g. int|string) it throws an exception because both types - // can be considered the main one, so there's no way to pick one - $baseType = $type->getBaseType(); - // for collections, it returns the type of the item used as the key; // in this example, the collection is a list, so it returns an "int" Type instance $keyType = $type->getCollectionKeyType(); From 7caf0dc9291186e3139738188b0ba827274d6745 Mon Sep 17 00:00:00 2001 From: lacatoire Date: Mon, 18 Nov 2024 11:08:55 +0100 Subject: [PATCH 116/427] Clarify documentation about differences between AutowireIterator and AutowireLocator --- .../service_subscribers_locators.rst | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index da5cb415800..ada84158fcc 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -381,19 +381,48 @@ attribute:: :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` attribute was introduced in Symfony 6.4. -.. note:: +The AutowireIterator Attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Variant of the ``AutowireLocator`` that specifically provides an iterable of services +based on a tag. This allows you to collect all services with a particular tag into +an iterable, which can be useful when you need to iterate over a set of services +rather than retrieving them individually. - To receive an iterable instead of a service locator, you can switch the - :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` - attribute to - :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator` - attribute. +For example, if you want to collect all the handlers for different command types, +you can use the ``AutowireIterator`` attribute to automatically inject all services +tagged with a specific tag:: + + // src/CommandBus.php + namespace App; + + use App\CommandHandler\BarHandler; + use App\CommandHandler\FooHandler; + use Psr\Container\ContainerInterface; + use Symfony\Component\DependencyInjection\Attribute\AutowireIterator; + + class CommandBus + { + public function __construct( + #[AutowireIterator('command_handler')] + private iterable $handlers, // Collects all services tagged with 'command_handler' + ) { + } - .. versionadded:: 6.4 + public function handle(Command $command): mixed + { + foreach ($this->handlers as $handler) { + if ($handler->supports($command)) { + return $handler->handle($command); + } + } + } + } + +.. versionadded:: 6.4 - The - :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator` - attribute was introduced in Symfony 6.4. + The + :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator` + attribute was introduced in Symfony 6.4. .. _service-subscribers-locators_defining-service-locator: From 337b5974e08ee43012ccd3ec6174f35409ccea41 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 23 Nov 2024 18:03:07 +0100 Subject: [PATCH 117/427] More syntax fixes --- serializer/encoders.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer/encoders.rst b/serializer/encoders.rst index 65eece78031..003eb4523fe 100644 --- a/serializer/encoders.rst +++ b/serializer/encoders.rst @@ -65,7 +65,7 @@ are available to customize the behavior of the encoder: ``csv_end_of_line`` (default: ``\n``) Sets the character(s) used to mark the end of each line in the CSV file. ``csv_escape_char`` (default: empty string) - .. deprecated:: + .. deprecated:: 7.2 The ``csv_escape_char`` option was deprecated in Symfony 7.2. From dc999f33194b22851c44ba6147833b1e8003bc8f Mon Sep 17 00:00:00 2001 From: Baptiste Leduc Date: Fri, 15 Nov 2024 10:20:18 +0100 Subject: [PATCH 118/427] Add more details to TypeInfo documentation --- components/type_info.rst | 100 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index bbc7d0ea8dc..18556e02972 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -40,12 +40,24 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: // Many others are available and can be // found in Symfony\Component\TypeInfo\TypeFactoryTrait +Resolvers +~~~~~~~~~ + The second way of using the component is to use ``TypeInfo`` to resolve a type -based on reflection or a simple string:: +based on reflection or a simple string, this is aimed towards libraries that wants to +describe a class or anything that has a type easily:: use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; + class Dummy + { + public function __construct( + public int $id, + ) { + } + } + // Instantiate a new resolver $typeResolver = TypeResolver::create(); @@ -70,6 +82,88 @@ Each of these calls will return you a ``Type`` instance that corresponds to the static method used. You can also resolve types from a string (as shown in the ``bool`` parameter of the previous example) -.. note:: +PHPDoc parsing +~~~~~~~~~~~~~~ - To support raw string resolving, you need to install ``phpstan/phpdoc-parser`` package. +But most times you won't have clean typed properties or you want a more precise type +thank to advanced PHPDoc, to do that you would want a string resolver based on that PHPDoc. +First you will require ``phpstan/phpdoc-parser`` package from composer to support string +revolving. Then you would do as following:: + + use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; + + class Dummy + { + public function __construct( + public int $id, + /** @var string[] $tags */ + public array $tags, + ) { + } + } + + $typeResolver = TypeResolver::create(); + $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type + $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns a collection with "int" as key and "string" as values Type + +Advanced usages +~~~~~~~~~~~~~~~ + +There is many methods to manipulate and check types depending on your needs within the TypeInfo components. + +If you need a check a simple Type:: + + // You need to check if a Type + $type = Type::int(); // with a simple int type + // You can check if a given type comply with a given identifier + $type->isIdentifiedBy(TypeIdentifier::INT); // true + $type->isIdentifiedBy(TypeIdentifier::STRING); // false + + $type = Type::union(Type::string(), Type::int()); // with an union of int and string types + // You can now see that the second check will pass to true since we have an union with a string type + $type->isIdentifiedBy(TypeIdentifier::INT); // true + $type->isIdentifiedBy(TypeIdentifier::STRING); // true + + class DummyParent {} + class Dummy extends DummyParent implements DummyInterface {} + $type = Type::object(Dummy::class); // with an object Type + // You can check is the Type is an object, or even if it's a given class + $type->isIdentifiedBy(TypeIdentifier::OBJECT); // true + $type->isIdentifiedBy(Dummy::class); // true + // Or inherits/implements something + $type->isIdentifiedBy(DummyParent::class); // true + $type->isIdentifiedBy(DummyInterface::class); // true + +Sometimes you want to check for more than one thing at a time so a callable may be better to check everything:: + + class Foo + { + private int $integer; + private string $string; + private ?float $float; + } + + $reflClass = new \ReflectionClass(Foo::class); + + $resolver = TypeResolver::create(); + $integerType = $resolver->resolve($reflClass->getProperty('integer')); + $stringType = $resolver->resolve($reflClass->getProperty('string')); + $floatType = $resolver->resolve($reflClass->getProperty('float')); + + // your callable to check whatever you need + // here we want to validate a given type is a non nullable number + $isNonNullableNumber = function (Type $type): bool { + if ($type->isNullable()) { + return false; + } + + if ($type->isIdentifiedBy(TypeIdentifier::INT) || $type->isIdentifiedBy(TypeIdentifier::FLOAT)) { + return true; + } + + return false; + }; + + $integerType->isSatisfiedBy($isNonNullableNumber); // true + $stringType->isSatisfiedBy($isNonNullableNumber); // false + $floatType->isSatisfiedBy($isNonNullableNumber); // false From 03b029b9f3d144573b16f94a56e51aa7666e1342 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Wed, 27 Nov 2024 06:36:46 +0100 Subject: [PATCH 119/427] minor cs fix for ci --- serializer/encoders.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/serializer/encoders.rst b/serializer/encoders.rst index 003eb4523fe..e36d8731e48 100644 --- a/serializer/encoders.rst +++ b/serializer/encoders.rst @@ -65,6 +65,7 @@ are available to customize the behavior of the encoder: ``csv_end_of_line`` (default: ``\n``) Sets the character(s) used to mark the end of each line in the CSV file. ``csv_escape_char`` (default: empty string) + .. deprecated:: 7.2 The ``csv_escape_char`` option was deprecated in Symfony 7.2. From e427a6cb7466dba166e17f446b0f5a210757c8b9 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Wed, 27 Nov 2024 06:18:03 +0100 Subject: [PATCH 120/427] [Security] Secret with remember me feature --- security/remember_me.rst | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/security/remember_me.rst b/security/remember_me.rst index 8fac6d78849..2fd0f7e8d1e 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -19,7 +19,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option: main: # ... remember_me: - secret: '%kernel.secret%' # required + secret: '%kernel.secret%' lifetime: 604800 # 1 week in seconds # by default, the feature is enabled by checking a # checkbox in the login form (see below), uncomment the @@ -44,7 +44,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option: - firewall('main') // ... ->rememberMe() - ->secret('%kernel.secret%') // required + ->secret('%kernel.secret%') ->lifetime(604800) // 1 week in seconds // by default, the feature is enabled by checking a @@ -77,9 +77,11 @@ the session lasts using a cookie with the ``remember_me`` firewall option: ; }; -The ``secret`` option is the only required option and it is used to sign -the remember me cookie. It's common to use the ``kernel.secret`` parameter, -which is defined using the ``APP_SECRET`` environment variable. +.. versionadded:: 7.2 + + The ``secret`` option is no longer required starting from Symfony 7.2. By + default, ``%kernel.secret%`` is used, which is defined using the + ``APP_SECRET`` environment variable. After enabling the ``remember_me`` system in the configuration, there are a couple more things to do before remember me works correctly: @@ -171,7 +173,6 @@ allow users to opt-out. In these cases, you can use the main: # ... remember_me: - secret: '%kernel.secret%' # ... always_remember_me: true @@ -194,7 +195,6 @@ allow users to opt-out. In these cases, you can use the @@ -211,7 +211,6 @@ allow users to opt-out. In these cases, you can use the $security->firewall('main') // ... ->rememberMe() - ->secret('%kernel.secret%') // ... ->alwaysRememberMe(true) ; @@ -335,7 +334,6 @@ are fetched from the user object using the main: # ... remember_me: - secret: '%kernel.secret%' # ... signature_properties: ['password', 'updatedAt'] @@ -357,7 +355,7 @@ are fetched from the user object using the - + password updatedAt @@ -375,7 +373,6 @@ are fetched from the user object using the $security->firewall('main') // ... ->rememberMe() - ->secret('%kernel.secret%') // ... ->signatureProperties(['password', 'updatedAt']) ; @@ -419,7 +416,6 @@ You can enable the doctrine token provider using the ``doctrine`` setting: main: # ... remember_me: - secret: '%kernel.secret%' # ... token_provider: doctrine: true @@ -442,7 +438,7 @@ You can enable the doctrine token provider using the ``doctrine`` setting: - + @@ -459,7 +455,6 @@ You can enable the doctrine token provider using the ``doctrine`` setting: $security->firewall('main') // ... ->rememberMe() - ->secret('%kernel.secret%') // ... ->tokenProvider([ 'doctrine' => true, From c71b9f93795d90f0ae377f17026173f1e1c949a5 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Mon, 2 Dec 2024 08:38:44 +0100 Subject: [PATCH 121/427] remove a gc_probability default mention --- session.rst | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/session.rst b/session.rst index 393cd24a898..aa4c3ba381f 100644 --- a/session.rst +++ b/session.rst @@ -494,18 +494,7 @@ deleted. This allows one to expire records based on idle time. However, some operating systems (e.g. Debian) do their own session handling and set the ``session.gc_probability`` variable to ``0`` to stop PHP doing garbage -collection. That's why Symfony now overwrites this value to ``1``. - -If you wish to use the original value set in your ``php.ini``, add the following -configuration: - -.. code-block:: yaml - - # config/packages/framework.yaml - framework: - session: - # ... - gc_probability: null +collection. You can configure these settings by passing ``gc_probability``, ``gc_divisor`` and ``gc_maxlifetime`` in an array to the constructor of @@ -513,6 +502,10 @@ and ``gc_maxlifetime`` in an array to the constructor of or to the :method:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage::setOptions` method. +.. versionadded:: 7.2 + + Starting from Symfony 7.2, ``php.ini``'s directive is used as default for ``gc_probability``. + .. _session-database: Store Sessions in a Database From 2083dc2eb14cc9b7d7213249d4d0437d36b997ce Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Mon, 2 Dec 2024 10:40:51 +0100 Subject: [PATCH 122/427] Allow integer for the calendar option of DateType --- reference/forms/types/date.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index e88e91d80dd..6b8d21a19bd 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -156,11 +156,12 @@ values for the year, month and day fields:: ``calendar`` ~~~~~~~~~~~~ -**type**: ``\IntlCalendar`` **default**: ``null`` +**type**: ``integer`` or ``\IntlCalendar`` **default**: ``null`` The calendar to use for formatting and parsing the date. The value should be -an instance of the :phpclass:`IntlCalendar` to use. By default, the Gregorian -calendar with the application default locale is used. +an ``integer`` from :phpclass:`IntlDateFormatter` calendar constants or an instance +of the :phpclass:`IntlCalendar` to use. By default, the Gregorian calendar +with the application default locale is used. .. versionadded:: 7.2 From a0f7fab6e75ac4b76e21f5f412132f1bebed375a Mon Sep 17 00:00:00 2001 From: Morf <1416936+m0rff@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:10:23 +0100 Subject: [PATCH 123/427] fix: Update micro_kernel_trait.rst --- configuration/micro_kernel_trait.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index c9739679f69..62e8c2d4128 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -16,7 +16,7 @@ via Composer: .. code-block:: terminal - $ composer symfony/framework-bundle symfony/runtime + $ composer require symfony/framework-bundle symfony/runtime Next, create an ``index.php`` file that defines the kernel class and runs it: From 646e1995c71abf8b84e75c51cc355b1cc5e258b4 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Mon, 2 Dec 2024 10:13:27 +0100 Subject: [PATCH 124/427] [Messenger] Document `getRetryDelay()` --- messenger.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/messenger.rst b/messenger.rst index 74f7d792436..aa46ef9b1d3 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1134,6 +1134,13 @@ and must be retried. If you throw :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableMessageHandlingException`, the message will always be retried infinitely and ``max_retries`` setting will be ignored. +If you want to override retry delay form the retry strategy. You can achieve this +using by providing it in the exception, using the ``getRetryDelay()`` method from :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableExceptionInterface`. + +.. versionadded:: 7.2 + + The method ``getRetryDelay()`` was introduced in Symfony 7.2. + .. _messenger-failure-transport: Saving & Retrying Failed Messages From f99ae716aeb01cc279f4def8386f4d4fa7d7c190 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 2 Dec 2024 16:21:58 +0100 Subject: [PATCH 125/427] Reword --- messenger.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index 35db17a75b3..053ccfd172e 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1134,12 +1134,14 @@ and must be retried. If you throw :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableMessageHandlingException`, the message will always be retried infinitely and ``max_retries`` setting will be ignored. -If you want to override retry delay form the retry strategy. You can achieve this -using by providing it in the exception, using the ``getRetryDelay()`` method from :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableExceptionInterface`. +You can define a custom retry delay (e.g., to use the value from the ``Retry-After`` +header in an HTTP response) by setting the ``retryDelay`` argument in the +constructor of the ``RecoverableMessageHandlingException``. .. versionadded:: 7.2 - The method ``getRetryDelay()`` was introduced in Symfony 7.2. + The ``retryDelay`` argument and the ``getRetryDelay()`` method were introduced + in Symfony 7.2. .. _messenger-failure-transport: From 977be3230885146769f8304e9aa0a578b4cc372e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 2 Dec 2024 16:34:09 +0100 Subject: [PATCH 126/427] Reword --- session.rst | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/session.rst b/session.rst index aa4c3ba381f..e3f2246b6f6 100644 --- a/session.rst +++ b/session.rst @@ -492,19 +492,30 @@ the ``php.ini`` directive ``session.gc_maxlifetime``. The meaning in this contex that any stored session that was saved more than ``gc_maxlifetime`` ago should be deleted. This allows one to expire records based on idle time. -However, some operating systems (e.g. Debian) do their own session handling and set -the ``session.gc_probability`` variable to ``0`` to stop PHP doing garbage -collection. +However, some operating systems (e.g. Debian) manage session handling differently +and set the ``session.gc_probability`` variable to ``0`` to prevent PHP from performing +garbage collection. By default, Symfony uses the value of the ``gc_probability`` +directive set in the ``php.ini`` file. If you can't modify this PHP setting, you +can configure it directly in Symfony: -You can configure these settings by passing ``gc_probability``, ``gc_divisor`` -and ``gc_maxlifetime`` in an array to the constructor of +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + session: + # ... + gc_probability: 1 + +Alternatively, you can configure these settings by passing ``gc_probability``, +``gc_divisor`` and ``gc_maxlifetime`` in an array to the constructor of :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage` or to the :method:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage::setOptions` method. .. versionadded:: 7.2 - Starting from Symfony 7.2, ``php.ini``'s directive is used as default for ``gc_probability``. + Using the ``php.ini`` directive as the default value for ``gc_probability`` + was introduced in Symfony 7.2. .. _session-database: From 00a781fdd643e516a6f196e84e765716e5a99e44 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Mon, 2 Dec 2024 17:25:05 +0100 Subject: [PATCH 127/427] Update mailer.rst: Changing order of tips Page: https://symfony.com/doc/current/mailer.html#email-addresses Reason: Bring the 2 IDN-related tips together. --- mailer.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mailer.rst b/mailer.rst index 8ff13c2561a..9cfba6c1a71 100644 --- a/mailer.rst +++ b/mailer.rst @@ -560,17 +560,17 @@ both strings or address objects:: // ... ; -.. versionadded:: 7.2 - - Support for non-ASCII email addresses (e.g. ``jânë.dœ@ëxãmplę.com``) - was introduced in Symfony 7.2. - .. tip:: Instead of calling ``->from()`` *every* time you create a new email, you can :ref:`configure emails globally ` to set the same ``From`` email to all messages. +.. versionadded:: 7.2 + + Support for non-ASCII email addresses (e.g. ``jânë.dœ@ëxãmplę.com``) + was introduced in Symfony 7.2. + .. note:: The local part of the address (what goes before the ``@``) can include UTF-8 From ec2743dd19e580971b8707eff6a66edcdf9f10a2 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Tue, 3 Dec 2024 12:05:33 +0100 Subject: [PATCH 128/427] [HttpFoundation] Do not use named parameters in example --- components/http_foundation.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 4dcf3b1e4da..c91ec5ced8f 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -367,11 +367,13 @@ of the ``anonymize()`` method to specify the number of bytes that should be anonymized depending on the IP address format:: $ipv4 = '123.234.235.236'; - $anonymousIpv4 = IpUtils::anonymize($ipv4, v4Bytes: 3); + $anonymousIpv4 = IpUtils::anonymize($ipv4, 3); // $anonymousIpv4 = '123.0.0.0' $ipv6 = '2a01:198:603:10:396e:4789:8e99:890f'; - $anonymousIpv6 = IpUtils::anonymize($ipv6, v6Bytes: 10); + // (you must define the second argument (bytes to anonymize in IPv4 addresses) + // even when you are only anonymizing IPv6 addresses) + $anonymousIpv6 = IpUtils::anonymize($ipv6, 3, 10); // $anonymousIpv6 = '2a01:198:603::' .. versionadded:: 7.2 From f58f1ebfa747a4aa900710abed46b0563f55fb76 Mon Sep 17 00:00:00 2001 From: Tim Goudriaan Date: Sat, 7 Dec 2024 11:53:08 +0100 Subject: [PATCH 129/427] [Scheduler] Periodical triggers timing --- scheduler.rst | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/scheduler.rst b/scheduler.rst index 160ba26e0cb..9407b85e57f 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -286,14 +286,37 @@ defined by PHP datetime functions:: RecurringMessage::every('3 weeks', new Message()); RecurringMessage::every('first Monday of next month', new Message()); - $from = new \DateTimeImmutable('13:47', new \DateTimeZone('Europe/Paris')); - $until = '2023-06-12'; - RecurringMessage::every('first Monday of next month', new Message(), $from, $until); - .. tip:: You can also define periodic tasks using :ref:`the AsPeriodicTask attribute `. +Be aware that the message isn't passed to the messenger when you start the +scheduler. The message will only be executed after the first frequency period +has passed. + +It's also possible to pass a from and until time for your schedule. For +example, if you want to execute a command every day at 13:00:: + + $from = new \DateTimeImmutable('13:00', new \DateTimeZone('Europe/Paris')); + RecurringMessage::every('1 day', new Message(), from: $from); + +Or if you want to execute a message every day until a specific date:: + + $until = '2023-06-12'; + RecurringMessage::every('1 day', new Message(), until: $until); + +And you can even combine the from and until parameters for more granular +control:: + + $from = new \DateTimeImmutable('2023-01-01 13:47', new \DateTimeZone('Europe/Paris')); + $until = '2023-06-12'; + RecurringMessage::every('first Monday of next month', new Message(), from: $from, until: $until); + +If you don't pass a from parameter to your schedule, the first frequency period +is counted from the moment the scheduler is started. So if you start your +scheduler at 8:33 and the message is scheduled to perform every hour, it +will be executed at 9:33, 10:33, 11:33 and so on. + Custom Triggers ~~~~~~~~~~~~~~~ From c14a4e733e4ba53e7fc5746356465d8924b22f5c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 7 Dec 2024 10:48:52 +0100 Subject: [PATCH 130/427] [AssetMapper] Document the feature that precompresses assets --- frontend/asset_mapper.rst | 61 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index f519c7c6109..708de32979f 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -656,7 +656,9 @@ which will automatically do most of these things for you: - **Compress your assets**: Your web server should compress (e.g. using gzip) your assets (JavaScript, CSS, images) before sending them to the browser. This is automatically enabled in Caddy and can be activated in Nginx and Apache. - In Cloudflare, assets are compressed by default. + In Cloudflare, assets are compressed by default. AssetMapper also supports + :ref:`precompressing your web assets ` to further + improve performance. - **Set long-lived cache expiry**: Your web server should set a long-lived ``Cache-Control`` HTTP header on your assets. Because the AssetMapper component includes a version @@ -704,6 +706,57 @@ even though it hasn't yet seen the ``import`` statement for them. Additionally, if the :doc:`WebLink Component ` is available in your application, Symfony will add a ``Link`` header in the response to preload the CSS files. +.. _performance-precompressing: + +Pre-Compressing Assets +---------------------- + +Although most servers (Caddy, Nginx, Apache, FrankenPHP) and services like Cloudflare +provide asset compression features, AssetMapper also allows you to compress all +your assets before serving them. + +This improves performance because you can compress assets using the highest (and +slowest) compression ratios beforehand and provide those compressed assets to the +server, which then returns them to the client without wasting CPU resources on +compression. + +AssetMapper supports `Brotli`_, `Zstandard`_ and `gzip`_ compression formats. +Before using any of them, the server that pre-compresses assets must have +installed the following PHP extensions or CLI commands: + +* Brotli: ``brotli`` CLI command; `brotli PHP extension`_; +* Zstandard: ``zstd`` CLI command; `zstd PHP extension`_; +* gzip: ``gzip`` CLI command; `zlib PHP extension`_. + +Then, update your AssetMapper configuration to define which compression to use +and which file extensions should be compressed: + +.. code-block:: yaml + + # config/packages/asset_mapper.yaml + framework: + asset_mapper: + # ... + + precompress: + format: 'zstandard' + # if you don't define the following option, AssetMapper will compress all + # the extensions considered safe (css, js, json, svg, xml, ttf, otf, wasm, etc.) + extensions: ['css', 'js', 'json', 'svg', 'xml'] + +Now, when running the ``asset-map:compile`` command, all matching files will be +compressed in the configured format and at the highest compression level. The +compressed files are created with the same name as the original but with the +``.br``, ``.zst``, or ``.gz`` extension appended. Web servers that support asset +precompression will use the compressed assets automatically, so there's nothing +else to configure in your server. + +.. tip:: + + AssetMapper provides an ``assets:compress`` CLI command and a service called + ``asset_mapper.compressor`` that you can use anywhere in your application to + compress any kind of files (e.g. files uploaded by users to your application). + Frequently Asked Questions -------------------------- @@ -1195,3 +1248,9 @@ command as part of your CI to be warned anytime a new vulnerability is found. .. _strict-dynamic: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#strict-dynamic .. _kocal/biome-js-bundle: https://github.com/Kocal/BiomeJsBundle .. _`SensioLabs Minify Bundle`: https://github.com/sensiolabs/minify-bundle +.. _`Brotli`: https://en.wikipedia.org/wiki/Brotli +.. _`Zstandard`: https://en.wikipedia.org/wiki/Zstd +.. _`gzip`: https://en.wikipedia.org/wiki/Gzip +.. _`brotli PHP extension`: https://pecl.php.net/package/brotli +.. _`zstd PHP extension`: https://pecl.php.net/package/zstd +.. _`zlib PHP extension`: https://www.php.net/manual/en/book.zlib.php From 0a3fb8d716fd0adf21d56762821ce7b19f71b90b Mon Sep 17 00:00:00 2001 From: Timo Bakx Date: Sat, 7 Dec 2024 12:19:15 +0100 Subject: [PATCH 131/427] Replaced `caution` directive by `warning` Fixes #20371 --- reference/forms/types/options/choice_lazy.rst.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/options/choice_lazy.rst.inc b/reference/forms/types/options/choice_lazy.rst.inc index bdcbf178406..08fbe953e41 100644 --- a/reference/forms/types/options/choice_lazy.rst.inc +++ b/reference/forms/types/options/choice_lazy.rst.inc @@ -24,7 +24,7 @@ will only load and render the choices that are preset as default values or submitted. This defers the loading of the full list of choices, helping to improve your form's performance. -.. caution:: +.. warning:: Keep in mind that when using ``choice_lazy``, you are responsible for providing the user interface for selecting choices, typically through a From 1d690fc9714cf2ebb6506c3656e6aa6e7909c33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 7 Dec 2024 17:04:18 +0100 Subject: [PATCH 132/427] [AssetMapper] mention Zopfli pre-compression and add config for web servers --- frontend/asset_mapper.rst | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index b55803e157f..e83da5aa42b 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -726,7 +726,7 @@ installed the following PHP extensions or CLI commands: * Brotli: ``brotli`` CLI command; `brotli PHP extension`_; * Zstandard: ``zstd`` CLI command; `zstd PHP extension`_; -* gzip: ``gzip`` CLI command; `zlib PHP extension`_. +* gzip: ``zopfli`` (better) or ``gzip`` CLI command; `zlib PHP extension`_. Then, update your AssetMapper configuration to define which compression to use and which file extensions should be compressed: @@ -751,6 +751,27 @@ compressed files are created with the same name as the original but with the precompression will use the compressed assets automatically, so there's nothing else to configure in your server. +Finally, you need to configure your web server to serve the precompressed assets +instead of the original ones: + +.. configuration-block:: + + .. code-block:: caddy + + file_server { + precompressed br zstd gzip + } + + .. code-block:: nginx + + gzip_static on; + + # Requires https://github.com/google/ngx_brotli + brotli_static on; + + # Requires https://github.com/tokers/zstd-nginx-module + zstd_static on; + .. tip:: AssetMapper provides an ``assets:compress`` CLI command and a service called From 9eb33c848bcf7ba26e42f7b8a080358933218cdc Mon Sep 17 00:00:00 2001 From: Antoine M Date: Tue, 10 Dec 2024 12:08:13 +0100 Subject: [PATCH 133/427] Update security.rst --- reference/configuration/security.rst | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index b89aab67608..ac9e0382fa5 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -1075,6 +1075,58 @@ the session must not be used when authenticating users: // ... }; +.. _reference-security-lazy: + +lazy +~~~~~~~~~ + +Firewalls can configure a ``lazy`` boolean option in order to load the user and start the session only +if the application actually accesses the User object, +(e.g. via a is_granted() call in a template or isGranted() in a controller or service): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + lazy: true + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security): void { + $mainFirewall = $security->firewall('main'); + $mainFirewall->lazy(true); + // ... + }; + User Checkers ~~~~~~~~~~~~~ From 405f95ef8844382504372d0dc85178505d7cdfed Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 10 Dec 2024 15:51:38 +0100 Subject: [PATCH 134/427] Minor reword --- components/type_info.rst | 64 ++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index 18556e02972..734ac4140ba 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -43,9 +43,9 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: Resolvers ~~~~~~~~~ -The second way of using the component is to use ``TypeInfo`` to resolve a type -based on reflection or a simple string, this is aimed towards libraries that wants to -describe a class or anything that has a type easily:: +The second way to use the component is by using ``TypeInfo`` to resolve a type +based on reflection or a simple string. This approach is designed for libraries +that need a simple way to describe a class or anything with a type:: use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; @@ -82,13 +82,15 @@ Each of these calls will return you a ``Type`` instance that corresponds to the static method used. You can also resolve types from a string (as shown in the ``bool`` parameter of the previous example) -PHPDoc parsing +PHPDoc Parsing ~~~~~~~~~~~~~~ -But most times you won't have clean typed properties or you want a more precise type -thank to advanced PHPDoc, to do that you would want a string resolver based on that PHPDoc. -First you will require ``phpstan/phpdoc-parser`` package from composer to support string -revolving. Then you would do as following:: +In many cases, you may not have cleanly typed properties or may need more precise +type definitions provided by advanced PHPDoc. To achieve this, you can use a string +resolver based on the PHPDoc annotations. + +First, run the command ``composer require phpstan/phpdoc-parser`` to install the +PHP package required for string resolving. Then, follow these steps:: use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; @@ -106,35 +108,40 @@ revolving. Then you would do as following:: $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns a collection with "int" as key and "string" as values Type -Advanced usages +Advanced Usages ~~~~~~~~~~~~~~~ -There is many methods to manipulate and check types depending on your needs within the TypeInfo components. +The TypeInfo component provides various methods to manipulate and check types, +depending on your needs. -If you need a check a simple Type:: +Checking a **simple type**:: - // You need to check if a Type - $type = Type::int(); // with a simple int type - // You can check if a given type comply with a given identifier - $type->isIdentifiedBy(TypeIdentifier::INT); // true + // define a simple integer type + $type = Type::int(); + // check if the type matches a specific identifier + $type->isIdentifiedBy(TypeIdentifier::INT); // true $type->isIdentifiedBy(TypeIdentifier::STRING); // false - $type = Type::union(Type::string(), Type::int()); // with an union of int and string types - // You can now see that the second check will pass to true since we have an union with a string type - $type->isIdentifiedBy(TypeIdentifier::INT); // true + // define a union type (equivalent to PHP's int|string) + $type = Type::union(Type::string(), Type::int()); + // now the second check is true because the union type contains the string type + $type->isIdentifiedBy(TypeIdentifier::INT); // true $type->isIdentifiedBy(TypeIdentifier::STRING); // true class DummyParent {} class Dummy extends DummyParent implements DummyInterface {} - $type = Type::object(Dummy::class); // with an object Type - // You can check is the Type is an object, or even if it's a given class + + // define an object type + $type = Type::object(Dummy::class); + + // check if the type is an object or matches a specific class $type->isIdentifiedBy(TypeIdentifier::OBJECT); // true - $type->isIdentifiedBy(Dummy::class); // true - // Or inherits/implements something - $type->isIdentifiedBy(DummyParent::class); // true - $type->isIdentifiedBy(DummyInterface::class); // true + $type->isIdentifiedBy(Dummy::class); // true + // check if it inherits/implements something + $type->isIdentifiedBy(DummyParent::class); // true + $type->isIdentifiedBy(DummyInterface::class); // true -Sometimes you want to check for more than one thing at a time so a callable may be better to check everything:: +Using callables for **complex checks**: class Foo { @@ -150,8 +157,7 @@ Sometimes you want to check for more than one thing at a time so a callable may $stringType = $resolver->resolve($reflClass->getProperty('string')); $floatType = $resolver->resolve($reflClass->getProperty('float')); - // your callable to check whatever you need - // here we want to validate a given type is a non nullable number + // define a callable to validate non-nullable number types $isNonNullableNumber = function (Type $type): bool { if ($type->isNullable()) { return false; @@ -165,5 +171,5 @@ Sometimes you want to check for more than one thing at a time so a callable may }; $integerType->isSatisfiedBy($isNonNullableNumber); // true - $stringType->isSatisfiedBy($isNonNullableNumber); // false - $floatType->isSatisfiedBy($isNonNullableNumber); // false + $stringType->isSatisfiedBy($isNonNullableNumber); // false + $floatType->isSatisfiedBy($isNonNullableNumber); // false From f87bbdf690f629b3096a1f8d0848f471d5e966ed Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Wed, 11 Dec 2024 10:38:18 +0100 Subject: [PATCH 135/427] [HttpFoundation] Add StreamedResponse string iterable documentation --- components/http_foundation.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index c91ec5ced8f..8db6cd27f68 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -681,8 +681,19 @@ Streaming a Response ~~~~~~~~~~~~~~~~~~~~ The :class:`Symfony\\Component\\HttpFoundation\\StreamedResponse` class allows -you to stream the Response back to the client. The response content is -represented by a PHP callable instead of a string:: +you to stream the Response back to the client. The response content can be +represented by a string iterable:: + + use Symfony\Component\HttpFoundation\StreamedResponse; + + $chunks = ['Hello', ' World']; + + $response = new StreamedResponse(); + $response->setChunks($chunks); + $response->send(); + +For most complex use cases, the response content can be instead represented by +a PHP callable:: use Symfony\Component\HttpFoundation\StreamedResponse; @@ -710,6 +721,10 @@ represented by a PHP callable instead of a string:: // disables FastCGI buffering in nginx only for this response $response->headers->set('X-Accel-Buffering', 'no'); +.. versionadded:: 7.3 + + Support for using string iterables was introduced in Symfony 7.3. + Streaming a JSON Response ~~~~~~~~~~~~~~~~~~~~~~~~~ From b66e743657a527d4c14e3e4a1330893c6956cc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20L=C3=A9v=C3=AAque?= Date: Wed, 11 Dec 2024 17:11:32 +0100 Subject: [PATCH 136/427] [Console] Add support of millisecondes for formatTime --- components/console/helpers/formatterhelper.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/console/helpers/formatterhelper.rst b/components/console/helpers/formatterhelper.rst index 3cb87c4c307..bff0c82c90f 100644 --- a/components/console/helpers/formatterhelper.rst +++ b/components/console/helpers/formatterhelper.rst @@ -129,10 +129,12 @@ Sometimes you want to format seconds to time. This is possible with the The first argument is the seconds to format and the second argument is the precision (default ``1``) of the result:: - Helper::formatTime(42); // 42 secs - Helper::formatTime(125); // 2 mins - Helper::formatTime(125, 2); // 2 mins, 5 secs - Helper::formatTime(172799, 4); // 1 day, 23 hrs, 59 mins, 59 secs + Helper::formatTime(0.001); // 1 ms + Helper::formatTime(42); // 42 s + Helper::formatTime(125); // 2 min + Helper::formatTime(125, 2); // 2 min, 5 s + Helper::formatTime(172799, 4); // 1 d, 23 h, 59 min, 59 s + Helper::formatTime(172799.056, 5); // 1 d, 23 h, 59 min, 59 s, 56 ms Formatting Memory ----------------- From bf5dd100d61c54ed6e4ed729198d2d04a64940a0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 12 Dec 2024 10:56:45 +0100 Subject: [PATCH 137/427] Add the versionadded directive --- components/console/helpers/formatterhelper.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/console/helpers/formatterhelper.rst b/components/console/helpers/formatterhelper.rst index bff0c82c90f..d2b19915a3a 100644 --- a/components/console/helpers/formatterhelper.rst +++ b/components/console/helpers/formatterhelper.rst @@ -136,6 +136,10 @@ precision (default ``1``) of the result:: Helper::formatTime(172799, 4); // 1 d, 23 h, 59 min, 59 s Helper::formatTime(172799.056, 5); // 1 d, 23 h, 59 min, 59 s, 56 ms +.. versionadded:: 7.3 + + Support for formatting up to milliseconds was introduced in Symfony 7.3. + Formatting Memory ----------------- From eb5ffa691cc0239d89c72d9ca74897b2e85b23fc Mon Sep 17 00:00:00 2001 From: Baptiste Leduc Date: Thu, 12 Dec 2024 11:48:47 +0100 Subject: [PATCH 138/427] Fix PHP block in TypeInfo documentation --- components/type_info.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/type_info.rst b/components/type_info.rst index 734ac4140ba..e7062c5f249 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -141,7 +141,7 @@ Checking a **simple type**:: $type->isIdentifiedBy(DummyParent::class); // true $type->isIdentifiedBy(DummyInterface::class); // true -Using callables for **complex checks**: +Using callables for **complex checks**:: class Foo { From 3e4bcf17aae617ddf5295e53b95bd505b1a1d509 Mon Sep 17 00:00:00 2001 From: Baptiste Leduc Date: Thu, 12 Dec 2024 11:48:47 +0100 Subject: [PATCH 139/427] Fix PHP block in TypeInfo documentation --- components/type_info.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/type_info.rst b/components/type_info.rst index 734ac4140ba..e7062c5f249 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -141,7 +141,7 @@ Checking a **simple type**:: $type->isIdentifiedBy(DummyParent::class); // true $type->isIdentifiedBy(DummyInterface::class); // true -Using callables for **complex checks**: +Using callables for **complex checks**:: class Foo { From 2fdd0dbfd61d9bd93d679c8febedcddca40d5e3a Mon Sep 17 00:00:00 2001 From: Felix Eymonot Date: Tue, 17 Dec 2024 12:19:23 +0100 Subject: [PATCH 140/427] docs(controller): add docs for key option in MapQueryString --- controller.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/controller.rst b/controller.rst index c11615d93aa..5da85057bbe 100644 --- a/controller.rst +++ b/controller.rst @@ -443,6 +443,27 @@ HTTP status to return if the validation fails:: The default status code returned if the validation fails is 404. +If you want to map your object to a nested array in your query with a specific key, +you can use the ``key`` option in your :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString` +attribute:: + + use App\Model\SearchDto; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\HttpKernel\Attribute\MapQueryString; + + // ... + + public function dashboard( + #[MapQueryString(key: 'search')] SearchDto $searchDto + ): Response + { + // ... + } + +.. versionadded:: 7.3 + + The ``key`` option of ``#[MapQueryString]`` was introduced in Symfony 7.3. + If you need a valid DTO even when the request query string is empty, set a default value for your controller arguments:: From 8aeceab63ce821c69bb182377ad1c3c0b54bf17e Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 17 Dec 2024 13:06:15 +0100 Subject: [PATCH 141/427] Fix the configuration for custom password strength estimator --- reference/constraints/PasswordStrength.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/PasswordStrength.rst b/reference/constraints/PasswordStrength.rst index 671b5f495ef..60125a763a1 100644 --- a/reference/constraints/PasswordStrength.rst +++ b/reference/constraints/PasswordStrength.rst @@ -178,7 +178,7 @@ service to use your own estimator: class: App\Validator\CustomPasswordStrengthEstimator Symfony\Component\Validator\Constraints\PasswordStrengthValidator: - arguments: [!service_closure '@custom_password_strength_estimator'] + arguments: [!closure '@custom_password_strength_estimator'] .. code-block:: xml @@ -192,7 +192,7 @@ service to use your own estimator: - + @@ -210,5 +210,5 @@ service to use your own estimator: $services->set('custom_password_strength_estimator', CustomPasswordStrengthEstimator::class); $services->set(PasswordStrengthValidator::class) - ->args([service_closure('custom_password_strength_estimator')]); + ->args([closure('custom_password_strength_estimator')]); }; From c196b447547b28048a9f1d5849f6964e982933ad Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Thu, 9 Mar 2023 09:10:30 -0500 Subject: [PATCH 142/427] Add tip for using new isGrantedForUser() function --- security.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/security.rst b/security.rst index c8dfc8d6233..5da16121b30 100644 --- a/security.rst +++ b/security.rst @@ -2585,6 +2585,18 @@ want to include extra details only for users that have a ``ROLE_SALES_ADMIN`` ro // ... } +.. tip:: + + Using ``isGranted()`` checks authorization against the currently logged in user. If you need to check + against a user that is not the one logged in or if checking authorization when the user session is not + available in a CLI context (example: message queue, cronjob) ``isGrantedForUser()`` can be used to set the + target user explicitly. + + .. versionadded:: 7.3 + + The :method:`Symfony\\Bundle\\SecurityBundle\\Security::isGrantedForUser` + method was introduced in Symfony 7.3. + If you're using the :ref:`default services.yaml configuration `, Symfony will automatically pass the ``security.helper`` to your service thanks to autowiring and the ``Security`` type-hint. From f10c7e9f81e4db9cba84d03027ca7eccf0a9e31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20PLANUS?= <48881747+leo29plns@users.noreply.github.com> Date: Thu, 19 Dec 2024 08:06:37 +0100 Subject: [PATCH 143/427] Update 7.2.x-dev to 7.2.x --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index 1d7081e93b7..853b53f2400 100644 --- a/setup.rst +++ b/setup.rst @@ -48,10 +48,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_directory --version="7.2.x-dev" --webapp + $ symfony new my_project_directory --version="7.2.x" --webapp # run this if you are building a microservice, console application or API - $ symfony new my_project_directory --version="7.2.x-dev" + $ symfony new my_project_directory --version="7.2.x" The only difference between these two commands is the number of packages installed by default. The ``--webapp`` option installs extra packages to give @@ -63,12 +63,12 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/skeleton:"7.2.x-dev" my_project_directory + $ composer create-project symfony/skeleton:"7.2.x" my_project_directory $ cd my_project_directory $ composer require webapp # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"7.2.x-dev" my_project_directory + $ composer create-project symfony/skeleton:"7.2.x" my_project_directory No matter which command you run to create the Symfony application. All of them will create a new ``my_project_directory/`` directory, download some dependencies From ccdeed257e1e882374a185b18437933694b94bb7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Dec 2024 17:47:14 +0100 Subject: [PATCH 144/427] Minor tweak --- controller.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/controller.rst b/controller.rst index 5da85057bbe..026e76ed0a6 100644 --- a/controller.rst +++ b/controller.rst @@ -443,9 +443,8 @@ HTTP status to return if the validation fails:: The default status code returned if the validation fails is 404. -If you want to map your object to a nested array in your query with a specific key, -you can use the ``key`` option in your :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString` -attribute:: +If you want to map your object to a nested array in your query using a specific key, +set the ``key`` option in the ``#[MapQueryString]`` attribute:: use App\Model\SearchDto; use Symfony\Component\HttpFoundation\Response; From d99915066523753285953b349f1a9782cc353fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sun, 22 Dec 2024 14:40:09 +0100 Subject: [PATCH 145/427] [AssetMapper] Update hash examples Since 7.2, hash are shorter. This PR updates the various hashes in code examples, to illustrate more precisely what a user will see on its local install / code. --- frontend/asset_mapper.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index decc7827e0d..95b656f043d 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -12,7 +12,7 @@ The component has two main features: * :ref:`Mapping & Versioning Assets `: All files inside of ``assets/`` are made available publicly and **versioned**. You can reference the file ``assets/images/product.jpg`` in a Twig template with ``{{ asset('images/product.jpg') }}``. - The final URL will include a version hash, like ``/assets/images/product-3c16d9220694c0e56d8648f25e6035e9.jpg``. + The final URL will include a version hash, like ``/assets/images/product-3c16d92m.jpg``. * :ref:`Importmaps `: A native browser feature that makes it easier to use the JavaScript ``import`` statement (e.g. ``import { Modal } from 'bootstrap'``) @@ -70,7 +70,7 @@ The path - ``images/duck.png`` - is relative to your mapped directory (``assets/ This is known as the **logical path** to your asset. If you look at the HTML in your page, the URL will be something -like: ``/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png``. If you change +like: ``/assets/images/duck-3c16d92m.png``. If you change the file, the version part of the URL will also change automatically. .. _asset-mapper-compile-assets: @@ -78,7 +78,7 @@ the file, the version part of the URL will also change automatically. Serving Assets in dev vs prod ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the ``dev`` environment, the URL ``/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png`` +In the ``dev`` environment, the URL ``/assets/images/duck-3c16d92m.png`` is handled and returned by your Symfony app. For the ``prod`` environment, before deploy, you should run: @@ -283,9 +283,9 @@ outputs an `importmap`_: @@ -342,8 +342,8 @@ The ``importmap()`` function also outputs a set of "preloads": .. code-block:: html - - + + This is a performance optimization and you can learn more about below in :ref:`Performance: Add Preloading `. @@ -494,9 +494,9 @@ for ``duck.png``: .. code-block:: css - /* public/assets/styles/app-3c16d9220694c0e56d8648f25e6035e9.css */ + /* public/assets/styles/app-3c16d92m.css */ .quack { - background-image: url('../images/duck-3c16d9220694c0e56d8648f25e6035e9.png'); + background-image: url('../images/duck-3c16d92m.png'); } .. _asset-mapper-tailwind: @@ -573,7 +573,7 @@ Sometimes a JavaScript file you're importing (e.g. ``import './duck.js'``), or a CSS/image file you're referencing won't be found, and you'll see a 404 error in your browser's console. You'll also notice that the 404 URL is missing the version hash in the filename (e.g. a 404 to ``/assets/duck.js`` instead of -a path like ``/assets/duck.1b7a64b3b3d31219c262cf72521a5267.js``). +a path like ``/assets/duck-1b7a64b3.js``). This is usually because the path is wrong. If you're referencing the file directly in a Twig template: @@ -848,7 +848,7 @@ be versioned! It will output something like: .. code-block:: html+twig - + Overriding 3rd-Party Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 47e65dfb47d70815d3bbe8e7c809c421b2ad4ec9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 26 Dec 2024 11:17:56 +0100 Subject: [PATCH 146/427] Update the Symfony version to install in 7.3 branch --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index 853b53f2400..b269da2c476 100644 --- a/setup.rst +++ b/setup.rst @@ -48,10 +48,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_directory --version="7.2.x" --webapp + $ symfony new my_project_directory --version="7.3.x-dev" --webapp # run this if you are building a microservice, console application or API - $ symfony new my_project_directory --version="7.2.x" + $ symfony new my_project_directory --version="7.3.x-dev" The only difference between these two commands is the number of packages installed by default. The ``--webapp`` option installs extra packages to give @@ -63,12 +63,12 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/skeleton:"7.2.x" my_project_directory + $ composer create-project symfony/skeleton:"7.3.x-dev" my_project_directory $ cd my_project_directory $ composer require webapp # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"7.2.x" my_project_directory + $ composer create-project symfony/skeleton:"7.3.x-dev" my_project_directory No matter which command you run to create the Symfony application. All of them will create a new ``my_project_directory/`` directory, download some dependencies From 04790be521b670ddffbee654c55da3bc165dfd55 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Mon, 30 Dec 2024 08:38:13 +0100 Subject: [PATCH 147/427] [Validator] Validate SVG ratio in Image validator --- reference/constraints/Image.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst index 48dc1d5e0ed..23fbe5a157a 100644 --- a/reference/constraints/Image.rst +++ b/reference/constraints/Image.rst @@ -210,6 +210,10 @@ add several other options. If this option is false, the image cannot be landscape oriented. +.. versionadded:: 7.3 + + The ``allowLandscape`` option support for SVG files was introduced in Symfony 7.3. + ``allowLandscapeMessage`` ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -234,6 +238,10 @@ Parameter Description If this option is false, the image cannot be portrait oriented. +.. versionadded:: 7.3 + + The ``allowPortrait`` option support for SVG files was introduced in Symfony 7.3. + ``allowPortraitMessage`` ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -260,6 +268,10 @@ If this option is false, the image cannot be a square. If you want to force a square image, then leave this option as its default ``true`` value and set `allowLandscape`_ and `allowPortrait`_ both to ``false``. +.. versionadded:: 7.3 + + The ``allowSquare`` option support for SVG files was introduced in Symfony 7.3. + ``allowSquareMessage`` ~~~~~~~~~~~~~~~~~~~~~~ @@ -358,6 +370,10 @@ Parameter Description If set, the aspect ratio (``width / height``) of the image file must be less than or equal to this value. +.. versionadded:: 7.3 + + The ``maxRatio`` option support for SVG files was introduced in Symfony 7.3. + ``maxRatioMessage`` ~~~~~~~~~~~~~~~~~~~ @@ -477,6 +493,10 @@ Parameter Description If set, the aspect ratio (``width / height``) of the image file must be greater than or equal to this value. +.. versionadded:: 7.3 + + The ``minRatio`` option support for SVG files was introduced in Symfony 7.3. + ``minRatioMessage`` ~~~~~~~~~~~~~~~~~~~ From 3596f8c2b09f3380773a42a38b30f152fada315c Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 2 Jan 2025 12:59:47 +0100 Subject: [PATCH 148/427] Add ifFalse() --- components/config/definition.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/config/definition.rst b/components/config/definition.rst index 0e626931568..24c142ec5a5 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -815,6 +815,7 @@ A validation rule always has an "if" part. You can specify this part in the following ways: - ``ifTrue()`` +- ``ifFalse()`` - ``ifString()`` - ``ifNull()`` - ``ifEmpty()`` @@ -833,6 +834,10 @@ A validation rule also requires a "then" part: Usually, "then" is a closure. Its return value will be used as a new value for the node, instead of the node's original value. +.. versionadded:: 7.3 + + The ``ifFalse()`` method was introduced in Symfony 7.3. + Configuring the Node Path Separator ----------------------------------- From e1c23c76557c1bad82005f61effb685fba775c6c Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Thu, 2 Jan 2025 10:20:16 -0500 Subject: [PATCH 149/427] Add docs for is_granted_for_user() function --- reference/twig_reference.rst | 21 +++++++++++++++++++++ security.rst | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index d8b802dd73e..4485494bd9c 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -174,6 +174,27 @@ Returns ``true`` if the current user has the given role. Optionally, an object can be passed to be used by the voter. More information can be found in :ref:`security-template`. +is_granted_for_user +~~~~~~~~~~~~~~~~~~~ + +.. code-block:: twig + + {{ is_granted_for_user(user, attribute, subject = null, field = null) }} + +``user`` + **type**: ``object`` +``attribute`` + **type**: ``string`` +``subject`` *(optional)* + **type**: ``object`` +``field`` *(optional)* + **type**: ``string`` + +Returns ``true`` if the user is authorized for the specified attribute. + +Optionally, an object can be passed to be used by the voter. More information +can be found in :ref:`security-template`. + logout_path ~~~~~~~~~~~ diff --git a/security.rst b/security.rst index 8026c63484b..7fe452e4fae 100644 --- a/security.rst +++ b/security.rst @@ -2549,6 +2549,17 @@ the built-in ``is_granted()`` helper function in any Twig template: .. _security-isgranted: +Similarly, if you want to check if a specific user has a certain role, you can use +the built-in ``is_granted_for_user()`` helper function: + +.. code-block:: html+twig + + {% if is_granted_for_user(user, 'ROLE_ADMIN') %} + Delete + {% endif %} + +.. _security-isgrantedforuser: + Securing other Services ....................... From ddf1ad3975a30bd1b3fce6528c4795646674508e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Jan 2025 13:17:39 +0100 Subject: [PATCH 150/427] Add the missing versionadded directive --- reference/twig_reference.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 4485494bd9c..e01fa3f80e3 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -177,6 +177,10 @@ can be found in :ref:`security-template`. is_granted_for_user ~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 7.3 + + The ``is_granted_for_user()`` function was introduced in Symfony 7.3. + .. code-block:: twig {{ is_granted_for_user(user, attribute, subject = null, field = null) }} From effffa3bb0bcdbb7016d7bd415cd23c4f01fd948 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Jan 2025 14:55:02 +0100 Subject: [PATCH 151/427] Minor tweak --- frontend/asset_mapper.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index 81e91c1fc9d..d68c77c0105 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -747,11 +747,9 @@ and which file extensions should be compressed: Now, when running the ``asset-map:compile`` command, all matching files will be compressed in the configured format and at the highest compression level. The compressed files are created with the same name as the original but with the -``.br``, ``.zst``, or ``.gz`` extension appended. Web servers that support asset -precompression will use the compressed assets automatically, so there's nothing -else to configure in your server. +``.br``, ``.zst``, or ``.gz`` extension appended. -Finally, you need to configure your web server to serve the precompressed assets +Then, you need to configure your web server to serve the precompressed assets instead of the original ones: .. configuration-block:: From 9b65586c1ee8ec15873d290b6eaa01e8bd2dc062 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Jan 2025 16:43:16 +0100 Subject: [PATCH 152/427] Fix build --- validation/custom_constraint.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index 990e1de9371..59da9e60568 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -66,7 +66,7 @@ Constraint with Private Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constraints are cached for performance reasons. To achieve this, the base -``Constraint`` class uses PHP's :phpfunction:`get_object_vars()` function, which +``Constraint`` class uses PHP's :phpfunction:`get_object_vars` function, which excludes private properties of child classes. If your constraint defines private properties, you must explicitly include them From 1272701ec6e1d15e9bf21d6ab55445d6f68838ba Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Jan 2025 16:19:25 +0100 Subject: [PATCH 153/427] [DependencyInjection] Make #[AsTaggedItem] repeatable --- service_container/tags.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/service_container/tags.rst b/service_container/tags.rst index 270d6702f5a..bf50a191ba3 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -1281,4 +1281,19 @@ be used directly on the class of the service you want to configure:: // ... } +You can apply the ``#[AsTaggedItem]`` attribute multiple times to register the +same service under different indexes: + + #[AsTaggedItem(index: 'handler_one', priority: 5)] + #[AsTaggedItem(index: 'handler_two', priority: 20)] + class SomeService + { + // ... + } + +.. versionadded:: 7.3 + + The feature to apply the ``#[AsTaggedItem]`` attribute multiple times was + introduced in Symfony 7.3. + .. _`PHP constructor promotion`: https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion From 9d4972de1863f3a028c6ce5d5e8d4ad2ac866201 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Jan 2025 16:52:36 +0100 Subject: [PATCH 154/427] Minor reword --- security.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/security.rst b/security.rst index baa1a32a3a7..92367f29a88 100644 --- a/security.rst +++ b/security.rst @@ -2596,12 +2596,13 @@ want to include extra details only for users that have a ``ROLE_SALES_ADMIN`` ro // ... } + .. tip:: - Using ``isGranted()`` checks authorization against the currently logged in user. If you need to check - against a user that is not the one logged in or if checking authorization when the user session is not - available in a CLI context (example: message queue, cronjob) ``isGrantedForUser()`` can be used to set the - target user explicitly. + The ``isGranted()`` method checks authorization for the currently logged-in user. + If you need to check authorization for a different user or when the user session + is unavailable (e.g., in a CLI context such as a message queue or cron job), you + can use the ``isGrantedForUser()`` method to explicitly set the target user. .. versionadded:: 7.3 From 1afb8ebf3663a634108eac91b3d74ee20631d0af Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Jan 2025 15:57:26 +0100 Subject: [PATCH 155/427] [HttpFoundation] Generate url-safe hashes for signed urls --- routing.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/routing.rst b/routing.rst index ef3287dd1be..4ab0dce2a82 100644 --- a/routing.rst +++ b/routing.rst @@ -2802,6 +2802,11 @@ argument of :method:`Symfony\\Component\\HttpFoundation\\UriSigner::sign`:: The feature to add an expiration date for a signed URI was introduced in Symfony 7.1. +.. versionadded:: 7.3 + + Starting with Symfony 7.3, signed URI hashes no longer include the ``/`` or + ``+`` characters, as these may cause issues with certain clients. + Troubleshooting --------------- From ab691630aaeeabe52ae7717be558faa560968169 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 6 Jan 2025 09:11:25 +0100 Subject: [PATCH 156/427] [Yaml] Add support for dumping `null` as an empty value by using the `Yaml::DUMP_NULL_AS_EMPTY` flag --- components/yaml.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/yaml.rst b/components/yaml.rst index 30f715a7a24..58436adffc2 100644 --- a/components/yaml.rst +++ b/components/yaml.rst @@ -428,6 +428,16 @@ you can dump them as ``~`` with the ``DUMP_NULL_AS_TILDE`` flag:: $dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_TILDE); // foo: ~ +Another valid representation of the ``null`` value is an empty string. You can +use the ``DUMP_NULL_AS_EMPTY`` flag to dump null values as empty strings:: + + $dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_EMPTY); + // foo: + +.. versionadded:: 7.3 + + The ``DUMP_NULL_AS_EMPTY`` flag was introduced in Symfony 7.3. + Dumping Numeric Keys as Strings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 7d7e77cafbabba22b2443f4edc9fc13e3aba1bdf Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 6 Jan 2025 20:48:52 +0100 Subject: [PATCH 157/427] [PropertyInfo] Add PropertyDescriptionExtractorInterface to PhpStanExtractor --- components/property_info.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/property_info.rst b/components/property_info.rst index 2e1ee42dd3f..0ff1768441a 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -469,7 +469,18 @@ information from annotations of properties and methods, such as ``@var``, use App\Domain\Foo; $phpStanExtractor = new PhpStanExtractor(); + + // Type information. $phpStanExtractor->getTypesFromConstructor(Foo::class, 'bar'); + // Description information. + $phpStanExtractor->getShortDescription($class, 'bar'); + $phpStanExtractor->getLongDescription($class, 'bar'); + +.. versionadded:: 7.3 + + The :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpStanExtractor::getShortDescription` + and :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpStanExtractor::getLongDescription` + methods were introduced in Symfony 7.3. SerializerExtractor ~~~~~~~~~~~~~~~~~~~ From 6d16cd8b4e41fa0b1686c44edb93b1f77023cd6f Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 6 Jan 2025 21:15:30 +0100 Subject: [PATCH 158/427] [Mailer] Add retry_period option for email transport --- mailer.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mailer.rst b/mailer.rst index 4f0619147ad..8cc0d8641e3 100644 --- a/mailer.rst +++ b/mailer.rst @@ -331,6 +331,17 @@ The failover-transport starts using the first transport and if it fails, it will retry the same delivery with the next transports until one of them succeeds (or until all of them fail). +By default, the delivery will be retried 60 seconds after previous sending failed. +You can change the retry period by setting the ``retry_period`` option in the DSN: + +.. code-block:: env + + MAILER_DSN="failover(postmark+api://ID@default sendgrid+smtp://KEY@default)?retry_period=15" + +.. versionadded:: 7.3 + + The ``retry_period`` option was introduced in Symfony 7.3. + Load Balancing ~~~~~~~~~~~~~~ @@ -351,6 +362,17 @@ As with the failover transport, round-robin retries deliveries until a transport succeeds (or all fail). In contrast to the failover transport, it *spreads* the load across all its transports. +By default, the delivery will be retried 60 seconds after previous sending failed. +You can change the retry period by setting the ``retry_period`` option in the DSN: + +.. code-block:: env + + MAILER_DSN="roundrobin(postmark+api://ID@default sendgrid+smtp://KEY@default)?retry_period=15" + +.. versionadded:: 7.3 + + The ``retry_period`` option was introduced in Symfony 7.3. + TLS Peer Verification ~~~~~~~~~~~~~~~~~~~~~ From 7d94c8e8fc64032721af5415d8a3c0fe018ecf71 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 7 Jan 2025 08:42:04 +0100 Subject: [PATCH 159/427] Minor reword --- mailer.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mailer.rst b/mailer.rst index 8cc0d8641e3..4fd02eb84d7 100644 --- a/mailer.rst +++ b/mailer.rst @@ -331,8 +331,8 @@ The failover-transport starts using the first transport and if it fails, it will retry the same delivery with the next transports until one of them succeeds (or until all of them fail). -By default, the delivery will be retried 60 seconds after previous sending failed. -You can change the retry period by setting the ``retry_period`` option in the DSN: +By default, delivery is retried 60 seconds after a failed attempt. You can adjust +the retry period by setting the ``retry_period`` option in the DSN: .. code-block:: env @@ -362,8 +362,8 @@ As with the failover transport, round-robin retries deliveries until a transport succeeds (or all fail). In contrast to the failover transport, it *spreads* the load across all its transports. -By default, the delivery will be retried 60 seconds after previous sending failed. -You can change the retry period by setting the ``retry_period`` option in the DSN: +By default, delivery is retried 60 seconds after a failed attempt. You can adjust +the retry period by setting the ``retry_period`` option in the DSN: .. code-block:: env From d1400d406951f664bd159e38eab33c5a93cb73e9 Mon Sep 17 00:00:00 2001 From: Iker Ibarguren Date: Tue, 7 Jan 2025 09:51:40 +0100 Subject: [PATCH 160/427] Update notifier.rst Brevo third-party service now supports webhooks. --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 36fbd5ada89..5b3f12a67fa 100644 --- a/notifier.rst +++ b/notifier.rst @@ -76,7 +76,7 @@ Service **Webhook support**: No `Brevo`_ **Install**: ``composer require symfony/brevo-notifier`` \ **DSN**: ``brevo://API_KEY@default?sender=SENDER`` \ - **Webhook support**: No + **Webhook support**: Yes `Clickatell`_ **Install**: ``composer require symfony/clickatell-notifier`` \ **DSN**: ``clickatell://ACCESS_TOKEN@default?from=FROM`` \ **Webhook support**: No From e4f8ff86daa93eab17172a0fd001caccd5c93e55 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 7 Jan 2025 12:04:07 +0100 Subject: [PATCH 161/427] Add a versionadded directive --- notifier.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/notifier.rst b/notifier.rst index 5b3f12a67fa..090f4db2007 100644 --- a/notifier.rst +++ b/notifier.rst @@ -236,6 +236,10 @@ Service The ``Primotexto``, ``Sipgate`` and ``Sweego`` integrations were introduced in Symfony 7.2. +.. versionadded:: 7.3 + + Webhook support for the ``Brevo`` integration was introduced in Symfony 7.3. + .. deprecated:: 7.1 The `Sms77`_ integration is deprecated since From 17a46adc143905ee469e48118039c7e8f66760b5 Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne Date: Sun, 5 Jan 2025 17:34:40 +0100 Subject: [PATCH 162/427] [Validator] [DateTime] Add ``format`` to error messages --- reference/constraints/DateTime.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/reference/constraints/DateTime.rst b/reference/constraints/DateTime.rst index f6bcce7e5f5..ffcfbf55dda 100644 --- a/reference/constraints/DateTime.rst +++ b/reference/constraints/DateTime.rst @@ -99,11 +99,16 @@ This message is shown if the underlying data is not a valid datetime. You can use the following parameters in this message: -=============== ============================================================== -Parameter Description -=============== ============================================================== -``{{ value }}`` The current (invalid) value -``{{ label }}`` Corresponding form field label -=============== ============================================================== +================ ============================================================== +Parameter Description +================ ============================================================== +``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label +``{{ format }}`` The date format defined in ``format`` +================ ============================================================== + +.. versionadded:: 7.3 + + The ``{{ format }}`` parameter was introduced in Symfony 7.3. .. include:: /reference/constraints/_payload-option.rst.inc From 45113124f7b2affdcceae4460f218b4efc740839 Mon Sep 17 00:00:00 2001 From: tcoch Date: Mon, 6 Jan 2025 09:22:34 +0100 Subject: [PATCH 163/427] [String] Add `AbstractString::pascal()` method --- string.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/string.rst b/string.rst index 43d3a236ab6..e51e7d1b502 100644 --- a/string.rst +++ b/string.rst @@ -234,8 +234,10 @@ Methods to Change Case u('Foo: Bar-baz.')->snake(); // 'foo_bar_baz' // changes all graphemes/code points to kebab-case u('Foo: Bar-baz.')->kebab(); // 'foo-bar-baz' - // other cases can be achieved by chaining methods. E.g. PascalCase: - u('Foo: Bar-baz.')->camel()->title(); // 'FooBarBaz' + // changes all graphemes/code points to PascalCase + u('Foo: Bar-baz.')->pascal(); // 'FooBarBaz' + // other cases can be achieved by chaining methods, e.g. : + u('Foo: Bar-baz.')->camel()->upper(); // 'FOOBARBAZ' .. versionadded:: 7.1 @@ -246,6 +248,10 @@ Methods to Change Case The ``kebab()`` method was introduced in Symfony 7.2. +.. versionadded:: 7.3 + + The ``pascal()`` method was introduced in Symfony 7.3. + The methods of all string classes are case-sensitive by default. You can perform case-insensitive operations with the ``ignoreCase()`` method:: From 951f461e329cb0c8f275ca9100b2a5789844afec Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Tue, 7 Jan 2025 16:08:07 +0100 Subject: [PATCH 164/427] [TypeInfo] Add `accepts` method --- components/type_info.rst | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/components/type_info.rst b/components/type_info.rst index e7062c5f249..70280d9a348 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -114,7 +114,7 @@ Advanced Usages The TypeInfo component provides various methods to manipulate and check types, depending on your needs. -Checking a **simple type**:: +**Identify** a type:: // define a simple integer type $type = Type::int(); @@ -141,6 +141,23 @@ Checking a **simple type**:: $type->isIdentifiedBy(DummyParent::class); // true $type->isIdentifiedBy(DummyInterface::class); // true +Checking if a type **accepts a value**:: + + $type = Type::int(); + // check if the type accepts a given value + $type->accepts(123); // true + $type->accepts('z'); // false + + $type = Type::union(Type::string(), Type::int()); + // now the second check is true because the union type accepts either a int and a string value + $type->accepts(123); // true + $type->accepts('z'); // true + +.. versionadded:: 7.3 + + The :method:`Symfony\\Component\\TypeInfo\\Type::accepts` + method was introduced in Symfony 7.3. + Using callables for **complex checks**:: class Foo From b4f8f6bf5f596664eb36c6311107b0b0056fd166 Mon Sep 17 00:00:00 2001 From: tcoch Date: Mon, 6 Jan 2025 17:22:10 +0100 Subject: [PATCH 165/427] [Validator] Add Slug constraint --- reference/constraints/Slug.rst | 119 ++++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 2 files changed, 120 insertions(+) create mode 100644 reference/constraints/Slug.rst diff --git a/reference/constraints/Slug.rst b/reference/constraints/Slug.rst new file mode 100644 index 00000000000..5b7661b4aba --- /dev/null +++ b/reference/constraints/Slug.rst @@ -0,0 +1,119 @@ +Slug +==== + +.. versionadded:: 7.3 + + The ``Slug`` constraint was introduced in Symfony 7.3. + +Validates that a value is a slug. +A slug is a string that, by default, matches the regex ``/^[a-z0-9]+(?:-[a-z0-9]+)*$/``. + +.. include:: /reference/constraints/_empty-values-are-valid.rst.inc + +========== =================================================================== +Applies to :ref:`property or method ` +Class :class:`Symfony\\Component\\Validator\\Constraints\\Slug` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\SlugValidator` +========== =================================================================== + +Basic Usage +----------- + +The ``Slug`` constraint can be applied to a property or a "getter" method: + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Slug] + protected string $slug; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\Author: + properties: + slug: + - Slug: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class Author + { + // ... + + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('slug', new Assert\Slug()); + } + } + +Examples of valid values : + +* foobar +* foo-bar +* foo123 +* foo-123bar + +Upper case characters would result in an violation of this constraint. + +Options +------- + +``regex`` +~~~~~~~~~ + +**type**: ``string`` default: ``/^[a-z0-9]+(?:-[a-z0-9]+)*$/`` + +This option allows you to modify the regular expression pattern that the input will be matched against +via the :phpfunction:`preg_match` PHP function. + +If you need to use it, you might also want to take a look at the :doc:`Regex constraint `. + +``message`` +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is not a valid slug`` + +This is the message that will be shown if this validator fails. + +You can use the following parameters in this message: + +================= ============================================================== +Parameter Description +================= ============================================================== +``{{ value }}`` The current (invalid) value +================= ============================================================== + +.. include:: /reference/constraints/_groups-option.rst.inc + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index f23f5b71aa3..58801a8c653 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -33,6 +33,7 @@ String Constraints * :doc:`NotCompromisedPassword ` * :doc:`PasswordStrength ` * :doc:`Regex ` +* :doc:`Slug ` * :doc:`Ulid ` * :doc:`Url ` * :doc:`UserPassword ` From d688f6312c64050123f0c27b0871f80ab63b677c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 7 Jan 2025 17:56:09 +0100 Subject: [PATCH 166/427] Minor tweaks --- reference/constraints/Slug.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/reference/constraints/Slug.rst b/reference/constraints/Slug.rst index 5b7661b4aba..2eb82cd9c10 100644 --- a/reference/constraints/Slug.rst +++ b/reference/constraints/Slug.rst @@ -5,8 +5,8 @@ Slug The ``Slug`` constraint was introduced in Symfony 7.3. -Validates that a value is a slug. -A slug is a string that, by default, matches the regex ``/^[a-z0-9]+(?:-[a-z0-9]+)*$/``. +Validates that a value is a slug. By default, a slug is a string that matches +the following regular expression: ``/^[a-z0-9]+(?:-[a-z0-9]+)*$/``. .. include:: /reference/constraints/_empty-values-are-valid.rst.inc @@ -19,7 +19,7 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\SlugValidator` Basic Usage ----------- -The ``Slug`` constraint can be applied to a property or a "getter" method: +The ``Slug`` constraint can be applied to a property or a getter method: .. configuration-block:: @@ -77,14 +77,14 @@ The ``Slug`` constraint can be applied to a property or a "getter" method: } } -Examples of valid values : +Examples of valid values: * foobar * foo-bar * foo123 * foo-123bar -Upper case characters would result in an violation of this constraint. +Uppercase characters would result in an violation of this constraint. Options ------- @@ -94,8 +94,8 @@ Options **type**: ``string`` default: ``/^[a-z0-9]+(?:-[a-z0-9]+)*$/`` -This option allows you to modify the regular expression pattern that the input will be matched against -via the :phpfunction:`preg_match` PHP function. +This option allows you to modify the regular expression pattern that the input +will be matched against via the :phpfunction:`preg_match` PHP function. If you need to use it, you might also want to take a look at the :doc:`Regex constraint `. From 693b758160d580d9e5bbdb6e0e8b4310baf2d5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Wed, 8 Jan 2025 06:29:55 +0100 Subject: [PATCH 167/427] [Security] Remove mention of is_granted_ `$field` argument The third argument of is_granted / is_granted_for_user is undocumented (except on this page) (neither on Symfony docs, code, nor on... Symfony ACL Bundle docs). It must be kept and maintained for BC reasons. But it can be missleading/frustrating to show this argument to users, when they cannot use it with a standard/recommended Symfony installation. And if they just test it, the error could lead them to believe the AclBundle needs to be installed to use the `is_granted` function(s). As suggested in https://github.com/symfony/symfony/pull/59282#issuecomment-2569716817 I believe "not showing it" is the "best" solution here. --- reference/twig_reference.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index e01fa3f80e3..acbab2f3817 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -160,14 +160,12 @@ is_granted .. code-block:: twig - {{ is_granted(role, object = null, field = null) }} + {{ is_granted(role, object = null) }} ``role`` **type**: ``string`` ``object`` *(optional)* **type**: ``object`` -``field`` *(optional)* - **type**: ``string`` Returns ``true`` if the current user has the given role. @@ -183,7 +181,7 @@ is_granted_for_user .. code-block:: twig - {{ is_granted_for_user(user, attribute, subject = null, field = null) }} + {{ is_granted_for_user(user, attribute, subject = null) }} ``user`` **type**: ``object`` @@ -191,8 +189,6 @@ is_granted_for_user **type**: ``string`` ``subject`` *(optional)* **type**: ``object`` -``field`` *(optional)* - **type**: ``string`` Returns ``true`` if the user is authorized for the specified attribute. From 23800a97fa5114849320dac166b80ff97b3d2d46 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 8 Jan 2025 10:18:55 +0100 Subject: [PATCH 168/427] Minor tweak --- components/type_info.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/type_info.rst b/components/type_info.rst index 70280d9a348..47fe9dfd9ba 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -149,7 +149,7 @@ Checking if a type **accepts a value**:: $type->accepts('z'); // false $type = Type::union(Type::string(), Type::int()); - // now the second check is true because the union type accepts either a int and a string value + // now the second check is true because the union type accepts either an int or a string value $type->accepts(123); // true $type->accepts('z'); // true From cf53d1914e874def9e39324e6c5ad32e0b441f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Wed, 8 Jan 2025 12:06:09 +0100 Subject: [PATCH 169/427] Fix typo --- components/type_info.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/type_info.rst b/components/type_info.rst index e7062c5f249..2a92a3db63e 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -106,7 +106,7 @@ PHP package required for string resolving. Then, follow these steps:: $typeResolver = TypeResolver::create(); $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type - $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns a collection with "int" as key and "string" as values Type + $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'tags')); // returns a collection with "int" as key and "string" as values Type Advanced Usages ~~~~~~~~~~~~~~~ From ed80f8b78a6714ed0c092e7cf90eb98afecf75be Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 8 Jan 2025 22:05:23 +0100 Subject: [PATCH 170/427] revert webhook support for the Brevo Notifier bridge --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 090f4db2007..f74ff92009e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -76,7 +76,7 @@ Service **Webhook support**: No `Brevo`_ **Install**: ``composer require symfony/brevo-notifier`` \ **DSN**: ``brevo://API_KEY@default?sender=SENDER`` \ - **Webhook support**: Yes + **Webhook support**: No `Clickatell`_ **Install**: ``composer require symfony/clickatell-notifier`` \ **DSN**: ``clickatell://ACCESS_TOKEN@default?from=FROM`` \ **Webhook support**: No From fb028aa7e77e8a2324b3b65e4e9823045d26ef73 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 9 Jan 2025 12:24:39 +0100 Subject: [PATCH 171/427] Remove an uneeded versionadded directive --- notifier.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index f74ff92009e..36fbd5ada89 100644 --- a/notifier.rst +++ b/notifier.rst @@ -236,10 +236,6 @@ Service The ``Primotexto``, ``Sipgate`` and ``Sweego`` integrations were introduced in Symfony 7.2. -.. versionadded:: 7.3 - - Webhook support for the ``Brevo`` integration was introduced in Symfony 7.3. - .. deprecated:: 7.1 The `Sms77`_ integration is deprecated since From f8667f57029ad20b615c6c7f42d13bc02df86fa5 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 6 Jan 2025 21:16:06 +0100 Subject: [PATCH 172/427] [OptionsResolver] Support union of types --- components/options_resolver.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index ff25f9e0fc4..266911bf13d 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -305,13 +305,20 @@ correctly. To validate the types of the options, call // specify multiple allowed types $resolver->setAllowedTypes('port', ['null', 'int']); + // which is similar to + $resolver->setAllowedTypes('port', 'int|null'); // check all items in an array recursively for a type $resolver->setAllowedTypes('dates', 'DateTime[]'); $resolver->setAllowedTypes('ports', 'int[]'); + $resolver->setAllowedTypes('endpoints', '(int|string)[]'); } } +.. versionadded:: 7.3 + + Union of type, using the ``|`` syntax, was introduced in Symfony 7.3. + You can pass any type for which an ``is_()`` function is defined in PHP. You may also pass fully qualified class or interface names (which is checked using ``instanceof``). Additionally, you can validate all items in an array From ca50eeb570eb13b2c35b7fa02f199bfc509755d8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 9 Jan 2025 15:29:40 +0100 Subject: [PATCH 173/427] Minor tweaks --- components/options_resolver.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 266911bf13d..95741a7e372 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -305,19 +305,20 @@ correctly. To validate the types of the options, call // specify multiple allowed types $resolver->setAllowedTypes('port', ['null', 'int']); - // which is similar to + // if you prefer, you can also use the following equivalent syntax $resolver->setAllowedTypes('port', 'int|null'); // check all items in an array recursively for a type $resolver->setAllowedTypes('dates', 'DateTime[]'); $resolver->setAllowedTypes('ports', 'int[]'); + // the following syntax means "an array of integers or an array of strings" $resolver->setAllowedTypes('endpoints', '(int|string)[]'); } } .. versionadded:: 7.3 - Union of type, using the ``|`` syntax, was introduced in Symfony 7.3. + Defining type unions with the ``|`` syntax was introduced in Symfony 7.3. You can pass any type for which an ``is_()`` function is defined in PHP. You may also pass fully qualified class or interface names (which is checked From c532aed720a486a85ba26209cf7ad4185db5c0ec Mon Sep 17 00:00:00 2001 From: chx Date: Mon, 6 Jan 2025 14:36:23 +0100 Subject: [PATCH 174/427] [DependencyInjection] Documented the new @> shorthand --- service_container/service_closures.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/service_container/service_closures.rst b/service_container/service_closures.rst index cedbaaa2bf9..73dc17961fd 100644 --- a/service_container/service_closures.rst +++ b/service_container/service_closures.rst @@ -52,6 +52,14 @@ argument of type ``service_closure``: # In case the dependency is optional # arguments: [!service_closure '@?mailer'] +.. versionadded:: 7.3 + + # A shorthand is available + # arguments: ['@>mailer'] + + # It also works when the dependency is optional + # arguments: ['@>?mailer'] + .. code-block:: xml From 250c35b812814ed105d1790213b9938a2e244666 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 10 Jan 2025 16:08:17 +0100 Subject: [PATCH 175/427] Reword --- service_container/service_closures.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/service_container/service_closures.rst b/service_container/service_closures.rst index 73dc17961fd..88b0ab64002 100644 --- a/service_container/service_closures.rst +++ b/service_container/service_closures.rst @@ -52,12 +52,11 @@ argument of type ``service_closure``: # In case the dependency is optional # arguments: [!service_closure '@?mailer'] -.. versionadded:: 7.3 - - # A shorthand is available - # arguments: ['@>mailer'] + # you can also use the special '@>' syntax as a shortcut of '!service_closure' + App\Service\AnotherService: + arguments: ['@>mailer'] - # It also works when the dependency is optional + # the shortcut also works for optional dependencies # arguments: ['@>?mailer'] .. code-block:: xml @@ -98,6 +97,10 @@ argument of type ``service_closure``: // ->args([service_closure('mailer')->ignoreOnInvalid()]); }; +.. versionadded:: 7.3 + + The ``@>`` shortcut syntax for YAML was introduced in Symfony 7.3. + .. seealso:: Service closures can be injected :ref:`by using autowiring ` From c880a8818fa495a6b34188bddd76b946e54e6d3a Mon Sep 17 00:00:00 2001 From: Javier Spagnoletti Date: Sat, 11 Jan 2025 03:14:50 -0300 Subject: [PATCH 176/427] [Doctrine] Use PDO constants in XML configuration example --- reference/configuration/doctrine.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index cd1852710e7..25621f60493 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -507,9 +507,9 @@ set up the connection using environment variables for the certificate paths: server-version="8.0.31" driver="pdo_mysql"> - %env(MYSQL_SSL_KEY)% - %env(MYSQL_SSL_CERT)% - %env(MYSQL_SSL_CA)% + %env(MYSQL_SSL_KEY)% + %env(MYSQL_SSL_CERT)% + %env(MYSQL_SSL_CA)% From 207933321946e82e537eece0022f2045e22c0ff8 Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne Date: Sun, 12 Jan 2025 11:09:02 +0100 Subject: [PATCH 177/427] [FrameworkBundle] Remove ``--show-arguments`` option for ``debug:container`` --- controller/value_resolver.rst | 2 +- service_container/debug.rst | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/controller/value_resolver.rst b/controller/value_resolver.rst index dbbea7bcc87..1844ff0c9be 100644 --- a/controller/value_resolver.rst +++ b/controller/value_resolver.rst @@ -396,7 +396,7 @@ command to see which argument resolvers are present and in which order they run: .. code-block:: terminal - $ php bin/console debug:container debug.argument_resolver.inner --show-arguments + $ php bin/console debug:container debug.argument_resolver.inner You can also configure the name passed to the ``ValueResolver`` attribute to target your resolver. Otherwise it will default to the service's id. diff --git a/service_container/debug.rst b/service_container/debug.rst index c09413e7213..0a7898108fb 100644 --- a/service_container/debug.rst +++ b/service_container/debug.rst @@ -51,6 +51,3 @@ its id: .. code-block:: terminal $ php bin/console debug:container App\Service\Mailer - - # to show the service arguments: - $ php bin/console debug:container App\Service\Mailer --show-arguments From e12afdd378e43587f1d9cfb06e8f5708146b2e76 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 13 Jan 2025 09:34:01 +0100 Subject: [PATCH 178/427] Add a versionadded directive --- service_container/debug.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/service_container/debug.rst b/service_container/debug.rst index 0a7898108fb..aab6fa9529f 100644 --- a/service_container/debug.rst +++ b/service_container/debug.rst @@ -51,3 +51,9 @@ its id: .. code-block:: terminal $ php bin/console debug:container App\Service\Mailer + +.. versionadded:: 7.3 + + Starting in Symfony 7.3, this command displays the service arguments by default. + In earlier Symfony versions, you needed to use the ``--show-arguments`` option, + which is now deprecated. From d46522ad4ae49ae8317ad5c762daac0227ed143a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Jan 2025 09:53:02 +0100 Subject: [PATCH 179/427] Add more details about the context variable --- reference/constraints/When.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/reference/constraints/When.rst b/reference/constraints/When.rst index 12b43fc7d63..2a05e58ee9c 100644 --- a/reference/constraints/When.rst +++ b/reference/constraints/When.rst @@ -163,7 +163,7 @@ validation of constraints won't be triggered. To learn more about the expression language syntax, see :doc:`/reference/formats/expression_language`. -Depending on how you use the constraint, you have access to 1 or 3 variables +Depending on how you use the constraint, you have access to different variables in your expression: ``this`` @@ -172,7 +172,13 @@ in your expression: The value of the property being validated (only available when the constraint is applied to a property). ``context`` - This is the context that is used in validation + The :class:`Symfony\\Component\\Validator\\Context\\ExecutionContextInterface` + object that provides information such as the currently validated class, the + name of the currently validated property, the list of violations, etc. + +.. versionadded:: 7.2 + + The ``context`` variable in expressions was introduced in Symfony 7.2. The ``value`` variable can be used when you want to execute more complex validation based on its value: From 1c51901e95a0d05284e311df419bc9828dc983c7 Mon Sep 17 00:00:00 2001 From: Farhad Hedayatifard Date: Tue, 29 Oct 2024 21:10:14 +0330 Subject: [PATCH 180/427] [Mailer] feat(mailer): Add AhaSend Mailer doc --- .doctor-rst.yaml | 4 +- .github/workflows/ci.yaml | 2 +- _build/redirection_map | 5 +- .../serializer/serializer_workflow.svg | 0 .../serializer/serializer_workflow.dia | Bin bundles.rst | 6 +- bundles/best_practices.rst | 2 +- bundles/extension.rst | 2 +- bundles/override.rst | 2 +- cache.rst | 2 +- components/cache/adapters/apcu_adapter.rst | 4 +- .../adapters/couchbasebucket_adapter.rst | 2 +- .../adapters/couchbasecollection_adapter.rst | 2 +- .../cache/adapters/filesystem_adapter.rst | 2 +- .../cache/adapters/memcached_adapter.rst | 4 +- .../cache/adapters/php_files_adapter.rst | 2 +- components/cache/adapters/redis_adapter.rst | 84 +- components/clock.rst | 6 +- components/config/definition.rst | 24 +- .../console/changing_default_command.rst | 2 +- components/console/events.rst | 2 +- .../console/helpers/formatterhelper.rst | 14 +- components/console/helpers/progressbar.rst | 2 +- components/console/helpers/questionhelper.rst | 6 +- components/event_dispatcher.rst | 6 +- components/expression_language.rst | 8 +- components/finder.rst | 2 +- components/form.rst | 2 +- components/http_foundation.rst | 25 +- components/http_kernel.rst | 2 +- components/ldap.rst | 2 +- components/lock.rst | 38 +- components/options_resolver.rst | 4 +- components/phpunit_bridge.rst | 4 +- components/process.rst | 4 +- components/property_access.rst | 8 +- components/property_info.rst | 17 +- components/runtime.rst | 5 +- components/serializer.rst | 1938 -------------- components/type_info.rst | 136 +- components/uid.rst | 4 +- components/validator/resources.rst | 2 +- components/yaml.rst | 10 + configuration.rst | 8 +- configuration/env_var_processors.rst | 2 +- configuration/micro_kernel_trait.rst | 2 +- configuration/multiple_kernels.rst | 2 +- configuration/override_dir_structure.rst | 2 +- console.rst | 10 +- console/calling_commands.rst | 5 +- console/command_in_controller.rst | 2 +- console/commands_as_services.rst | 4 +- console/input.rst | 2 +- contributing/code/bc.rst | 8 +- contributing/code/bugs.rst | 2 +- contributing/code/maintenance.rst | 3 + contributing/documentation/format.rst | 2 +- contributing/documentation/standards.rst | 2 +- controller.rst | 32 +- controller/error_pages.rst | 2 +- deployment.rst | 2 +- deployment/proxies.rst | 2 +- doctrine.rst | 8 +- doctrine/custom_dql_functions.rst | 2 +- doctrine/multiple_entity_managers.rst | 6 +- event_dispatcher.rst | 11 + form/bootstrap5.rst | 6 +- form/create_custom_field_type.rst | 2 +- form/data_mappers.rst | 4 +- form/data_transformers.rst | 6 +- form/direct_submit.rst | 2 +- form/events.rst | 4 +- form/form_collections.rst | 6 +- form/form_customization.rst | 4 +- form/form_themes.rst | 2 +- form/inherit_data_option.rst | 2 +- form/type_guesser.rst | 2 +- form/unit_testing.rst | 6 +- form/without_class.rst | 2 +- forms.rst | 2 +- frontend.rst | 10 + frontend/asset_mapper.rst | 129 +- frontend/encore/installation.rst | 2 +- frontend/encore/simple-example.rst | 4 +- frontend/encore/virtual-machine.rst | 4 +- http_cache/cache_invalidation.rst | 2 +- http_cache/esi.rst | 2 +- http_cache/varnish.rst | 33 +- http_client.rst | 18 +- lock.rst | 2 +- logging/channels_handlers.rst | 2 +- logging/monolog_exclude_http_codes.rst | 2 +- mailer.rst | 62 +- mercure.rst | 93 +- messenger.rst | 29 +- notifier.rst | 85 +- profiler.rst | 4 +- reference/attributes.rst | 12 +- reference/configuration/framework.rst | 11 +- reference/configuration/web_profiler.rst | 2 +- reference/constraints/Bic.rst | 15 +- reference/constraints/Callback.rst | 8 +- reference/constraints/DateTime.rst | 17 +- reference/constraints/EqualTo.rst | 2 +- reference/constraints/File.rst | 9 +- reference/constraints/IdenticalTo.rst | 2 +- reference/constraints/Image.rst | 20 + reference/constraints/MacAddress.rst | 1 + reference/constraints/NotEqualTo.rst | 2 +- reference/constraints/NotIdenticalTo.rst | 2 +- reference/constraints/PasswordStrength.rst | 6 +- reference/constraints/Slug.rst | 119 + reference/constraints/UniqueEntity.rst | 6 +- reference/constraints/_payload-option.rst.inc | 2 - reference/constraints/map.rst.inc | 1 + reference/dic_tags.rst | 4 +- reference/formats/expression_language.rst | 2 +- reference/formats/message_format.rst | 2 +- reference/forms/types/choice.rst | 2 +- reference/forms/types/collection.rst | 6 +- reference/forms/types/country.rst | 2 +- reference/forms/types/currency.rst | 2 +- reference/forms/types/date.rst | 9 +- reference/forms/types/dateinterval.rst | 4 +- reference/forms/types/entity.rst | 2 +- reference/forms/types/language.rst | 2 +- reference/forms/types/locale.rst | 2 +- reference/forms/types/money.rst | 5 +- .../types/options/_date_limitation.rst.inc | 2 +- .../forms/types/options/choice_lazy.rst.inc | 2 +- .../forms/types/options/choice_name.rst.inc | 2 +- reference/forms/types/options/data.rst.inc | 2 +- .../options/empty_data_description.rst.inc | 2 +- .../forms/types/options/inherit_data.rst.inc | 2 +- reference/forms/types/options/value.rst.inc | 2 +- reference/forms/types/password.rst | 2 +- reference/forms/types/textarea.rst | 2 +- reference/forms/types/time.rst | 10 +- reference/forms/types/timezone.rst | 2 +- reference/forms/types/url.rst | 7 + reference/twig_reference.rst | 33 +- routing.rst | 78 +- scheduler.rst | 8 + security.rst | 37 +- security/access_control.rst | 6 +- security/access_token.rst | 4 +- security/custom_authenticator.rst | 27 +- security/impersonating_user.rst | 9 +- security/ldap.rst | 4 +- security/login_link.rst | 2 +- security/passwords.rst | 2 +- security/remember_me.rst | 25 +- security/user_providers.rst | 2 +- security/voters.rst | 31 +- serializer.rst | 2331 ++++++++++++++--- serializer/custom_context_builders.rst | 8 +- serializer/custom_encoders.rst | 61 - serializer/custom_name_converter.rst | 112 + serializer/custom_normalizer.rst | 66 +- serializer/encoders.rst | 373 +++ service_container.rst | 4 +- service_container/compiler_passes.rst | 80 +- service_container/definitions.rst | 4 +- service_container/lazy_services.rst | 2 +- service_container/service_decoration.rst | 76 +- .../service_subscribers_locators.rst | 2 +- service_container/tags.rst | 17 +- session.rst | 26 +- setup.rst | 8 +- setup/_update_all_packages.rst.inc | 2 +- setup/file_permissions.rst | 8 +- setup/symfony_server.rst | 8 +- setup/upgrade_major.rst | 2 +- setup/web_server_configuration.rst | 110 +- string.rst | 10 +- templates.rst | 4 +- testing.rst | 16 +- testing/end_to_end.rst | 2 +- testing/insulating_clients.rst | 2 +- translation.rst | 8 +- validation.rst | 2 +- validation/custom_constraint.rst | 41 + validation/groups.rst | 2 +- validation/sequence_provider.rst | 4 +- web_link.rst | 22 +- webhook.rst | 7 +- workflow.rst | 2 +- 187 files changed, 4032 insertions(+), 3028 deletions(-) rename _images/{components => }/serializer/serializer_workflow.svg (100%) rename _images/sources/{components => }/serializer/serializer_workflow.dia (100%) delete mode 100644 components/serializer.rst create mode 100644 reference/constraints/Slug.rst delete mode 100644 serializer/custom_encoders.rst create mode 100644 serializer/custom_name_converter.rst create mode 100644 serializer/encoders.rst diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index 5ea86e6abc4..04e720bf653 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -23,6 +23,8 @@ rules: forbidden_directives: directives: - '.. index::' + - directive: '.. caution::' + replacements: ['.. warning::', '.. danger::'] indention: ~ lowercase_as_in_use_statements: ~ max_blank_lines: @@ -46,6 +48,7 @@ rules: no_namespace_after_use_statements: ~ no_php_open_tag_in_code_block_php_directive: ~ no_space_before_self_xml_closing_tag: ~ + non_static_phpunit_assertions: ~ only_backslashes_in_namespace_in_php_code_block: ~ only_backslashes_in_use_statements_in_php_code_block: ~ ordered_use_statements: ~ @@ -99,7 +102,6 @@ whitelist: - '#. 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.7.2' # Doctrine - '.. versionadded:: 2.8.0' # Doctrine - '.. versionadded:: 1.9.0' # Encore - '.. versionadded:: 1.18' # Flex in setup/upgrade_minor.rst diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fcbdbe0477b..061b0bb85b0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -73,7 +73,7 @@ jobs: key: ${{ runner.os }}-doctor-rst-${{ steps.extract_base_branch.outputs.branch }} - name: "Run DOCtor-RST" - uses: docker://oskarstark/doctor-rst:1.62.3 + uses: docker://oskarstark/doctor-rst:1.64.0 with: args: --short --error-format=github --cache-file=/github/workspace/.cache/doctor-rst.cache diff --git a/_build/redirection_map b/_build/redirection_map index 115ec75ade2..1701f4a8f70 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -525,8 +525,7 @@ /testing/functional_tests_assertions /testing#testing-application-assertions /components https://symfony.com/components /components/index https://symfony.com/components -/serializer/normalizers /components/serializer#normalizers -/components/serializer#component-serializer-attributes-groups-annotations /components/serializer#component-serializer-attributes-groups-attributes +/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 @@ -572,3 +571,5 @@ /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/_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/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/bundles.rst b/bundles.rst index ba3a2209999..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 @@ -58,7 +58,7 @@ Start by creating a new class called ``AcmeBlogBundle``:: { } -.. caution:: +.. warning:: If your bundle must be compatible with previous Symfony versions you have to extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\Bundle` instead. @@ -118,7 +118,7 @@ to be adjusted if needed: .. _bundles-legacy-directory-structure: -.. caution:: +.. warning:: The recommended bundle structure was changed in Symfony 5, read the `Symfony 4.4 bundle documentation`_ for information about the old diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 5996bcbe43d..376984388db 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -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 diff --git a/bundles/extension.rst b/bundles/extension.rst index 347f63b7af5..0537eb00c3e 100644 --- a/bundles/extension.rst +++ b/bundles/extension.rst @@ -200,7 +200,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 36aea69b231..f25bd785373 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -19,7 +19,7 @@ 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. diff --git a/cache.rst b/cache.rst index 7264585f233..833e4d77007 100644 --- a/cache.rst +++ b/cache.rst @@ -829,7 +829,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. diff --git a/components/cache/adapters/apcu_adapter.rst b/components/cache/adapters/apcu_adapter.rst index 99d76ce5d27..f2e92850cd8 100644 --- a/components/cache/adapters/apcu_adapter.rst +++ b/components/cache/adapters/apcu_adapter.rst @@ -5,7 +5,7 @@ This adapter is a high-performance, shared memory cache. It can *significantly* increase an application's performance, as its cache contents are stored in shared memory, a component appreciably faster than many others, such as the filesystem. -.. caution:: +.. warning:: **Requirement:** The `APCu extension`_ must be installed and active to use this adapter. @@ -30,7 +30,7 @@ and cache items version string as constructor arguments:: $version = null ); -.. caution:: +.. warning:: Use of this adapter is discouraged in write/delete heavy workloads, as these operations cause memory fragmentation that results in significantly degraded performance. diff --git a/components/cache/adapters/couchbasebucket_adapter.rst b/components/cache/adapters/couchbasebucket_adapter.rst index aaf400319f4..29c9e26f83c 100644 --- a/components/cache/adapters/couchbasebucket_adapter.rst +++ b/components/cache/adapters/couchbasebucket_adapter.rst @@ -14,7 +14,7 @@ shared memory; you can store contents independent of your PHP environment. The ability to utilize a cluster of servers to provide redundancy and/or fail-over is also available. -.. caution:: +.. warning:: **Requirements:** The `Couchbase PHP extension`_ as well as a `Couchbase server`_ must be installed, active, and running to use this adapter. Version ``2.6`` or diff --git a/components/cache/adapters/couchbasecollection_adapter.rst b/components/cache/adapters/couchbasecollection_adapter.rst index 25640a20b0f..ba78cc46eff 100644 --- a/components/cache/adapters/couchbasecollection_adapter.rst +++ b/components/cache/adapters/couchbasecollection_adapter.rst @@ -8,7 +8,7 @@ shared memory; you can store contents independent of your PHP environment. The ability to utilize a cluster of servers to provide redundancy and/or fail-over is also available. -.. caution:: +.. warning:: **Requirements:** The `Couchbase PHP extension`_ as well as a `Couchbase server`_ must be installed, active, and running to use this adapter. Version ``3.0`` or diff --git a/components/cache/adapters/filesystem_adapter.rst b/components/cache/adapters/filesystem_adapter.rst index 26ef48af27c..db877454859 100644 --- a/components/cache/adapters/filesystem_adapter.rst +++ b/components/cache/adapters/filesystem_adapter.rst @@ -33,7 +33,7 @@ and cache root path as constructor parameters:: $directory = null ); -.. caution:: +.. warning:: The overhead of filesystem IO often makes this adapter one of the *slower* choices. If throughput is paramount, the in-memory adapters diff --git a/components/cache/adapters/memcached_adapter.rst b/components/cache/adapters/memcached_adapter.rst index d68d3e3b9ac..64baf0d4702 100644 --- a/components/cache/adapters/memcached_adapter.rst +++ b/components/cache/adapters/memcached_adapter.rst @@ -8,7 +8,7 @@ shared memory; you can store contents independent of your PHP environment. The ability to utilize a cluster of servers to provide redundancy and/or fail-over is also available. -.. caution:: +.. warning:: **Requirements:** The `Memcached PHP extension`_ as well as a `Memcached server`_ must be installed, active, and running to use this adapter. Version ``2.2`` or @@ -256,7 +256,7 @@ Available Options executed in a "fire-and-forget" manner; no attempt to ensure the operation has been received or acted on will be made once the client has executed it. - .. caution:: + .. warning:: Not all library operations are tested in this mode. Mixed TCP and UDP servers are not allowed. diff --git a/components/cache/adapters/php_files_adapter.rst b/components/cache/adapters/php_files_adapter.rst index efd2cf0e964..6f171f0fede 100644 --- a/components/cache/adapters/php_files_adapter.rst +++ b/components/cache/adapters/php_files_adapter.rst @@ -28,7 +28,7 @@ file similar to the following:: handles file includes, this adapter has the potential to be much faster than other filesystem-based caches. -.. caution:: +.. warning:: While it supports updates and because it is using OPcache as a backend, this adapter is better suited for append-mostly needs. Using it in other scenarios might lead to diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst index 719d6056f19..3362f4cc2db 100644 --- a/components/cache/adapters/redis_adapter.rst +++ b/components/cache/adapters/redis_adapter.rst @@ -15,7 +15,7 @@ Unlike the :doc:`APCu adapter `, and si shared memory; you can store contents independent of your PHP environment. The ability to utilize a cluster of servers to provide redundancy and/or fail-over is also available. -.. caution:: +.. warning:: **Requirements:** At least one `Redis server`_ must be installed and running to use this adapter. Additionally, this adapter requires a compatible extension or library that implements @@ -38,7 +38,13 @@ as the second and third parameters:: // the default lifetime (in seconds) for cache items that do not define their // own lifetime, with a value 0 causing items to be stored indefinitely (i.e. // until RedisAdapter::clear() is invoked or the server(s) are purged) - $defaultLifetime = 0 + $defaultLifetime = 0, + + // $marshaller (optional) An instance of MarshallerInterface to control the serialization + // and deserialization of cache items. By default, native PHP serialization is used. + // This can be useful for compressing data, applying custom serialization logic, or + // optimizing the size and performance of cached items + ?MarshallerInterface $marshaller = null ); Configure the Connection @@ -266,6 +272,80 @@ performance when using tag-based invalidation:: Read more about this topic in the official `Redis LRU Cache Documentation`_. +Working with Marshaller +----------------------- + +TagAwareMarshaller for Tag-Based Caching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Optimizes caching for tag-based retrieval, allowing efficient management of related items:: + + $marshaller = new TagAwareMarshaller(); + + $cache = new RedisAdapter($redis, 'tagged_namespace', 3600, $marshaller); + + $item = $cache->getItem('tagged_key'); + $item->set(['value' => 'some_data', 'tags' => ['tag1', 'tag2']]); + $cache->save($item); + +SodiumMarshaller for Encrypted Caching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Encrypts cached data using Sodium for enhanced security:: + + $encryptionKeys = [sodium_crypto_box_keypair()]; + $marshaller = new SodiumMarshaller($encryptionKeys); + + $cache = new RedisAdapter($redis, 'secure_namespace', 3600, $marshaller); + + $item = $cache->getItem('secure_key'); + $item->set('confidential_data'); + $cache->save($item); + +DefaultMarshaller with igbinary Serialization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Uses ``igbinary` for faster and more efficient serialization when available:: + + $marshaller = new DefaultMarshaller(true); + + $cache = new RedisAdapter($redis, 'optimized_namespace', 3600, $marshaller); + + $item = $cache->getItem('optimized_key'); + $item->set(['data' => 'optimized_data']); + $cache->save($item); + +DefaultMarshaller with Exception on Failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Throws an exception if serialization fails, facilitating error handling:: + + $marshaller = new DefaultMarshaller(false, true); + + $cache = new RedisAdapter($redis, 'error_namespace', 3600, $marshaller); + + try { + $item = $cache->getItem('error_key'); + $item->set('data'); + $cache->save($item); + } catch (\ValueError $e) { + echo 'Serialization failed: '.$e->getMessage(); + } + +SodiumMarshaller with Key Rotation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Supports key rotation, ensuring secure decryption with both old and new keys:: + + $keys = [sodium_crypto_box_keypair(), sodium_crypto_box_keypair()]; + $marshaller = new SodiumMarshaller($keys); + + $cache = new RedisAdapter($redis, 'rotated_namespace', 3600, $marshaller); + + $item = $cache->getItem('rotated_key'); + $item->set('data_to_encrypt'); + $cache->save($item); + .. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name .. _`Redis server`: https://redis.io/ .. _`Redis`: https://github.com/phpredis/phpredis diff --git a/components/clock.rst b/components/clock.rst index cdbbdd56e6b..5b20e6000b9 100644 --- a/components/clock.rst +++ b/components/clock.rst @@ -129,18 +129,18 @@ is expired or not, by modifying the clock's time:: $validUntil = new DateTimeImmutable('2022-11-16 15:25:00'); // $validUntil is in the future, so it is not expired - static::assertFalse($expirationChecker->isExpired($validUntil)); + $this->assertFalse($expirationChecker->isExpired($validUntil)); // Clock sleeps for 10 minutes, so now is '2022-11-16 15:30:00' $clock->sleep(600); // Instantly changes time as if we waited for 10 minutes (600 seconds) // modify the clock, accepts all formats supported by DateTimeImmutable::modify() - static::assertTrue($expirationChecker->isExpired($validUntil)); + $this->assertTrue($expirationChecker->isExpired($validUntil)); $clock->modify('2022-11-16 15:00:00'); // $validUntil is in the future again, so it is no longer expired - static::assertFalse($expirationChecker->isExpired($validUntil)); + $this->assertFalse($expirationChecker->isExpired($validUntil)); } } diff --git a/components/config/definition.rst b/components/config/definition.rst index 929246fa915..24c142ec5a5 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -83,9 +83,19 @@ reflect the real structure of the configuration values:: ->scalarNode('default_connection') ->defaultValue('mysql') ->end() + ->stringNode('username') + ->defaultValue('root') + ->end() + ->stringNode('password') + ->defaultValue('root') + ->end() ->end() ; +.. versionadded:: 7.2 + + The ``stringNode()`` method was introduced in Symfony 7.2. + The root node itself is an array node, and has children, like the boolean node ``auto_connect`` and the scalar node ``default_connection``. In general: after defining a node, a call to ``end()`` takes you one step up in the @@ -100,6 +110,7 @@ node definition. Node types are available for: * scalar (generic type that includes booleans, strings, integers, floats and ``null``) * boolean +* string * integer * float * enum (similar to scalar, but it only allows a finite set of values) @@ -109,6 +120,10 @@ node definition. Node types are available for: and are created with ``node($name, $type)`` or their associated shortcut ``xxxxNode($name)`` method. +.. versionadded:: 7.2 + + Support for the ``string`` type was introduced in Symfony 7.2. + Numeric Node Constraints ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -670,7 +685,7 @@ The separator used in keys is typically ``_`` in YAML and ``-`` in XML. For example, ``auto_connect`` in YAML and ``auto-connect`` in XML. The normalization would make both of these ``auto_connect``. -.. caution:: +.. warning:: The target key will not be altered if it's mixed like ``foo-bar_moo`` or if it already exists. @@ -800,6 +815,7 @@ A validation rule always has an "if" part. You can specify this part in the following ways: - ``ifTrue()`` +- ``ifFalse()`` - ``ifString()`` - ``ifNull()`` - ``ifEmpty()`` @@ -818,6 +834,10 @@ A validation rule also requires a "then" part: Usually, "then" is a closure. Its return value will be used as a new value for the node, instead of the node's original value. +.. versionadded:: 7.3 + + The ``ifFalse()`` method was introduced in Symfony 7.3. + Configuring the Node Path Separator ----------------------------------- @@ -889,7 +909,7 @@ Otherwise the result is a clean array of configuration values:: $configs ); -.. caution:: +.. warning:: When processing the configuration tree, the processor assumes that the top level array key (which matches the extension name) is already stripped off. diff --git a/components/console/changing_default_command.rst b/components/console/changing_default_command.rst index b739e3b39ba..c69995ea395 100644 --- a/components/console/changing_default_command.rst +++ b/components/console/changing_default_command.rst @@ -52,7 +52,7 @@ This will print the following to the command line: Hello World -.. caution:: +.. warning:: This feature has a limitation: you cannot pass any argument or option to the default command because they are ignored. diff --git a/components/console/events.rst b/components/console/events.rst index f0edf2205ac..e550025b7dd 100644 --- a/components/console/events.rst +++ b/components/console/events.rst @@ -14,7 +14,7 @@ the wheel, it uses the Symfony EventDispatcher component to do the work:: $application->setDispatcher($dispatcher); $application->run(); -.. caution:: +.. warning:: Console events are only triggered by the main command being executed. Commands called by the main command will not trigger any event, unless diff --git a/components/console/helpers/formatterhelper.rst b/components/console/helpers/formatterhelper.rst index 3cb87c4c307..d2b19915a3a 100644 --- a/components/console/helpers/formatterhelper.rst +++ b/components/console/helpers/formatterhelper.rst @@ -129,10 +129,16 @@ Sometimes you want to format seconds to time. This is possible with the The first argument is the seconds to format and the second argument is the precision (default ``1``) of the result:: - Helper::formatTime(42); // 42 secs - Helper::formatTime(125); // 2 mins - Helper::formatTime(125, 2); // 2 mins, 5 secs - Helper::formatTime(172799, 4); // 1 day, 23 hrs, 59 mins, 59 secs + Helper::formatTime(0.001); // 1 ms + Helper::formatTime(42); // 42 s + Helper::formatTime(125); // 2 min + Helper::formatTime(125, 2); // 2 min, 5 s + Helper::formatTime(172799, 4); // 1 d, 23 h, 59 min, 59 s + Helper::formatTime(172799.056, 5); // 1 d, 23 h, 59 min, 59 s, 56 ms + +.. versionadded:: 7.3 + + Support for formatting up to milliseconds was introduced in Symfony 7.3. Formatting Memory ----------------- diff --git a/components/console/helpers/progressbar.rst b/components/console/helpers/progressbar.rst index 4d524a2008e..19e2d0daef5 100644 --- a/components/console/helpers/progressbar.rst +++ b/components/console/helpers/progressbar.rst @@ -323,7 +323,7 @@ to display it can be customized:: // the bar width $progressBar->setBarWidth(50); -.. caution:: +.. warning:: For performance reasons, Symfony redraws the screen once every 100ms. If this is too fast or too slow for your application, use the methods diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index e33c4ed5fa7..2670ec3084a 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -329,7 +329,7 @@ convenient for passwords:: return Command::SUCCESS; } -.. caution:: +.. warning:: When you ask for a hidden response, Symfony will use either a binary, change ``stty`` mode or use another trick to hide the response. If none is available, @@ -392,7 +392,7 @@ method:: return Command::SUCCESS; } -.. caution:: +.. warning:: The normalizer is called first and the returned value is used as the input of the validator. If the answer is invalid, don't throw exceptions in the @@ -540,7 +540,7 @@ This way you can test any user interaction (even complex ones) by passing the ap simulates a user hitting ``ENTER`` after each input, no need for passing an additional input. -.. caution:: +.. warning:: On Windows systems Symfony uses a special binary to implement hidden questions. This means that those questions don't use the default ``Input`` diff --git a/components/event_dispatcher.rst b/components/event_dispatcher.rst index 83cead3d19c..8cd676dd5fe 100644 --- a/components/event_dispatcher.rst +++ b/components/event_dispatcher.rst @@ -476,11 +476,7 @@ with some other dispatchers: Learn More ---------- -.. toctree:: - :maxdepth: 1 - - /components/event_dispatcher/generic_event - +* :doc:`/components/event_dispatcher/generic_event` * :ref:`The kernel.event_listener tag ` * :ref:`The kernel.event_subscriber tag ` diff --git a/components/expression_language.rst b/components/expression_language.rst index 785beebd9da..b0dd10b0f42 100644 --- a/components/expression_language.rst +++ b/components/expression_language.rst @@ -106,6 +106,10 @@ if the expression is not valid:: $expressionLanguage->lint('1 + 2', []); // doesn't throw anything + $expressionLanguage->lint('1 + a', []); + // throws a SyntaxError exception: + // "Variable "a" is not valid around position 5 for expression `1 + a`." + The behavior of these methods can be configured with some flags defined in the :class:`Symfony\\Component\\ExpressionLanguage\\Parser` class: @@ -121,8 +125,8 @@ This is how you can use these flags:: $expressionLanguage = new ExpressionLanguage(); - // this returns true because the unknown variables and functions are ignored - var_dump($expressionLanguage->lint('unknown_var + unknown_function()', Parser::IGNORE_UNKNOWN_VARIABLES | Parser::IGNORE_UNKNOWN_FUNCTIONS)); + // does not throw a SyntaxError because the unknown variables and functions are ignored + $expressionLanguage->lint('unknown_var + unknown_function()', [], Parser::IGNORE_UNKNOWN_VARIABLES | Parser::IGNORE_UNKNOWN_FUNCTIONS); .. versionadded:: 7.1 diff --git a/components/finder.rst b/components/finder.rst index a3b91470b62..cecc597ac64 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -41,7 +41,7 @@ The ``$file`` variable is an instance of :class:`Symfony\\Component\\Finder\\SplFileInfo` which extends PHP's own :phpclass:`SplFileInfo` to provide methods to work with relative paths. -.. caution:: +.. warning:: The ``Finder`` object doesn't reset its internal state automatically. This means that you need to create a new instance if you do not want diff --git a/components/form.rst b/components/form.rst index f463ef5911b..44f407e4c8e 100644 --- a/components/form.rst +++ b/components/form.rst @@ -644,7 +644,7 @@ method: // ... -.. caution:: +.. warning:: The form's ``createView()`` method should be called *after* ``handleRequest()`` is called. Otherwise, when using :doc:`form events `, changes done diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 4dcf3b1e4da..8db6cd27f68 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -367,11 +367,13 @@ of the ``anonymize()`` method to specify the number of bytes that should be anonymized depending on the IP address format:: $ipv4 = '123.234.235.236'; - $anonymousIpv4 = IpUtils::anonymize($ipv4, v4Bytes: 3); + $anonymousIpv4 = IpUtils::anonymize($ipv4, 3); // $anonymousIpv4 = '123.0.0.0' $ipv6 = '2a01:198:603:10:396e:4789:8e99:890f'; - $anonymousIpv6 = IpUtils::anonymize($ipv6, v6Bytes: 10); + // (you must define the second argument (bytes to anonymize in IPv4 addresses) + // even when you are only anonymizing IPv6 addresses) + $anonymousIpv6 = IpUtils::anonymize($ipv6, 3, 10); // $anonymousIpv6 = '2a01:198:603::' .. versionadded:: 7.2 @@ -679,8 +681,19 @@ Streaming a Response ~~~~~~~~~~~~~~~~~~~~ The :class:`Symfony\\Component\\HttpFoundation\\StreamedResponse` class allows -you to stream the Response back to the client. The response content is -represented by a PHP callable instead of a string:: +you to stream the Response back to the client. The response content can be +represented by a string iterable:: + + use Symfony\Component\HttpFoundation\StreamedResponse; + + $chunks = ['Hello', ' World']; + + $response = new StreamedResponse(); + $response->setChunks($chunks); + $response->send(); + +For most complex use cases, the response content can be instead represented by +a PHP callable:: use Symfony\Component\HttpFoundation\StreamedResponse; @@ -708,6 +721,10 @@ represented by a PHP callable instead of a string:: // disables FastCGI buffering in nginx only for this response $response->headers->set('X-Accel-Buffering', 'no'); +.. versionadded:: 7.3 + + Support for using string iterables was introduced in Symfony 7.3. + Streaming a JSON Response ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/http_kernel.rst b/components/http_kernel.rst index 97de70b66df..02791b370bc 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -471,7 +471,7 @@ you will trigger the ``kernel.terminate`` event where you can perform certain actions that you may have delayed in order to return the response as quickly as possible to the client (e.g. sending emails). -.. caution:: +.. warning:: Internally, the HttpKernel makes use of the :phpfunction:`fastcgi_finish_request` PHP function. This means that at the moment, only the `PHP FPM`_ server diff --git a/components/ldap.rst b/components/ldap.rst index d5f6bc3fdfe..e52a341986c 100644 --- a/components/ldap.rst +++ b/components/ldap.rst @@ -70,7 +70,7 @@ distinguished name (DN) and the password of a user:: $ldap->bind($dn, $password); -.. caution:: +.. danger:: When the LDAP server allows unauthenticated binds, a blank password will always be valid. diff --git a/components/lock.rst b/components/lock.rst index bf75fb49f7a..b8ba38c8fc7 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -359,7 +359,7 @@ lose the lock it acquired automatically:: throw new \Exception('Process failed'); } -.. caution:: +.. warning:: A common pitfall might be to use the ``isAcquired()`` method to check if a lock has already been acquired by any process. As you can see in this example @@ -427,7 +427,7 @@ when the PHP process ends):: // if none is given, sys_get_temp_dir() is used internally. $store = new FlockStore('/var/stores'); -.. caution:: +.. warning:: Beware that some file systems (such as some types of NFS) do not support locking. In those cases, it's better to use a directory on a local disk @@ -668,7 +668,7 @@ the stores:: $store = new CombinedStore($stores, new UnanimousStrategy()); -.. caution:: +.. warning:: In order to get high availability when using the ``ConsensusStrategy``, the minimum cluster size must be three servers. This allows the cluster to keep @@ -720,7 +720,7 @@ the ``Lock``. Every concurrent process must store the ``Lock`` on the same server. Otherwise two different machines may allow two different processes to acquire the same ``Lock``. -.. caution:: +.. warning:: To guarantee that the same server will always be safe, do not use Memcached behind a LoadBalancer, a cluster or round-robin DNS. Even if the main server @@ -762,12 +762,12 @@ Using the above methods, a robust code would be:: // Perform the task whose duration MUST be less than 5 seconds } -.. caution:: +.. warning:: Choose wisely the lifetime of the ``Lock`` and check whether its remaining time to live is enough to perform the task. -.. caution:: +.. warning:: Storing a ``Lock`` usually takes a few milliseconds, but network conditions may increase that time a lot (up to a few seconds). Take that into account @@ -776,7 +776,7 @@ Using the above methods, a robust code would be:: By design, locks are stored on servers with a defined lifetime. If the date or time of the machine changes, a lock could be released sooner than expected. -.. caution:: +.. warning:: To guarantee that date won't change, the NTP service should be disabled and the date should be updated when the service is stopped. @@ -798,7 +798,7 @@ deployments. Some file systems (such as some types of NFS) do not support locking. -.. caution:: +.. warning:: All concurrent processes must use the same physical file system by running on the same machine and using the same absolute path to the lock directory. @@ -827,7 +827,7 @@ and may disappear by mistake at any time. If the Memcached service or the machine hosting it restarts, every lock would be lost without notifying the running processes. -.. caution:: +.. warning:: To avoid that someone else acquires a lock after a restart, it's recommended to delay service start and wait at least as long as the longest lock TTL. @@ -835,7 +835,7 @@ be lost without notifying the running processes. By default Memcached uses a LRU mechanism to remove old entries when the service needs space to add new items. -.. caution:: +.. warning:: The number of items stored in Memcached must be under control. If it's not possible, LRU should be disabled and Lock should be stored in a dedicated @@ -853,7 +853,7 @@ method uses the Memcached's ``flush()`` method which purges and removes everythi MongoDbStore ~~~~~~~~~~~~ -.. caution:: +.. warning:: The locked resource name is indexed in the ``_id`` field of the lock collection. Beware that an indexed field's value in MongoDB can be @@ -879,7 +879,7 @@ about `Expire Data from Collections by Setting TTL`_ in MongoDB. recommended to set constructor option ``gcProbability`` to ``0.0`` to disable this behavior if you have manually dealt with TTL index creation. -.. caution:: +.. warning:: This store relies on all PHP application and database nodes to have synchronized clocks for lock expiry to occur at the correct time. To ensure @@ -896,12 +896,12 @@ PdoStore The PdoStore relies on the `ACID`_ properties of the SQL engine. -.. caution:: +.. warning:: In a cluster configured with multiple primaries, ensure writes are synchronously propagated to every node, or always use the same node. -.. caution:: +.. warning:: Some SQL engines like MySQL allow to disable the unique constraint check. Ensure that this is not the case ``SET unique_checks=1;``. @@ -910,7 +910,7 @@ In order to purge old locks, this store uses a current datetime to define an expiration date reference. This mechanism relies on all server nodes to have synchronized clocks. -.. caution:: +.. warning:: To ensure locks don't expire prematurely; the TTLs should be set with enough extra time to account for any clock drift between nodes. @@ -939,7 +939,7 @@ and may disappear by mistake at any time. If the Redis service or the machine hosting it restarts, every locks would be lost without notifying the running processes. -.. caution:: +.. warning:: To avoid that someone else acquires a lock after a restart, it's recommended to delay service start and wait at least as long as the longest lock TTL. @@ -967,7 +967,7 @@ The ``CombinedStore`` will be, at best, as reliable as the least reliable of all managed stores. As soon as one managed store returns erroneous information, the ``CombinedStore`` won't be reliable. -.. caution:: +.. warning:: All concurrent processes must use the same configuration, with the same amount of managed stored and the same endpoint. @@ -985,13 +985,13 @@ must run on the same machine, virtual machine or container. Be careful when updating a Kubernetes or Swarm service because for a short period of time, there can be two running containers in parallel. -.. caution:: +.. warning:: All concurrent processes must use the same machine. Before starting a concurrent process on a new machine, check that other processes are stopped on the old one. -.. caution:: +.. warning:: When running on systemd with non-system user and option ``RemoveIPC=yes`` (default value), locks are deleted by systemd when that user logs out. diff --git a/components/options_resolver.rst b/components/options_resolver.rst index c8052d0d395..ff25f9e0fc4 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -485,7 +485,7 @@ these options, you can return the desired default value:: } } -.. caution:: +.. warning:: The argument of the callable must be type hinted as ``Options``. Otherwise, the callable itself is considered as the default value of the option. @@ -699,7 +699,7 @@ to the closure to access to them:: } } -.. caution:: +.. warning:: The arguments of the closure must be type hinted as ``OptionsResolver`` and ``Options`` respectively. Otherwise, the closure itself is considered as the diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index ba37bc0ecda..5ce4c003a11 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -253,7 +253,7 @@ deprecations but: * forget to mark appropriate tests with the ``@group legacy`` annotations. By using ``SYMFONY_DEPRECATIONS_HELPER=max[self]=0``, deprecations that are -triggered outside the ``vendors`` directory will be accounted for separately, +triggered outside the ``vendor/`` directory will be accounted for separately, while deprecations triggered from a library inside it will not (unless you reach 999999 of these), giving you the best of both worlds. @@ -621,7 +621,7 @@ test:: And that's all! -.. caution:: +.. warning:: Time-based function mocking follows the `PHP namespace resolutions rules`_ so "fully qualified function calls" (e.g ``\time()``) cannot be mocked. diff --git a/components/process.rst b/components/process.rst index 9502665dde1..f6c8837d2c3 100644 --- a/components/process.rst +++ b/components/process.rst @@ -108,7 +108,7 @@ You can configure the options passed to the ``other_options`` argument of // this option allows a subprocess to continue running after the main script exited $process->setOptions(['create_new_console' => true]); -.. caution:: +.. warning:: Most of the options defined by ``proc_open()`` (such as ``create_new_console`` and ``suppress_errors``) are only supported on Windows operating systems. @@ -552,7 +552,7 @@ Use :method:`Symfony\\Component\\Process\\Process::disableOutput` and $process->disableOutput(); $process->run(); -.. caution:: +.. warning:: You cannot enable or disable the output while the process is running. diff --git a/components/property_access.rst b/components/property_access.rst index 600481dce1a..f608640fa9b 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -26,6 +26,8 @@ default configuration:: $propertyAccessor = PropertyAccess::createPropertyAccessor(); +.. _property-access-reading-arrays: + Reading from Arrays ------------------- @@ -112,7 +114,7 @@ To read from properties, use the "dot" notation:: var_dump($propertyAccessor->getValue($person, 'children[0].firstName')); // 'Bar' -.. caution:: +.. warning:: Accessing public properties is the last option used by ``PropertyAccessor``. It tries to access the value using the below methods first before using @@ -260,7 +262,7 @@ The ``getValue()`` method can also use the magic ``__get()`` method:: var_dump($propertyAccessor->getValue($person, 'Wouter')); // [...] -.. caution:: +.. warning:: When implementing the magic ``__get()`` method, you also need to implement ``__isset()``. @@ -301,7 +303,7 @@ enable this feature by using :class:`Symfony\\Component\\PropertyAccess\\Propert var_dump($propertyAccessor->getValue($person, 'wouter')); // [...] -.. caution:: +.. warning:: The ``__call()`` feature is disabled by default, you can enable it by calling :method:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder::enableMagicCall` diff --git a/components/property_info.rst b/components/property_info.rst index 892cd5345a3..0ff1768441a 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -469,7 +469,18 @@ information from annotations of properties and methods, such as ``@var``, use App\Domain\Foo; $phpStanExtractor = new PhpStanExtractor(); + + // Type information. $phpStanExtractor->getTypesFromConstructor(Foo::class, 'bar'); + // Description information. + $phpStanExtractor->getShortDescription($class, 'bar'); + $phpStanExtractor->getLongDescription($class, 'bar'); + +.. versionadded:: 7.3 + + The :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpStanExtractor::getShortDescription` + and :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpStanExtractor::getLongDescription` + methods were introduced in Symfony 7.3. SerializerExtractor ~~~~~~~~~~~~~~~~~~~ @@ -478,9 +489,9 @@ SerializerExtractor This extractor depends on the `symfony/serializer`_ library. -Using :ref:`groups metadata ` -from the :doc:`Serializer component `, -the :class:`Symfony\\Component\\PropertyInfo\\Extractor\\SerializerExtractor` +Using :ref:`groups metadata ` from the +:doc:`Serializer component `, the +:class:`Symfony\\Component\\PropertyInfo\\Extractor\\SerializerExtractor` provides list information. This extractor is *not* registered automatically with the ``property_info`` service in the Symfony Framework:: diff --git a/components/runtime.rst b/components/runtime.rst index 7d17e7e7456..4eb75de2a75 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -3,7 +3,7 @@ The Runtime Component The Runtime Component decouples the bootstrapping logic from any global state to make sure the application can run with runtimes like `PHP-PM`_, `ReactPHP`_, - `Swoole`_, etc. without any changes. + `Swoole`_, `FrankenPHP`_ etc. without any changes. Installation ------------ @@ -42,7 +42,7 @@ the component. This file runs the following logic: #. At last, the Runtime is used to run the application (i.e. calling ``$kernel->handle(Request::createFromGlobals())->send()``). -.. caution:: +.. warning:: If you use the Composer ``--no-plugins`` option, the ``autoload_runtime.php`` file won't be created. @@ -487,6 +487,7 @@ The end user will now be able to create front controller like:: .. _PHP-PM: https://github.com/php-pm/php-pm .. _Swoole: https://openswoole.com/ +.. _FrankenPHP: https://frankenphp.dev/ .. _ReactPHP: https://reactphp.org/ .. _`PSR-15`: https://www.php-fig.org/psr/psr-15/ .. _`runtime template file`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Runtime/Internal/autoload_runtime.template diff --git a/components/serializer.rst b/components/serializer.rst deleted file mode 100644 index 0764612e28a..00000000000 --- a/components/serializer.rst +++ /dev/null @@ -1,1938 +0,0 @@ -The Serializer Component -======================== - - The Serializer component is meant to be used to turn objects into a - specific format (XML, JSON, YAML, ...) and the other way around. - -In order to do so, the Serializer component follows the following schema. - -.. raw:: html - - - -When (de)serializing objects, the Serializer uses an array as the intermediary -between objects and serialized contents. Encoders will only deal with -turning specific **formats** into **arrays** and vice versa. The same way, -normalizers will deal with turning specific **objects** into **arrays** and -vice versa. The Serializer deals with calling the normalizers and encoders -when serializing objects or deserializing formats. - -Serialization is a complex topic. This component may not cover all your use -cases out of the box, but it can be useful for developing tools to -serialize and deserialize your objects. - -Installation ------------- - -.. code-block:: terminal - - $ composer require symfony/serializer - -.. include:: /components/require_autoload.rst.inc - -To use the ``ObjectNormalizer``, the :doc:`PropertyAccess component ` -must also be installed. - -Usage ------ - -.. seealso:: - - This article explains the philosophy of the Serializer and gets you familiar - with the concepts of normalizers and encoders. The code examples assume - that you use the Serializer as an independent component. If you are using - the Serializer in a Symfony application, read :doc:`/serializer` after you - finish this article. - -To use the Serializer component, set up the -:class:`Symfony\\Component\\Serializer\\Serializer` specifying which encoders -and normalizer are going to be available:: - - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Encoder\XmlEncoder; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $encoders = [new XmlEncoder(), new JsonEncoder()]; - $normalizers = [new ObjectNormalizer()]; - - $serializer = new Serializer($normalizers, $encoders); - -The preferred normalizer is the -:class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer`, -but other normalizers are available. All the examples shown below use -the ``ObjectNormalizer``. - -Serializing an Object ---------------------- - -For the sake of this example, assume the following class already -exists in your project:: - - namespace App\Model; - - class Person - { - private int $age; - private string $name; - private bool $sportsperson; - private ?\DateTimeInterface $createdAt; - - // Getters - public function getAge(): int - { - return $this->age; - } - - public function getName(): string - { - return $this->name; - } - - public function getCreatedAt(): ?\DateTimeInterface - { - return $this->createdAt; - } - - // Issers - public function isSportsperson(): bool - { - return $this->sportsperson; - } - - // Setters - public function setAge(int $age): void - { - $this->age = $age; - } - - public function setName(string $name): void - { - $this->name = $name; - } - - public function setSportsperson(bool $sportsperson): void - { - $this->sportsperson = $sportsperson; - } - - public function setCreatedAt(?\DateTimeInterface $createdAt = null): void - { - $this->createdAt = $createdAt; - } - } - -Now, if you want to serialize this object into JSON, you only need to -use the Serializer service created before:: - - use App\Model\Person; - - $person = new Person(); - $person->setName('foo'); - $person->setAge(99); - $person->setSportsperson(false); - - $jsonContent = $serializer->serialize($person, 'json'); - - // $jsonContent contains {"name":"foo","age":99,"sportsperson":false,"createdAt":null} - - echo $jsonContent; // or return it in a Response - -The first parameter of the :method:`Symfony\\Component\\Serializer\\Serializer::serialize` -is the object to be serialized and the second is used to choose the proper encoder, -in this case :class:`Symfony\\Component\\Serializer\\Encoder\\JsonEncoder`. - -Deserializing an Object ------------------------ - -You'll now learn how to do the exact opposite. This time, the information -of the ``Person`` class would be encoded in XML format:: - - use App\Model\Person; - - $data = << - foo - 99 - false - - EOF; - - $person = $serializer->deserialize($data, Person::class, 'xml'); - -In this case, :method:`Symfony\\Component\\Serializer\\Serializer::deserialize` -needs three parameters: - -#. The information to be decoded -#. The name of the class this information will be decoded to -#. The encoder used to convert that information into an array - -By default, additional attributes that are not mapped to the denormalized object -will be ignored by the Serializer component. If you prefer to throw an exception -when this happens, set the ``AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES`` context option to -``false`` and provide an object that implements ``ClassMetadataFactoryInterface`` -when constructing the normalizer:: - - use App\Model\Person; - - $data = << - foo - 99 - Paris - - EOF; - - // $loader is any of the valid loaders explained later in this article - $classMetadataFactory = new ClassMetadataFactory($loader); - $normalizer = new ObjectNormalizer($classMetadataFactory); - $serializer = new Serializer([$normalizer]); - - // this will throw a Symfony\Component\Serializer\Exception\ExtraAttributesException - // because "city" is not an attribute of the Person class - $person = $serializer->deserialize($data, Person::class, 'xml', [ - AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, - ]); - -Deserializing in an Existing Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The serializer can also be used to update an existing object:: - - // ... - $person = new Person(); - $person->setName('bar'); - $person->setAge(99); - $person->setSportsperson(true); - - $data = << - foo - 69 - - EOF; - - $serializer->deserialize($data, Person::class, 'xml', [AbstractNormalizer::OBJECT_TO_POPULATE => $person]); - // $person = App\Model\Person(name: 'foo', age: '69', sportsperson: true) - -This is a common need when working with an ORM. - -The ``AbstractNormalizer::OBJECT_TO_POPULATE`` is only used for the top level object. If that object -is the root of a tree structure, all child elements that exist in the -normalized data will be re-created with new instances. - -When the ``AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE`` option is set to -true, existing children of the root ``OBJECT_TO_POPULATE`` are updated from the -normalized data, instead of the denormalizer re-creating them. Note that -``DEEP_OBJECT_TO_POPULATE`` only works for single child objects, but not for -arrays of objects. Those will still be replaced when present in the normalized -data. - -Context -------- - -Many Serializer features can be configured :ref:`using a context `. - -.. _component-serializer-attributes-groups: - -Attributes Groups ------------------ - -Sometimes, you want to serialize different sets of attributes from your -entities. Groups are a handy way to achieve this need. - -Assume you have the following plain-old-PHP object:: - - namespace Acme; - - class MyObj - { - public string $foo; - - private string $bar; - - public function getBar(): string - { - return $this->bar; - } - - public function setBar($bar): string - { - return $this->bar = $bar; - } - } - -The definition of serialization can be specified using attributes, XML or YAML. -The :class:`Symfony\\Component\\Serializer\\Mapping\\Factory\\ClassMetadataFactory` -that will be used by the normalizer must be aware of the format to use. - -The following code shows how to initialize the :class:`Symfony\\Component\\Serializer\\Mapping\\Factory\\ClassMetadataFactory` -for each format: - -* Attributes in PHP files:: - - use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; - use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; - - $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); - -* YAML files:: - - use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; - use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; - - $classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader('/path/to/your/definition.yaml')); - -* XML files:: - - use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; - use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; - - $classMetadataFactory = new ClassMetadataFactory(new XmlFileLoader('/path/to/your/definition.xml')); - -.. _component-serializer-attributes-groups-attributes: - -Then, create your groups definition: - -.. configuration-block:: - - .. code-block:: php-attributes - - namespace Acme; - - use Symfony\Component\Serializer\Annotation\Groups; - - class MyObj - { - #[Groups(['group1', 'group2'])] - public string $foo; - - #[Groups(['group4'])] - public string $anotherProperty; - - #[Groups(['group3'])] - public function getBar() // is* methods are also supported - { - return $this->bar; - } - - // ... - } - - .. code-block:: yaml - - Acme\MyObj: - attributes: - foo: - groups: ['group1', 'group2'] - anotherProperty: - groups: ['group4'] - bar: - groups: ['group3'] - - .. code-block:: xml - - - - - - group1 - group2 - - - - group4 - - - - group3 - - - - -You are now able to serialize only attributes in the groups you want:: - - use Acme\MyObj; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $obj = new MyObj(); - $obj->foo = 'foo'; - $obj->anotherProperty = 'anotherProperty'; - $obj->setBar('bar'); - - $normalizer = new ObjectNormalizer($classMetadataFactory); - $serializer = new Serializer([$normalizer]); - - $data = $serializer->normalize($obj, null, ['groups' => 'group1']); - // $data = ['foo' => 'foo']; - - $obj2 = $serializer->denormalize( - ['foo' => 'foo', 'anotherProperty' => 'anotherProperty', 'bar' => 'bar'], - MyObj::class, - null, - ['groups' => ['group1', 'group3']] - ); - // $obj2 = MyObj(foo: 'foo', bar: 'bar') - - // To get all groups, use the special value `*` in `groups` - $obj3 = $serializer->denormalize( - ['foo' => 'foo', 'anotherProperty' => 'anotherProperty', 'bar' => 'bar'], - MyObj::class, - null, - ['groups' => ['*']] - ); - // $obj2 = MyObj(foo: 'foo', anotherProperty: 'anotherProperty', bar: 'bar') - -.. _ignoring-attributes-when-serializing: - -Selecting Specific Attributes ------------------------------ - -It is also possible to serialize only a set of specific attributes:: - - use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - class User - { - public string $familyName; - public string $givenName; - public Company $company; - } - - class Company - { - public string $name; - public string $address; - } - - $company = new Company(); - $company->name = 'Les-Tilleuls.coop'; - $company->address = 'Lille, France'; - - $user = new User(); - $user->familyName = 'Dunglas'; - $user->givenName = 'Kévin'; - $user->company = $company; - - $serializer = new Serializer([new ObjectNormalizer()]); - - $data = $serializer->normalize($user, null, [AbstractNormalizer::ATTRIBUTES => ['familyName', 'company' => ['name']]]); - // $data = ['familyName' => 'Dunglas', 'company' => ['name' => 'Les-Tilleuls.coop']]; - -Only attributes that are not ignored (see below) are available. -If some serialization groups are set, only attributes allowed by those groups can be used. - -As for groups, attributes can be selected during both the serialization and deserialization processes. - -.. _serializer_ignoring-attributes: - -Ignoring Attributes -------------------- - -All accessible attributes are included by default when serializing objects. -There are two options to ignore some of those attributes. - -Option 1: Using ``#[Ignore]`` Attribute -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. configuration-block:: - - .. code-block:: php-attributes - - namespace App\Model; - - use Symfony\Component\Serializer\Annotation\Ignore; - - class MyClass - { - public string $foo; - - #[Ignore] - public string $bar; - } - - .. code-block:: yaml - - App\Model\MyClass: - attributes: - bar: - ignore: true - - .. code-block:: xml - - - - - - - - -You can now ignore specific attributes during serialization:: - - use App\Model\MyClass; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $obj = new MyClass(); - $obj->foo = 'foo'; - $obj->bar = 'bar'; - - $normalizer = new ObjectNormalizer($classMetadataFactory); - $serializer = new Serializer([$normalizer]); - - $data = $serializer->normalize($obj); - // $data = ['foo' => 'foo']; - -Option 2: Using the Context -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Pass an array with the names of the attributes to ignore using the -``AbstractNormalizer::IGNORED_ATTRIBUTES`` key in the ``context`` of the -serializer method:: - - use Acme\Person; - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $person = new Person(); - $person->setName('foo'); - $person->setAge(99); - - $normalizer = new ObjectNormalizer(); - $encoder = new JsonEncoder(); - - $serializer = new Serializer([$normalizer], [$encoder]); - $serializer->serialize($person, 'json', [AbstractNormalizer::IGNORED_ATTRIBUTES => ['age']]); // Output: {"name":"foo"} - -.. _component-serializer-converting-property-names-when-serializing-and-deserializing: - -Converting Property Names when Serializing and Deserializing ------------------------------------------------------------- - -Sometimes serialized attributes must be named differently than properties -or getter/setter methods of PHP classes. - -The Serializer component provides a handy way to translate or map PHP field -names to serialized names: The Name Converter System. - -Given you have the following object:: - - class Company - { - public string $name; - public string $address; - } - -And in the serialized form, all attributes must be prefixed by ``org_`` like -the following:: - - {"org_name": "Acme Inc.", "org_address": "123 Main Street, Big City"} - -A custom name converter can handle such cases:: - - use Symfony\Component\Serializer\NameConverter\NameConverterInterface; - - class OrgPrefixNameConverter implements NameConverterInterface - { - public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string - { - return 'org_'.$propertyName; - } - - public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string - { - // removes 'org_' prefix - return str_starts_with($propertyName, 'org_') ? substr($propertyName, 4) : $propertyName; - } - } - -The custom name converter can be used by passing it as second parameter of any -class extending :class:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer`, -including :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` -and :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer`:: - - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $nameConverter = new OrgPrefixNameConverter(); - $normalizer = new ObjectNormalizer(null, $nameConverter); - - $serializer = new Serializer([$normalizer], [new JsonEncoder()]); - - $company = new Company(); - $company->name = 'Acme Inc.'; - $company->address = '123 Main Street, Big City'; - - $json = $serializer->serialize($company, 'json'); - // {"org_name": "Acme Inc.", "org_address": "123 Main Street, Big City"} - $companyCopy = $serializer->deserialize($json, Company::class, 'json'); - // Same data as $company - -.. _using-camelized-method-names-for-underscored-attributes: - -CamelCase to snake_case -~~~~~~~~~~~~~~~~~~~~~~~ - -In many formats, it's common to use underscores to separate words (also known -as snake_case). However, in Symfony applications is common to use CamelCase to -name properties (even though the `PSR-1 standard`_ doesn't recommend any -specific case for property names). - -Symfony provides a built-in name converter designed to transform between -snake_case and CamelCased styles during serialization and deserialization -processes:: - - use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - - $normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter()); - - class Person - { - public function __construct( - private string $firstName, - ) { - } - - public function getFirstName(): string - { - return $this->firstName; - } - } - - $kevin = new Person('Kévin'); - $normalizer->normalize($kevin); - // ['first_name' => 'Kévin']; - - $anne = $normalizer->denormalize(['first_name' => 'Anne'], 'Person'); - // Person object with firstName: 'Anne' - -.. _serializer_name-conversion: - -Configure name conversion using metadata -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When using this component inside a Symfony application and the class metadata -factory is enabled as explained in the :ref:`Attributes Groups section `, -this is already set up and you only need to provide the configuration. Otherwise:: - - // ... - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); - - $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory); - - $serializer = new Serializer( - [new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter)], - ['json' => new JsonEncoder()] - ); - -Now configure your name conversion mapping. Consider an application that -defines a ``Person`` entity with a ``firstName`` property: - -.. configuration-block:: - - .. code-block:: php-attributes - - namespace App\Entity; - - use Symfony\Component\Serializer\Annotation\SerializedName; - - class Person - { - public function __construct( - #[SerializedName('customer_name')] - private string $firstName, - ) { - } - - // ... - } - - .. code-block:: yaml - - App\Entity\Person: - attributes: - firstName: - serialized_name: customer_name - - .. code-block:: xml - - - - - - - - -This custom mapping is used to convert property names when serializing and -deserializing objects:: - - $serialized = $serializer->serialize(new Person('Kévin'), 'json'); - // {"customer_name": "Kévin"} - -.. _serializing-boolean-attributes: - -Handling Boolean Attributes And Values --------------------------------------- - -During Serialization -~~~~~~~~~~~~~~~~~~~~ - -If you are using isser methods (methods prefixed by ``is``, like -``App\Model\Person::isSportsperson()``), the Serializer component will -automatically detect and use it to serialize related attributes. - -The ``ObjectNormalizer`` also takes care of methods starting with ``has``, ``get``, -and ``can``. - -During Deserialization -~~~~~~~~~~~~~~~~~~~~~~ - -PHP considers many different values as true or false. For example, the -strings ``true``, ``1``, and ``yes`` are considered true, while -``false``, ``0``, and ``no`` are considered false. - -When deserializing, the Serializer component can take care of this -automatically. This can be done by using the ``AbstractNormalizer::FILTER_BOOL`` -context option:: - - use Acme\Person; - use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $normalizer = new ObjectNormalizer(); - $serializer = new Serializer([$normalizer]); - - $data = $serializer->denormalize(['sportsperson' => 'yes'], Person::class, context: [AbstractNormalizer::FILTER_BOOL => true]); - -This context makes the deserialization process behave like the -:phpfunction:`filter_var` function with the ``FILTER_VALIDATE_BOOL`` flag. - -.. versionadded:: 7.1 - - The ``AbstractNormalizer::FILTER_BOOL`` context option was introduced in Symfony 7.1. - -Using Callbacks to Serialize Properties with Object Instances -------------------------------------------------------------- - -When serializing, you can set a callback to format a specific object property:: - - use App\Model\Person; - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; - use Symfony\Component\Serializer\Serializer; - - $encoder = new JsonEncoder(); - - // all callback parameters are optional (you can omit the ones you don't use) - $dateCallback = function (object $attributeValue, object $object, string $attributeName, ?string $format = null, array $context = []): string { - return $attributeValue instanceof \DateTime ? $attributeValue->format(\DateTime::ATOM) : ''; - }; - - $defaultContext = [ - AbstractNormalizer::CALLBACKS => [ - 'createdAt' => $dateCallback, - ], - ]; - - $normalizer = new GetSetMethodNormalizer(null, null, null, null, null, $defaultContext); - - $serializer = new Serializer([$normalizer], [$encoder]); - - $person = new Person(); - $person->setName('cordoval'); - $person->setAge(34); - $person->setCreatedAt(new \DateTime('now')); - - $serializer->serialize($person, 'json'); - // Output: {"name":"cordoval", "age": 34, "createdAt": "2014-03-22T09:43:12-0500"} - -.. _component-serializer-normalizers: - -Normalizers ------------ - -Normalizers turn **objects** into **arrays** and vice versa. They implement -:class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface` for -normalizing (object to array) and -:class:`Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface` for -denormalizing (array to object). - -Normalizers are enabled in the serializer passing them as its first argument:: - - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $normalizers = [new ObjectNormalizer()]; - $serializer = new Serializer($normalizers, []); - -Built-in Normalizers -~~~~~~~~~~~~~~~~~~~~ - -The Serializer component provides several built-in normalizers: - -:class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer` - This normalizer leverages the :doc:`PropertyAccess Component ` - to read and write in the object. It means that it can access to properties - directly and through getters, setters, hassers, issers, canners, adders and removers. - It supports calling the constructor during the denormalization process. - - Objects are normalized to a map of property names and values (names are - generated by removing the ``get``, ``set``, ``has``, ``is``, ``can``, ``add`` or ``remove`` - prefix from the method name and transforming the first letter to lowercase; e.g. - ``getFirstName()`` -> ``firstName``). - - The ``ObjectNormalizer`` is the most powerful normalizer. It is configured by - default in Symfony applications with the Serializer component enabled. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` - This normalizer reads the content of the class by calling the "getters" - (public methods starting with "get"). It will denormalize data by calling - the constructor and the "setters" (public methods starting with "set"). - - Objects are normalized to a map of property names and values (names are - generated by removing the ``get`` prefix from the method name and transforming - the first letter to lowercase; e.g. ``getFirstName()`` -> ``firstName``). - -:class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer` - This normalizer directly reads and writes public properties as well as - **private and protected** properties (from both the class and all of its - parent classes) by using `PHP reflection`_. It supports calling the constructor - during the denormalization process. - - Objects are normalized to a map of property names to property values. - - If you prefer to only normalize certain properties (e.g. only public properties) - set the ``PropertyNormalizer::NORMALIZE_VISIBILITY`` context option and - combine the following values: ``PropertyNormalizer::NORMALIZE_PUBLIC``, - ``PropertyNormalizer::NORMALIZE_PROTECTED`` or ``PropertyNormalizer::NORMALIZE_PRIVATE``. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\JsonSerializableNormalizer` - This normalizer works with classes that implement :phpclass:`JsonSerializable`. - - It will call the :phpmethod:`JsonSerializable::jsonSerialize` method and - then further normalize the result. This means that nested - :phpclass:`JsonSerializable` classes will also be normalized. - - This normalizer is particularly helpful when you want to gradually migrate - from an existing codebase using simple :phpfunction:`json_encode` to the Symfony - Serializer by allowing you to mix which normalizers are used for which classes. - - Unlike with :phpfunction:`json_encode` circular references can be handled. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\DateTimeNormalizer` - This normalizer converts :phpclass:`DateTimeInterface` objects (e.g. - :phpclass:`DateTime` and :phpclass:`DateTimeImmutable`) into strings, - integers or floats. By default, it converts them to strings using the `RFC3339`_ format. - To convert the objects to integers or floats, set the serializer context option - ``DateTimeNormalizer::CAST_KEY`` to ``int`` or ``float``. - - .. versionadded:: 7.1 - - The ``DateTimeNormalizer::CAST_KEY`` context option was introduced in Symfony 7.1. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\DateTimeZoneNormalizer` - This normalizer converts :phpclass:`DateTimeZone` objects into strings that - represent the name of the timezone according to the `list of PHP timezones`_. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\DataUriNormalizer` - This normalizer converts :phpclass:`SplFileInfo` objects into a `data URI`_ - string (``data:...``) such that files can be embedded into serialized data. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\DateIntervalNormalizer` - This normalizer converts :phpclass:`DateInterval` objects into strings. - By default, it uses the ``P%yY%mM%dDT%hH%iM%sS`` format. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\BackedEnumNormalizer` - This normalizer converts a \BackedEnum objects into strings or integers. - - By default, an exception is thrown when data is not a valid backed enumeration. If you - want ``null`` instead, you can set the ``BackedEnumNormalizer::ALLOW_INVALID_VALUES`` option. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\FormErrorNormalizer` - This normalizer works with classes that implement - :class:`Symfony\\Component\\Form\\FormInterface`. - - It will get errors from the form and normalize them into a normalized array. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer` - This normalizer converts objects that implement - :class:`Symfony\\Component\\Validator\\ConstraintViolationListInterface` - into a list of errors according to the `RFC 7807`_ standard. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\ProblemNormalizer` - Normalizes errors according to the API Problem spec `RFC 7807`_. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\CustomNormalizer` - Normalizes a PHP object using an object that implements :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizableInterface`. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\UidNormalizer` - This normalizer converts objects that extend - :class:`Symfony\\Component\\Uid\\AbstractUid` into strings. - The default normalization format for objects that implement :class:`Symfony\\Component\\Uid\\Uuid` - is the `RFC 4122`_ format (example: ``d9e7a184-5d5b-11ea-a62a-3499710062d0``). - The default normalization format for objects that implement :class:`Symfony\\Component\\Uid\\Ulid` - is the Base 32 format (example: ``01E439TP9XJZ9RPFH3T1PYBCR8``). - You can change the string format by setting the serializer context option - ``UidNormalizer::NORMALIZATION_FORMAT_KEY`` to ``UidNormalizer::NORMALIZATION_FORMAT_BASE_58``, - ``UidNormalizer::NORMALIZATION_FORMAT_BASE_32`` or ``UidNormalizer::NORMALIZATION_FORMAT_RFC_4122``. - - Also it can denormalize ``uuid`` or ``ulid`` strings to :class:`Symfony\\Component\\Uid\\Uuid` - or :class:`Symfony\\Component\\Uid\\Ulid`. The format does not matter. - -:class:`Symfony\\Component\\Serializer\\Normalizer\\TranslatableNormalizer` - This normalizer converts objects that implement - :class:`Symfony\\Contracts\\Translation\\TranslatableInterface` into - translated strings, using the - :method:`Symfony\\Contracts\\Translation\\TranslatableInterface::trans` - method. You can define the locale to use to translate the object by - setting the ``TranslatableNormalizer::NORMALIZATION_LOCALE_KEY`` serializer - context option. - -.. note:: - - You can also create your own Normalizer to use another structure. Read more at - :doc:`/serializer/custom_normalizer`. - -Certain normalizers are enabled by default when using the Serializer component -in a Symfony application, additional ones can be enabled by tagging them with -:ref:`serializer.normalizer `. - -Here is an example of how to enable the built-in -:class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer`, a -faster alternative to the -:class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer`: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # ... - - get_set_method_normalizer: - class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer - tags: [serializer.normalizer] - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; - - return static function (ContainerConfigurator $container): void { - $container->services() - // ... - ->set('get_set_method_normalizer', GetSetMethodNormalizer::class) - ->tag('serializer.normalizer') - ; - }; - -.. _component-serializer-encoders: - -Encoders --------- - -Encoders turn **arrays** into **formats** and vice versa. They implement -:class:`Symfony\\Component\\Serializer\\Encoder\\EncoderInterface` -for encoding (array to format) and -:class:`Symfony\\Component\\Serializer\\Encoder\\DecoderInterface` for decoding -(format to array). - -You can add new encoders to a Serializer instance by using its second constructor argument:: - - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Encoder\XmlEncoder; - use Symfony\Component\Serializer\Serializer; - - $encoders = [new XmlEncoder(), new JsonEncoder()]; - $serializer = new Serializer([], $encoders); - -Built-in Encoders -~~~~~~~~~~~~~~~~~ - -The Serializer component provides several built-in encoders: - -:class:`Symfony\\Component\\Serializer\\Encoder\\JsonEncoder` - This class encodes and decodes data in `JSON`_. - -:class:`Symfony\\Component\\Serializer\\Encoder\\XmlEncoder` - This class encodes and decodes data in `XML`_. - -:class:`Symfony\\Component\\Serializer\\Encoder\\YamlEncoder` - This encoder encodes and decodes data in `YAML`_. This encoder requires the - :doc:`Yaml Component `. - -:class:`Symfony\\Component\\Serializer\\Encoder\\CsvEncoder` - This encoder encodes and decodes data in `CSV`_. - -.. note:: - - You can also create your own Encoder to use another structure. Read more at - :doc:`/serializer/custom_encoders`. - -All these encoders are enabled by default when using the Serializer component -in a Symfony application. - -The ``JsonEncoder`` -~~~~~~~~~~~~~~~~~~~ - -The ``JsonEncoder`` encodes to and decodes from JSON strings, based on the PHP -:phpfunction:`json_encode` and :phpfunction:`json_decode` functions. It can be -useful to modify how these functions operate in certain instances by providing -options such as ``JSON_PRESERVE_ZERO_FRACTION``. You can use the serialization -context to pass in these options using the key ``json_encode_options`` or -``json_decode_options`` respectively:: - - $this->serializer->serialize($data, 'json', ['json_encode_options' => \JSON_PRESERVE_ZERO_FRACTION]); - -These are the options available: - -=============================== =========================================================================================================== ================================ -Option Description Default -=============================== ========================================================================================================== ================================ -``json_decode_associative`` If set to true returns the result as an array, returns a nested ``stdClass`` hierarchy otherwise. ``false`` -``json_decode_detailed_errors`` If set to true, exceptions thrown on parsing of JSON are more specific. Requires `seld/jsonlint`_ package. ``false`` -``json_decode_options`` `$flags`_ passed to :phpfunction:`json_decode` function. ``0`` -``json_encode_options`` `$flags`_ passed to :phpfunction:`json_encode` function. ``\JSON_PRESERVE_ZERO_FRACTION`` -``json_decode_recursion_depth`` Sets maximum recursion depth. ``512`` -=============================== ========================================================================================================== ================================ - -The ``CsvEncoder`` -~~~~~~~~~~~~~~~~~~ - -The ``CsvEncoder`` encodes to and decodes from CSV. - -The ``CsvEncoder`` Context Options -.................................. - -The ``encode()`` method defines a third optional parameter called ``context`` -which defines the configuration options for the CsvEncoder an associative array:: - - $csvEncoder->encode($array, 'csv', $context); - -These are the options available: - -======================= ============================================================= ========================== -Option Description Default -======================= ============================================================= ========================== -``csv_delimiter`` Sets the field delimiter separating values (one ``,`` - character only) -``csv_enclosure`` Sets the field enclosure (one character only) ``"`` -``csv_end_of_line`` Sets the character(s) used to mark the end of each ``\n`` - line in the CSV file -``csv_escape_char`` Deprecated. Sets the escape character (at most one character) empty string -``csv_key_separator`` Sets the separator for array's keys during its ``.`` - flattening -``csv_headers`` Sets the order of the header and data columns - E.g.: if ``$data = ['c' => 3, 'a' => 1, 'b' => 2]`` - and ``$options = ['csv_headers' => ['a', 'b', 'c']]`` - then ``serialize($data, 'csv', $options)`` returns - ``a,b,c\n1,2,3`` ``[]``, inferred from input data's keys -``csv_escape_formulas`` Escapes fields containing formulas by prepending them ``false`` - with a ``\t`` character -``as_collection`` Always returns results as a collection, even if only ``true`` - one line is decoded. -``no_headers`` Setting to ``false`` will use first row as headers. ``false`` - ``true`` generate numeric headers. -``output_utf8_bom`` Outputs special `UTF-8 BOM`_ along with encoded data ``false`` -======================= ============================================================= ========================== - -.. deprecated:: 7.2 - - The ``csv_escape_char`` option and the ``CsvEncoder::ESCAPE_CHAR_KEY`` - constant were deprecated in Symfony 7.2. - -The ``XmlEncoder`` -~~~~~~~~~~~~~~~~~~ - -This encoder transforms arrays into XML and vice versa. - -For example, take an object normalized as following:: - - ['foo' => [1, 2], 'bar' => true]; - -The ``XmlEncoder`` will encode this object like that: - -.. code-block:: xml - - - - 1 - 2 - 1 - - -The special ``#`` key can be used to define the data of a node:: - - ['foo' => ['@bar' => 'value', '#' => 'baz']]; - - // is encoded as follows: - // - // - // - // baz - // - // - -Furthermore, keys beginning with ``@`` will be considered attributes, and -the key ``#comment`` can be used for encoding XML comments:: - - $encoder = new XmlEncoder(); - $encoder->encode([ - 'foo' => ['@bar' => 'value'], - 'qux' => ['#comment' => 'A comment'], - ], 'xml'); - // will return: - // - // - // - // - // - -You can pass the context key ``as_collection`` in order to have the results -always as a collection. - -.. note:: - - You may need to add some attributes on the root node:: - - $encoder = new XmlEncoder(); - $encoder->encode([ - '@attribute1' => 'foo', - '@attribute2' => 'bar', - '#' => ['foo' => ['@bar' => 'value', '#' => 'baz']] - ], 'xml'); - - // will return: - // - // - // baz - // - -.. tip:: - - XML comments are ignored by default when decoding contents, but this - behavior can be changed with the optional context key ``XmlEncoder::DECODER_IGNORED_NODE_TYPES``. - - Data with ``#comment`` keys are encoded to XML comments by default. This can be - changed by adding the ``\XML_COMMENT_NODE`` option to the ``XmlEncoder::ENCODER_IGNORED_NODE_TYPES`` - key of the ``$defaultContext`` of the ``XmlEncoder`` constructor or - directly to the ``$context`` argument of the ``encode()`` method:: - - $xmlEncoder->encode($array, 'xml', [XmlEncoder::ENCODER_IGNORED_NODE_TYPES => [\XML_COMMENT_NODE]]); - -The ``XmlEncoder`` Context Options -.................................. - -The ``encode()`` method defines a third optional parameter called ``context`` -which defines the configuration options for the XmlEncoder an associative array:: - - $xmlEncoder->encode($array, 'xml', $context); - -These are the options available: - -============================== ================================================= ========================== -Option Description Default -============================== ================================================= ========================== -``xml_format_output`` If set to true, formats the generated XML with ``false`` - line breaks and indentation -``xml_version`` Sets the XML version attribute ``1.0`` -``xml_encoding`` Sets the XML encoding attribute ``utf-8`` -``xml_standalone`` Adds standalone attribute in the generated XML ``true`` -``xml_type_cast_attributes`` This provides the ability to forget the attribute ``true`` - type casting -``xml_root_node_name`` Sets the root node name ``response`` -``as_collection`` Always returns results as a collection, even if ``false`` - only one line is decoded -``decoder_ignored_node_types`` Array of node types (`DOM XML_* constants`_) ``[\XML_PI_NODE, \XML_COMMENT_NODE]`` - to be ignored while decoding -``encoder_ignored_node_types`` Array of node types (`DOM XML_* constants`_) ``[]`` - to be ignored while encoding -``load_options`` XML loading `options with libxml`_ ``\LIBXML_NONET | \LIBXML_NOBLANKS`` -``save_options`` XML saving `options with libxml`_ ``0`` -``remove_empty_tags`` If set to true, removes all empty tags in the ``false`` - generated XML -``cdata_wrapping`` If set to false, will not wrap any value ``true`` - matching the ``cdata_wrapping_pattern`` regex in - `a CDATA section`_ like following: - ```` -``cdata_wrapping_pattern`` A regular expression pattern to determine if a ``/[<>&]/`` - value should be wrapped in a CDATA section -============================== ================================================= ========================== - -.. versionadded:: 7.1 - - The ``cdata_wrapping_pattern`` option was introduced in Symfony 7.1. - -Example with custom ``context``:: - - use Symfony\Component\Serializer\Encoder\XmlEncoder; - - // create encoder with specified options as new default settings - $xmlEncoder = new XmlEncoder(['xml_format_output' => true]); - - $data = [ - 'id' => 'IDHNQIItNyQ', - 'date' => '2019-10-24', - ]; - - // encode with default context - $xmlEncoder->encode($data, 'xml'); - // outputs: - // - // - // IDHNQIItNyQ - // 2019-10-24 - // - - // encode with modified context - $xmlEncoder->encode($data, 'xml', [ - 'xml_root_node_name' => 'track', - 'encoder_ignored_node_types' => [ - \XML_PI_NODE, // removes XML declaration (the leading xml tag) - ], - ]); - // outputs: - // - // IDHNQIItNyQ - // 2019-10-24 - // - -The ``YamlEncoder`` -~~~~~~~~~~~~~~~~~~~ - -This encoder requires the :doc:`Yaml Component ` and -transforms from and to Yaml. - -The ``YamlEncoder`` Context Options -................................... - -The ``encode()`` method, like other encoder, uses ``context`` to set -configuration options for the YamlEncoder an associative array:: - - $yamlEncoder->encode($array, 'yaml', $context); - -These are the options available: - -=============== ======================================================== ========================== -Option Description Default -=============== ======================================================== ========================== -``yaml_inline`` The level where you switch to inline YAML ``0`` -``yaml_indent`` The level of indentation (used internally) ``0`` -``yaml_flags`` A bit field of ``Yaml::DUMP_*`` / ``PARSE_*`` constants ``0`` - to customize the encoding / decoding YAML string -=============== ======================================================== ========================== - -.. _component-serializer-context-builders: - -Context Builders ----------------- - -Instead of passing plain PHP arrays to the :ref:`serialization context `, -you can use "context builders" to define the context using a fluent interface:: - - use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder; - use Symfony\Component\Serializer\Context\Normalizer\ObjectNormalizerContextBuilder; - - $initialContext = [ - 'custom_key' => 'custom_value', - ]; - - $contextBuilder = (new ObjectNormalizerContextBuilder()) - ->withContext($initialContext) - ->withGroups(['group1', 'group2']); - - $contextBuilder = (new CsvEncoderContextBuilder()) - ->withContext($contextBuilder) - ->withDelimiter(';'); - - $serializer->serialize($something, 'csv', $contextBuilder->toArray()); - -.. note:: - - The Serializer component provides a context builder - for each :ref:`normalizer ` - and :ref:`encoder `. - - You can also :doc:`create custom context builders ` - to deal with your context values. - -.. deprecated:: 7.2 - - The ``CsvEncoderContextBuilder::withEscapeChar()`` method was deprecated - in Symfony 7.2. - -Skipping ``null`` Values ------------------------- - -By default, the Serializer will preserve properties containing a ``null`` value. -You can change this behavior by setting the ``AbstractObjectNormalizer::SKIP_NULL_VALUES`` context option -to ``true``:: - - $dummy = new class { - public ?string $foo = null; - public string $bar = 'notNull'; - }; - - $normalizer = new ObjectNormalizer(); - $result = $normalizer->normalize($dummy, 'json', [AbstractObjectNormalizer::SKIP_NULL_VALUES => true]); - // ['bar' => 'notNull'] - -Require all Properties ----------------------- - -By default, the Serializer will add ``null`` to nullable properties when the parameters for those are not provided. -You can change this behavior by setting the ``AbstractNormalizer::REQUIRE_ALL_PROPERTIES`` context option -to ``true``:: - - class Dummy - { - public function __construct( - public string $foo, - public ?string $bar, - ) { - } - } - - $data = ['foo' => 'notNull']; - - $normalizer = new ObjectNormalizer(); - $result = $normalizer->denormalize($data, Dummy::class, 'json', [AbstractNormalizer::REQUIRE_ALL_PROPERTIES => true]); - // throws Symfony\Component\Serializer\Exception\MissingConstructorArgumentException - -Skipping Uninitialized Properties ---------------------------------- - -In PHP, typed properties have an ``uninitialized`` state which is different -from the default ``null`` of untyped properties. When you try to access a typed -property before giving it an explicit value, you get an error. - -To avoid the Serializer throwing an error when serializing or normalizing an -object with uninitialized properties, by default the object normalizer catches -these errors and ignores such properties. - -You can disable this behavior by setting the ``AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES`` -context option to ``false``:: - - class Dummy { - public string $foo = 'initialized'; - public string $bar; // uninitialized - } - - $normalizer = new ObjectNormalizer(); - $result = $normalizer->normalize(new Dummy(), 'json', [AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES => false]); - // throws Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException as normalizer cannot read uninitialized properties - -.. note:: - - Calling ``PropertyNormalizer::normalize`` or ``GetSetMethodNormalizer::normalize`` - with ``AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES`` context option set - to ``false`` will throw an ``\Error`` instance if the given object has uninitialized - properties as the normalizer cannot read them (directly or via getter/isser methods). - -.. _component-serializer-handling-circular-references: - -Collecting Type Errors While Denormalizing ------------------------------------------- - -When denormalizing a payload to an object with typed properties, you'll get an -exception if the payload contains properties that don't have the same type as -the object. - -In those situations, use the ``COLLECT_DENORMALIZATION_ERRORS`` option to -collect all exceptions at once, and to get the object partially denormalized:: - - try { - $dto = $serializer->deserialize($request->getContent(), MyDto::class, 'json', [ - DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, - ]); - } catch (PartialDenormalizationException $e) { - $violations = new ConstraintViolationList(); - /** @var NotNormalizableValueException $exception */ - foreach ($e->getErrors() as $exception) { - $message = sprintf('The type must be one of "%s" ("%s" given).', implode(', ', $exception->getExpectedTypes()), $exception->getCurrentType()); - $parameters = []; - if ($exception->canUseMessageForUser()) { - $parameters['hint'] = $exception->getMessage(); - } - $violations->add(new ConstraintViolation($message, '', $parameters, null, $exception->getPath(), null)); - } - - return $this->json($violations, 400); - } - -Handling Circular References ----------------------------- - -Circular references are common when dealing with entity relations:: - - class Organization - { - private string $name; - private array $members; - - public function setName($name): void - { - $this->name = $name; - } - - public function getName(): string - { - return $this->name; - } - - public function setMembers(array $members): void - { - $this->members = $members; - } - - public function getMembers(): array - { - return $this->members; - } - } - - class Member - { - private string $name; - private Organization $organization; - - public function setName(string $name): void - { - $this->name = $name; - } - - public function getName(): string - { - return $this->name; - } - - public function setOrganization(Organization $organization): void - { - $this->organization = $organization; - } - - public function getOrganization(): Organization - { - return $this->organization; - } - } - -To avoid infinite loops, :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` -or :class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer` -throw a :class:`Symfony\\Component\\Serializer\\Exception\\CircularReferenceException` -when such a case is encountered:: - - $member = new Member(); - $member->setName('Kévin'); - - $organization = new Organization(); - $organization->setName('Les-Tilleuls.coop'); - $organization->setMembers([$member]); - - $member->setOrganization($organization); - - echo $serializer->serialize($organization, 'json'); // Throws a CircularReferenceException - -The key ``circular_reference_limit`` in the default context sets the number of -times it will serialize the same object before considering it a circular -reference. The default value is ``1``. - -Instead of throwing an exception, circular references can also be handled -by custom callables. This is especially useful when serializing entities -having unique identifiers:: - - $encoder = new JsonEncoder(); - $defaultContext = [ - AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function (object $object, ?string $format, array $context): string { - return $object->getName(); - }, - ]; - $normalizer = new ObjectNormalizer(null, null, null, null, null, null, $defaultContext); - - $serializer = new Serializer([$normalizer], [$encoder]); - var_dump($serializer->serialize($org, 'json')); - // {"name":"Les-Tilleuls.coop","members":[{"name":"K\u00e9vin", organization: "Les-Tilleuls.coop"}]} - -.. _serializer_handling-serialization-depth: - -Handling Serialization Depth ----------------------------- - -The Serializer component is able to detect and limit the serialization depth. -It is especially useful when serializing large trees. Assume the following data -structure:: - - namespace Acme; - - class MyObj - { - public string $foo; - - /** - * @var self - */ - public MyObj $child; - } - - $level1 = new MyObj(); - $level1->foo = 'level1'; - - $level2 = new MyObj(); - $level2->foo = 'level2'; - $level1->child = $level2; - - $level3 = new MyObj(); - $level3->foo = 'level3'; - $level2->child = $level3; - -The serializer can be configured to set a maximum depth for a given property. -Here, we set it to 2 for the ``$child`` property: - -.. configuration-block:: - - .. code-block:: php-attributes - - namespace Acme; - - use Symfony\Component\Serializer\Annotation\MaxDepth; - - class MyObj - { - #[MaxDepth(2)] - public MyObj $child; - - // ... - } - - .. code-block:: yaml - - Acme\MyObj: - attributes: - child: - max_depth: 2 - - .. code-block:: xml - - - - - - - - -The metadata loader corresponding to the chosen format must be configured in -order to use this feature. It is done automatically when using the Serializer component -in a Symfony application. When using the standalone component, refer to -:ref:`the groups documentation ` to -learn how to do that. - -The check is only done if the ``AbstractObjectNormalizer::ENABLE_MAX_DEPTH`` key of the serializer context -is set to ``true``. In the following example, the third level is not serialized -because it is deeper than the configured maximum depth of 2:: - - $result = $serializer->normalize($level1, null, [AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true]); - /* - $result = [ - 'foo' => 'level1', - 'child' => [ - 'foo' => 'level2', - 'child' => [ - 'child' => null, - ], - ], - ]; - */ - -Instead of throwing an exception, a custom callable can be executed when the -maximum depth is reached. This is especially useful when serializing entities -having unique identifiers:: - - use Symfony\Component\Serializer\Annotation\MaxDepth; - use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; - use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; - use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - class Foo - { - public int $id; - - #[MaxDepth(1)] - public MyObj $child; - } - - $level1 = new Foo(); - $level1->id = 1; - - $level2 = new Foo(); - $level2->id = 2; - $level1->child = $level2; - - $level3 = new Foo(); - $level3->id = 3; - $level2->child = $level3; - - $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); - - // all callback parameters are optional (you can omit the ones you don't use) - $maxDepthHandler = function (object $innerObject, object $outerObject, string $attributeName, ?string $format = null, array $context = []): string { - return '/foos/'.$innerObject->id; - }; - - $defaultContext = [ - AbstractObjectNormalizer::MAX_DEPTH_HANDLER => $maxDepthHandler, - ]; - $normalizer = new ObjectNormalizer($classMetadataFactory, null, null, null, null, null, $defaultContext); - - $serializer = new Serializer([$normalizer]); - - $result = $serializer->normalize($level1, null, [AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true]); - /* - $result = [ - 'id' => 1, - 'child' => [ - 'id' => 2, - 'child' => '/foos/3', - ], - ]; - */ - -Handling Arrays ---------------- - -The Serializer component is capable of handling arrays of objects as well. -Serializing arrays works just like serializing a single object:: - - use Acme\Person; - - $person1 = new Person(); - $person1->setName('foo'); - $person1->setAge(99); - $person1->setSportsman(false); - - $person2 = new Person(); - $person2->setName('bar'); - $person2->setAge(33); - $person2->setSportsman(true); - - $persons = [$person1, $person2]; - $data = $serializer->serialize($persons, 'json'); - - // $data contains [{"name":"foo","age":99,"sportsman":false},{"name":"bar","age":33,"sportsman":true}] - -If you want to deserialize such a structure, you need to add the -:class:`Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer` -to the set of normalizers. By appending ``[]`` to the type parameter of the -:method:`Symfony\\Component\\Serializer\\Serializer::deserialize` method, -you indicate that you're expecting an array instead of a single object:: - - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; - use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; - use Symfony\Component\Serializer\Serializer; - - $serializer = new Serializer( - [new GetSetMethodNormalizer(), new ArrayDenormalizer()], - [new JsonEncoder()] - ); - - $data = ...; // The serialized data from the previous example - $persons = $serializer->deserialize($data, 'Acme\Person[]', 'json'); - -Handling Constructor Arguments ------------------------------- - -If the class constructor defines arguments, as usually happens with -`Value Objects`_, the serializer won't be able to create the object if some -arguments are missing. In those cases, use the ``default_constructor_arguments`` -context option:: - - use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - class MyObj - { - public function __construct( - private string $foo, - private string $bar, - ) { - } - } - - $normalizer = new ObjectNormalizer(); - $serializer = new Serializer([$normalizer]); - - $data = $serializer->denormalize( - ['foo' => 'Hello'], - 'MyObj', - null, - [AbstractNormalizer::DEFAULT_CONSTRUCTOR_ARGUMENTS => [ - 'MyObj' => ['foo' => '', 'bar' => ''], - ]] - ); - // $data = new MyObj('Hello', ''); - -Recursive Denormalization and Type Safety ------------------------------------------ - -The Serializer component can use the :doc:`PropertyInfo Component ` to denormalize -complex types (objects). The type of the class' property will be guessed using the provided -extractor and used to recursively denormalize the inner data. - -When using this component in a Symfony application, all normalizers are automatically configured to use the registered extractors. -When using the component standalone, an implementation of :class:`Symfony\\Component\\PropertyInfo\\PropertyTypeExtractorInterface`, -(usually an instance of :class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor`) must be passed as the 4th -parameter of the ``ObjectNormalizer``:: - - namespace Acme; - - use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; - use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - class ObjectOuter - { - private ObjectInner $inner; - private \DateTimeInterface $date; - - public function getInner(): ObjectInner - { - return $this->inner; - } - - public function setInner(ObjectInner $inner): void - { - $this->inner = $inner; - } - - public function getDate(): \DateTimeInterface - { - return $this->date; - } - - public function setDate(\DateTimeInterface $date): void - { - $this->date = $date; - } - } - - class ObjectInner - { - public string $foo; - public string $bar; - } - - $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); - $serializer = new Serializer([new DateTimeNormalizer(), $normalizer]); - - $obj = $serializer->denormalize( - ['inner' => ['foo' => 'foo', 'bar' => 'bar'], 'date' => '1988/01/21'], - 'Acme\ObjectOuter' - ); - - dump($obj->getInner()->foo); // 'foo' - dump($obj->getInner()->bar); // 'bar' - dump($obj->getDate()->format('Y-m-d')); // '1988-01-21' - -When a ``PropertyTypeExtractor`` is available, the normalizer will also check that the data to denormalize -matches the type of the property (even for primitive types). For instance, if a ``string`` is provided, but -the type of the property is ``int``, an :class:`Symfony\\Component\\Serializer\\Exception\\UnexpectedValueException` -will be thrown. The type enforcement of the properties can be disabled by setting -the serializer context option ``ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT`` -to ``true``. - -.. _serializer_interfaces-and-abstract-classes: - -Serializing Interfaces and Abstract Classes -------------------------------------------- - -When dealing with objects that are fairly similar or share properties, you may -use interfaces or abstract classes. The Serializer component allows you to -serialize and deserialize these objects using a *"discriminator class mapping"*. - -The discriminator is the field (in the serialized string) used to differentiate -between the possible objects. In practice, when using the Serializer component, -pass a :class:`Symfony\\Component\\Serializer\\Mapping\\ClassDiscriminatorResolverInterface` -implementation to the :class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer`. - -The Serializer component provides an implementation of ``ClassDiscriminatorResolverInterface`` -called :class:`Symfony\\Component\\Serializer\\Mapping\\ClassDiscriminatorFromClassMetadata` -which uses the class metadata factory and a mapping configuration to serialize -and deserialize objects of the correct class. - -When using this component inside a Symfony application and the class metadata factory is enabled -as explained in the :ref:`Attributes Groups section `, -this is already set up and you only need to provide the configuration. Otherwise:: - - // ... - use Symfony\Component\Serializer\Encoder\JsonEncoder; - use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata; - use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping; - use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - use Symfony\Component\Serializer\Serializer; - - $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); - - $discriminator = new ClassDiscriminatorFromClassMetadata($classMetadataFactory); - - $serializer = new Serializer( - [new ObjectNormalizer($classMetadataFactory, null, null, null, $discriminator)], - ['json' => new JsonEncoder()] - ); - -Now configure your discriminator class mapping. Consider an application that -defines an abstract ``CodeRepository`` class extended by ``GitHubCodeRepository`` -and ``BitBucketCodeRepository`` classes: - -.. configuration-block:: - - .. code-block:: php-attributes - - namespace App; - - use App\BitBucketCodeRepository; - use App\GitHubCodeRepository; - use Symfony\Component\Serializer\Annotation\DiscriminatorMap; - - #[DiscriminatorMap(typeProperty: 'type', mapping: [ - 'github' => GitHubCodeRepository::class, - 'bitbucket' => BitBucketCodeRepository::class, - ])] - abstract class CodeRepository - { - // ... - } - - .. code-block:: yaml - - App\CodeRepository: - discriminator_map: - type_property: type - mapping: - github: 'App\GitHubCodeRepository' - bitbucket: 'App\BitBucketCodeRepository' - - .. code-block:: xml - - - - - - - - - - - -.. note:: - - The values of the ``mapping`` array option must be strings. - Otherwise, they will be cast into strings automatically. - -Once configured, the serializer uses the mapping to pick the correct class:: - - $serialized = $serializer->serialize(new GitHubCodeRepository(), 'json'); - // {"type": "github"} - - $repository = $serializer->deserialize($serialized, CodeRepository::class, 'json'); - // instanceof GitHubCodeRepository - -Learn more ----------- - -.. toctree:: - :maxdepth: 1 - :glob: - - /serializer - -.. seealso:: - - Normalizers for the Symfony Serializer Component supporting popular web API formats - (JSON-LD, GraphQL, OpenAPI, HAL, JSON:API) are available as part of the `API Platform`_ project. - -.. seealso:: - - A popular alternative to the Symfony Serializer component is the third-party - library, `JMS serializer`_ (versions before ``v1.12.0`` were released under - the Apache license, so incompatible with GPLv2 projects). - -.. _`PSR-1 standard`: https://www.php-fig.org/psr/psr-1/ -.. _`JMS serializer`: https://github.com/schmittjoh/serializer -.. _RFC3339: https://tools.ietf.org/html/rfc3339#section-5.8 -.. _`options with libxml`: https://www.php.net/manual/en/libxml.constants.php -.. _`DOM XML_* constants`: https://www.php.net/manual/en/dom.constants.php -.. _JSON: https://www.json.org/json-en.html -.. _XML: https://www.w3.org/XML/ -.. _YAML: https://yaml.org/ -.. _CSV: https://tools.ietf.org/html/rfc4180 -.. _`RFC 7807`: https://tools.ietf.org/html/rfc7807 -.. _`UTF-8 BOM`: https://en.wikipedia.org/wiki/Byte_order_mark -.. _`Value Objects`: https://en.wikipedia.org/wiki/Value_object -.. _`API Platform`: https://api-platform.com -.. _`list of PHP timezones`: https://www.php.net/manual/en/timezones.php -.. _`RFC 4122`: https://tools.ietf.org/html/rfc4122 -.. _`PHP reflection`: https://php.net/manual/en/book.reflection.php -.. _`data URI`: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs -.. _seld/jsonlint: https://github.com/Seldaek/jsonlint -.. _$flags: https://www.php.net/manual/en/json.constants.php -.. _`a CDATA section`: https://en.wikipedia.org/wiki/CDATA diff --git a/components/type_info.rst b/components/type_info.rst index 30ae11aa222..47fe9dfd9ba 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -11,11 +11,6 @@ This component provides: * A way to get types from PHP elements such as properties, method arguments, return types, and raw strings. -.. caution:: - - This component is :doc:`experimental ` and - could be changed at any time without prior notice. - Installation ------------ @@ -45,12 +40,24 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: // Many others are available and can be // found in Symfony\Component\TypeInfo\TypeFactoryTrait -The second way of using the component is to use ``TypeInfo`` to resolve a type -based on reflection or a simple string:: +Resolvers +~~~~~~~~~ + +The second way to use the component is by using ``TypeInfo`` to resolve a type +based on reflection or a simple string. This approach is designed for libraries +that need a simple way to describe a class or anything with a type:: use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; + class Dummy + { + public function __construct( + public int $id, + ) { + } + } + // Instantiate a new resolver $typeResolver = TypeResolver::create(); @@ -63,12 +70,6 @@ based on reflection or a simple string:: // Type instances have several helper methods - // returns the main type (e.g. in this example it returns an "array" Type instance); - // for nullable types (e.g. string|null) it returns the non-null type (e.g. string) - // and for compound types (e.g. int|string) it throws an exception because both types - // can be considered the main one, so there's no way to pick one - $baseType = $type->getBaseType(); - // for collections, it returns the type of the item used as the key; // in this example, the collection is a list, so it returns an "int" Type instance $keyType = $type->getCollectionKeyType(); @@ -81,6 +82,111 @@ Each of these calls will return you a ``Type`` instance that corresponds to the static method used. You can also resolve types from a string (as shown in the ``bool`` parameter of the previous example) -.. note:: +PHPDoc Parsing +~~~~~~~~~~~~~~ + +In many cases, you may not have cleanly typed properties or may need more precise +type definitions provided by advanced PHPDoc. To achieve this, you can use a string +resolver based on the PHPDoc annotations. + +First, run the command ``composer require phpstan/phpdoc-parser`` to install the +PHP package required for string resolving. Then, follow these steps:: + + use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; + + class Dummy + { + public function __construct( + public int $id, + /** @var string[] $tags */ + public array $tags, + ) { + } + } + + $typeResolver = TypeResolver::create(); + $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type + $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns a collection with "int" as key and "string" as values Type + +Advanced Usages +~~~~~~~~~~~~~~~ + +The TypeInfo component provides various methods to manipulate and check types, +depending on your needs. + +**Identify** a type:: + + // define a simple integer type + $type = Type::int(); + // check if the type matches a specific identifier + $type->isIdentifiedBy(TypeIdentifier::INT); // true + $type->isIdentifiedBy(TypeIdentifier::STRING); // false + + // define a union type (equivalent to PHP's int|string) + $type = Type::union(Type::string(), Type::int()); + // now the second check is true because the union type contains the string type + $type->isIdentifiedBy(TypeIdentifier::INT); // true + $type->isIdentifiedBy(TypeIdentifier::STRING); // true + + class DummyParent {} + class Dummy extends DummyParent implements DummyInterface {} + + // define an object type + $type = Type::object(Dummy::class); + + // check if the type is an object or matches a specific class + $type->isIdentifiedBy(TypeIdentifier::OBJECT); // true + $type->isIdentifiedBy(Dummy::class); // true + // check if it inherits/implements something + $type->isIdentifiedBy(DummyParent::class); // true + $type->isIdentifiedBy(DummyInterface::class); // true + +Checking if a type **accepts a value**:: + + $type = Type::int(); + // check if the type accepts a given value + $type->accepts(123); // true + $type->accepts('z'); // false + + $type = Type::union(Type::string(), Type::int()); + // now the second check is true because the union type accepts either an int or a string value + $type->accepts(123); // true + $type->accepts('z'); // true + +.. versionadded:: 7.3 + + The :method:`Symfony\\Component\\TypeInfo\\Type::accepts` + method was introduced in Symfony 7.3. + +Using callables for **complex checks**:: + + class Foo + { + private int $integer; + private string $string; + private ?float $float; + } + + $reflClass = new \ReflectionClass(Foo::class); + + $resolver = TypeResolver::create(); + $integerType = $resolver->resolve($reflClass->getProperty('integer')); + $stringType = $resolver->resolve($reflClass->getProperty('string')); + $floatType = $resolver->resolve($reflClass->getProperty('float')); + + // define a callable to validate non-nullable number types + $isNonNullableNumber = function (Type $type): bool { + if ($type->isNullable()) { + return false; + } + + if ($type->isIdentifiedBy(TypeIdentifier::INT) || $type->isIdentifiedBy(TypeIdentifier::FLOAT)) { + return true; + } + + return false; + }; - To support raw string resolving, you need to install ``phpstan/phpdoc-parser`` package. + $integerType->isSatisfiedBy($isNonNullableNumber); // true + $stringType->isSatisfiedBy($isNonNullableNumber); // false + $floatType->isSatisfiedBy($isNonNullableNumber); // false diff --git a/components/uid.rst b/components/uid.rst index 73974ef8732..6c92fff0af9 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -386,7 +386,7 @@ entity primary keys:: // ... } -.. caution:: +.. warning:: Using UUIDs as primary keys is usually not recommended for performance reasons: indexes are slower and take more space (because UUIDs in binary format take @@ -574,7 +574,7 @@ entity primary keys:: // ... } -.. caution:: +.. warning:: Using ULIDs as primary keys is usually not recommended for performance reasons. Although ULIDs don't suffer from index fragmentation issues (because the values diff --git a/components/validator/resources.rst b/components/validator/resources.rst index c1474c1710d..5b1448dfba1 100644 --- a/components/validator/resources.rst +++ b/components/validator/resources.rst @@ -171,7 +171,7 @@ You can set this custom implementation using ->setMetadataFactory(new CustomMetadataFactory(...)) ->getValidator(); -.. caution:: +.. warning:: Since you are using a custom metadata factory, you can't configure loaders and caches using the ``add*Mapping()`` methods anymore. You now have to diff --git a/components/yaml.rst b/components/yaml.rst index 30f715a7a24..58436adffc2 100644 --- a/components/yaml.rst +++ b/components/yaml.rst @@ -428,6 +428,16 @@ you can dump them as ``~`` with the ``DUMP_NULL_AS_TILDE`` flag:: $dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_TILDE); // foo: ~ +Another valid representation of the ``null`` value is an empty string. You can +use the ``DUMP_NULL_AS_EMPTY`` flag to dump null values as empty strings:: + + $dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_EMPTY); + // foo: + +.. versionadded:: 7.3 + + The ``DUMP_NULL_AS_EMPTY`` flag was introduced in Symfony 7.3. + Dumping Numeric Keys as Strings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/configuration.rst b/configuration.rst index 51ad9368098..35bc2fb7eec 100644 --- a/configuration.rst +++ b/configuration.rst @@ -267,7 +267,7 @@ reusable configuration value. By convention, parameters are defined under the // ... -.. caution:: +.. warning:: By default and when using XML configuration, the values between ```` tags are not trimmed. This means that the value of the following parameter will be @@ -379,7 +379,7 @@ a new ``locale`` parameter is added to the ``config/services.yaml`` file). By convention, parameters whose names start with a dot ``.`` (for example, ``.mailer.transport``), are available only during the container compilation. - They are useful when working with :ref:`Compiler Passes ` + They are useful when working with :doc:`Compiler Passes ` to declare some temporary parameters that won't be available later in the application. Configuration parameters are usually validation-free, but you can ensure that @@ -809,7 +809,7 @@ Use environment variables in values by prefixing variables with ``$``: DB_USER=root DB_PASS=${DB_USER}pass # include the user as a password prefix -.. caution:: +.. warning:: The order is important when some env var depends on the value of other env vars. In the above example, ``DB_PASS`` must be defined after ``DB_USER``. @@ -830,7 +830,7 @@ Embed commands via ``$()`` (not supported on Windows): START_TIME=$(date) -.. caution:: +.. warning:: Using ``$()`` might not work depending on your shell. diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index baf4037d05a..2e82104db66 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -687,7 +687,7 @@ Symfony provides the following env var processors: ], ]); - .. caution:: + .. warning:: In order to ease extraction of the resource from the URL, the leading ``/`` is trimmed from the ``path`` component. diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index c9739679f69..62e8c2d4128 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -16,7 +16,7 @@ via Composer: .. code-block:: terminal - $ composer symfony/framework-bundle symfony/runtime + $ composer require symfony/framework-bundle symfony/runtime Next, create an ``index.php`` file that defines the kernel class and runs it: diff --git a/configuration/multiple_kernels.rst b/configuration/multiple_kernels.rst index 512ea57f24d..ec8742213b5 100644 --- a/configuration/multiple_kernels.rst +++ b/configuration/multiple_kernels.rst @@ -229,7 +229,7 @@ but it should typically be added to your web server configuration. # .env APP_ID=api -.. caution:: +.. warning:: The value of this variable must match the application directory within ``apps/`` as it is used in the Kernel to load the specific application diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index d17b67aedba..e5dff35b6d0 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -111,7 +111,7 @@ In this case you have changed the location of the cache directory to You can also change the cache directory by defining an environment variable named ``APP_CACHE_DIR`` whose value is the full path of the cache folder. -.. caution:: +.. warning:: You should keep the cache directory different for each environment, otherwise some unexpected behavior may happen. Each environment generates diff --git a/console.rst b/console.rst index 57f322c983d..6a3ba70300f 100644 --- a/console.rst +++ b/console.rst @@ -366,7 +366,7 @@ Output sections let you manipulate the Console output in advanced ways, such as are updated independently and :ref:`appending rows to tables ` that have already been rendered. -.. caution:: +.. warning:: Terminals only allow overwriting the visible content, so you must take into account the console height when trying to write/overwrite section contents. @@ -531,13 +531,13 @@ call ``setAutoExit(false)`` on it to get the command result in ``CommandTester`` You can also test a whole console application by using :class:`Symfony\\Component\\Console\\Tester\\ApplicationTester`. -.. caution:: +.. warning:: When testing commands using the ``CommandTester`` class, console events are not dispatched. If you need to test those events, use the :class:`Symfony\\Component\\Console\\Tester\\ApplicationTester` instead. -.. caution:: +.. warning:: When testing commands using the :class:`Symfony\\Component\\Console\\Tester\\ApplicationTester` class, don't forget to disable the auto exit flag:: @@ -547,7 +547,7 @@ call ``setAutoExit(false)`` on it to get the command result in ``CommandTester`` $tester = new ApplicationTester($application); -.. caution:: +.. warning:: When testing ``InputOption::VALUE_NONE`` command options, you must pass ``true`` to them:: @@ -619,7 +619,7 @@ profile is accessible through the web page of the profiler. terminal supports links). If you run it in debug verbosity (``-vvv``) you'll also see the time and memory consumed by the command. -.. caution:: +.. warning:: When profiling the ``messenger:consume`` command from the :doc:`Messenger ` component, add the ``--no-reset`` option to the command or you won't get any diff --git a/console/calling_commands.rst b/console/calling_commands.rst index c5bfc6e5a72..349f1357682 100644 --- a/console/calling_commands.rst +++ b/console/calling_commands.rst @@ -36,6 +36,9 @@ method):: '--yell' => true, ]); + // disable interactive behavior for the greet command + $greetInput->setInteractive(false); + $returnCode = $this->getApplication()->doRun($greetInput, $output); // ... @@ -57,7 +60,7 @@ method):: ``$this->getApplication()->find('demo:greet')->run()`` will allow proper events to be dispatched for that inner command as well. -.. caution:: +.. warning:: Note that all the commands will run in the same process and some of Symfony's built-in commands may not work well this way. For instance, the ``cache:clear`` diff --git a/console/command_in_controller.rst b/console/command_in_controller.rst index 64475bff103..74af9e17c15 100644 --- a/console/command_in_controller.rst +++ b/console/command_in_controller.rst @@ -11,7 +11,7 @@ service that can be reused in the controller. However, when the command is part of a third-party library, you don't want to modify or duplicate their code. Instead, you can run the command directly from the controller. -.. caution:: +.. warning:: In comparison with a direct call from the console, calling a command from a controller has a slight performance impact because of the request stack diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst index 75aa13d5be8..1393879a1df 100644 --- a/console/commands_as_services.rst +++ b/console/commands_as_services.rst @@ -51,7 +51,7 @@ argument (thanks to autowiring). In other words, you only need to create this class and everything works automatically! You can call the ``app:sunshine`` command and start logging. -.. caution:: +.. warning:: You *do* have access to services in ``configure()``. However, if your command is not :ref:`lazy `, try to avoid doing any @@ -130,7 +130,7 @@ only when the ``app:sunshine`` command is actually called. You don't need to call ``setName()`` for configuring the command when it is lazy. -.. caution:: +.. warning:: Calling the ``list`` command will instantiate all commands, including lazy commands. However, if the command is a ``Symfony\Component\Console\Command\LazyCommand``, then diff --git a/console/input.rst b/console/input.rst index c038ace56fc..baf47c6fd15 100644 --- a/console/input.rst +++ b/console/input.rst @@ -197,7 +197,7 @@ values after a whitespace or an ``=`` sign (e.g. ``--iterations 5`` or ``--iterations=5``), but short options can only use whitespaces or no separation at all (e.g. ``-i 5`` or ``-i5``). -.. caution:: +.. warning:: While it is possible to separate an option from its value with a whitespace, using this form leads to an ambiguity should the option appear before the diff --git a/contributing/code/bc.rst b/contributing/code/bc.rst index cff99a1554f..497c70fb01d 100644 --- a/contributing/code/bc.rst +++ b/contributing/code/bc.rst @@ -30,7 +30,7 @@ The second section, "Working on Symfony Code", is targeted at Symfony contributors. This section lists detailed rules that every contributor needs to follow to ensure smooth upgrades for our users. -.. caution:: +.. warning:: :doc:`Experimental Features ` and code marked with the ``@internal`` tags are excluded from our Backward @@ -53,7 +53,7 @@ All interfaces shipped with Symfony can be used in type hints. You can also call any of the methods that they declare. We guarantee that we won't break code that sticks to these rules. -.. caution:: +.. warning:: The exception to this rule are interfaces tagged with ``@internal``. Such interfaces should not be used or implemented. @@ -89,7 +89,7 @@ Using our Classes All classes provided by Symfony may be instantiated and accessed through their public methods and properties. -.. caution:: +.. warning:: Classes, properties and methods that bear the tag ``@internal`` as well as the classes located in the various ``*\Tests\`` namespaces are an @@ -146,7 +146,7 @@ Using our Traits All traits provided by Symfony may be used in your classes. -.. caution:: +.. warning:: The exception to this rule are traits tagged with ``@internal``. Such traits should not be used. diff --git a/contributing/code/bugs.rst b/contributing/code/bugs.rst index fba68617ee3..b0a46766026 100644 --- a/contributing/code/bugs.rst +++ b/contributing/code/bugs.rst @@ -4,7 +4,7 @@ Reporting a Bug Whenever you find a bug in Symfony, we kindly ask you to report it. It helps us make a better Symfony. -.. caution:: +.. warning:: If you think you've found a security issue, please use the special :doc:`procedure ` instead. diff --git a/contributing/code/maintenance.rst b/contributing/code/maintenance.rst index 04740ce8c6e..27e4fd73ea0 100644 --- a/contributing/code/maintenance.rst +++ b/contributing/code/maintenance.rst @@ -67,6 +67,9 @@ issue): * **Adding new deprecations**: After a version reaches stability, new deprecations cannot be added anymore. +* **Adding or updating annotations**: Adding or updating annotations (PHPDoc + annotations for instance) is not allowed; fixing them might be accepted. + Anything not explicitly listed above should be done on the next minor or major version instead. For instance, the following changes are never accepted in a patch version: diff --git a/contributing/documentation/format.rst b/contributing/documentation/format.rst index d933f3bcead..e81abe92b79 100644 --- a/contributing/documentation/format.rst +++ b/contributing/documentation/format.rst @@ -16,7 +16,7 @@ source code. If you want to learn more about this format, check out the `reStructuredText Primer`_ tutorial and the `reStructuredText Reference`_. -.. caution:: +.. warning:: If you are familiar with Markdown, be careful as things are sometimes very similar but different: diff --git a/contributing/documentation/standards.rst b/contributing/documentation/standards.rst index 420780d25f5..5e195d008fd 100644 --- a/contributing/documentation/standards.rst +++ b/contributing/documentation/standards.rst @@ -122,7 +122,7 @@ Example } } -.. caution:: +.. warning:: In YAML you should put a space after ``{`` and before ``}`` (e.g. ``{ _controller: ... }``), but this should not be done in Twig (e.g. ``{'hello' : 'value'}``). diff --git a/controller.rst b/controller.rst index 4fd03948ae2..026e76ed0a6 100644 --- a/controller.rst +++ b/controller.rst @@ -443,6 +443,26 @@ HTTP status to return if the validation fails:: The default status code returned if the validation fails is 404. +If you want to map your object to a nested array in your query using a specific key, +set the ``key`` option in the ``#[MapQueryString]`` attribute:: + + use App\Model\SearchDto; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\HttpKernel\Attribute\MapQueryString; + + // ... + + public function dashboard( + #[MapQueryString(key: 'search')] SearchDto $searchDto + ): Response + { + // ... + } + +.. versionadded:: 7.3 + + The ``key`` option of ``#[MapQueryString]`` was introduced in Symfony 7.3. + If you need a valid DTO even when the request query string is empty, set a default value for your controller arguments:: @@ -788,6 +808,14 @@ response types. Some of these are mentioned below. To learn more about the ``Request`` and ``Response`` (and different ``Response`` classes), see the :ref:`HttpFoundation component documentation `. +.. note:: + + Technically, a controller can return a value other than a ``Response``. + However, your application is responsible for transforming that value into a + ``Response`` object. This is handled using :doc:`events ` + (specifically the :ref:`kernel.view event `), + an advanced feature you'll learn about later. + Accessing Configuration Values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -890,7 +918,7 @@ method:: { $response = $this->sendEarlyHints([ new Link(rel: 'preconnect', href: 'https://fonts.google.com'), - (new Link(href: '/style.css'))->withAttribute('as', 'stylesheet'), + (new Link(href: '/style.css'))->withAttribute('as', 'style'), (new Link(href: '/script.js'))->withAttribute('as', 'script'), ]); @@ -946,6 +974,6 @@ Learn more about Controllers .. _`Early hints`: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103 .. _`SAPI`: https://www.php.net/manual/en/function.php-sapi-name.php .. _`FrankenPHP`: https://frankenphp.dev -.. _`Validate Filters`: https://www.php.net/manual/en/filter.filters.validate.php +.. _`Validate Filters`: https://www.php.net/manual/en/filter.constants.php .. _`phpstan/phpdoc-parser`: https://packagist.org/packages/phpstan/phpdoc-parser .. _`phpdocumentor/type-resolver`: https://packagist.org/packages/phpdocumentor/type-resolver diff --git a/controller/error_pages.rst b/controller/error_pages.rst index 001e637c03e..fc36b88779a 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -319,7 +319,7 @@ error pages. .. note:: - If your listener calls ``setThrowable()`` on the + If your listener calls ``setResponse()`` on the :class:`Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent` event, propagation will be stopped and the response will be sent to the client. diff --git a/deployment.rst b/deployment.rst index 3edbc34dd6b..864ebc7a963 100644 --- a/deployment.rst +++ b/deployment.rst @@ -184,7 +184,7 @@ as you normally do: significantly by building a "class map". The ``--no-dev`` flag ensures that development packages are not installed in the production environment. -.. caution:: +.. warning:: If you get a "class not found" error during this step, you may need to run ``export APP_ENV=prod`` (or ``export SYMFONY_ENV=prod`` if you're not diff --git a/deployment/proxies.rst b/deployment/proxies.rst index cd5649d979a..4dad6f95fb1 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -102,7 +102,7 @@ using the following configuration options: Support for the ``SYMFONY_TRUSTED_PROXIES`` and ``SYMFONY_TRUSTED_HEADERS`` environment variables was introduced in Symfony 7.2. -.. caution:: +.. danger:: Enabling the ``Request::HEADER_X_FORWARDED_HOST`` option exposes the application to `HTTP Host header attacks`_. Make sure the proxy really diff --git a/doctrine.rst b/doctrine.rst index dc42a5b9e73..171f8a3348a 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -58,7 +58,7 @@ The database connection information is stored as an environment variable called # to use oracle: # DATABASE_URL="oci8://db_user:db_password@127.0.0.1:1521/db_name" -.. caution:: +.. warning:: If the username, password, host or database name contain any character considered special in a URI (such as ``: / ? # [ ] @ ! $ & ' ( ) * + , ; =``), @@ -174,7 +174,7 @@ Whoa! You now have a new ``src/Entity/Product.php`` file:: Confused why the price is an integer? Don't worry: this is just an example. But, storing prices as integers (e.g. 100 = $1 USD) can avoid rounding issues. -.. caution:: +.. warning:: There is a `limit of 767 bytes for the index key prefix`_ when using InnoDB tables in MySQL 5.6 and earlier versions. String columns with 255 @@ -204,7 +204,7 @@ If you want to use XML instead of attributes, add ``type: xml`` and ``dir: '%kernel.project_dir%/config/doctrine'`` to the entity mappings in your ``config/packages/doctrine.yaml`` file. -.. caution:: +.. warning:: Be careful not to use reserved SQL keywords as your table or column names (e.g. ``GROUP`` or ``USER``). See Doctrine's `Reserved SQL keywords documentation`_ @@ -320,7 +320,7 @@ before, execute your migrations: $ php bin/console doctrine:migrations:migrate -.. caution:: +.. warning:: If you are using an SQLite database, you'll see the following error: *PDOException: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL diff --git a/doctrine/custom_dql_functions.rst b/doctrine/custom_dql_functions.rst index 1b3aa4aa185..e5b21819f58 100644 --- a/doctrine/custom_dql_functions.rst +++ b/doctrine/custom_dql_functions.rst @@ -132,7 +132,7 @@ In Symfony, you can register your custom DQL functions as follows: ->datetimeFunction('test_datetime', DatetimeFunction::class); }; -.. caution:: +.. warning:: DQL functions are instantiated by Doctrine outside of the Symfony :doc:`service container ` so you can't inject services diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index 014d9e4dccb..1a56c55ddad 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -15,7 +15,7 @@ entities, each with their own database connection strings or separate cache conf advanced and not usually required. Be sure you actually need multiple entity managers before adding in this layer of complexity. -.. caution:: +.. warning:: Entities cannot define associations across different entity managers. If you need that, there are `several alternatives`_ that require some custom setup. @@ -142,7 +142,7 @@ and ``customer``. The ``default`` entity manager manages entities in the entities in ``src/Entity/Customer``. You've also defined two connections, one for each entity manager, but you are free to define the same connection for both. -.. caution:: +.. warning:: When working with multiple connections and entity managers, you should be explicit about which configuration you want. If you *do* omit the name of @@ -251,7 +251,7 @@ The same applies to repository calls:: } } -.. caution:: +.. warning:: One entity can be managed by more than one entity manager. This however results in unexpected behavior when extending from ``ServiceEntityRepository`` diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 6787cba2d83..27885af267b 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -41,6 +41,9 @@ The most common way to listen to an event is to register an **event listener**:: // Customize your response object to display the exception details $response = new Response(); $response->setContent($message); + // the exception message can contain unfiltered user input; + // set the content-type to text to avoid XSS issues + $response->headers->set('Content-Type', 'text/plain; charset=utf-8'); // HttpExceptionInterface is a special type of exception that // holds status code and header details @@ -798,3 +801,11 @@ could listen to the ``mailer.post_send`` event and change the method's return va That's it! Your subscriber should be called automatically (or read more about :ref:`event subscriber configuration `). + +Learn More +---------- + +- :ref:`The Request-Response Lifecycle ` +- :doc:`/reference/events` +- :ref:`Security-related Events ` +- :doc:`/components/event_dispatcher` diff --git a/form/bootstrap5.rst b/form/bootstrap5.rst index 400747bba12..db098a1ba09 100644 --- a/form/bootstrap5.rst +++ b/form/bootstrap5.rst @@ -171,7 +171,7 @@ class to the label: ], // ... -.. caution:: +.. warning:: Switches only work with **checkbox**. @@ -201,7 +201,7 @@ class to the ``row_attr`` option. } }) }} -.. caution:: +.. warning:: If you fill the ``help`` option of your form, it will also be rendered as part of the group. @@ -239,7 +239,7 @@ of your form type. } }) }} -.. caution:: +.. warning:: You **must** provide a ``label`` and a ``placeholder`` to make floating labels work properly. diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 709f3321544..0d92a967fa0 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -449,7 +449,7 @@ are some examples of Twig block names for the postal address type: ``postal_address_zipCode_label`` The label block of the ZIP Code field. -.. caution:: +.. warning:: When the name of your form class matches any of the built-in field types, your form might not be rendered correctly. A form type named diff --git a/form/data_mappers.rst b/form/data_mappers.rst index cb5c7936701..38c92ce35ae 100644 --- a/form/data_mappers.rst +++ b/form/data_mappers.rst @@ -126,7 +126,7 @@ in your form type:: } } -.. caution:: +.. warning:: The data passed to the mapper is *not yet validated*. This means that your objects should allow being created in an invalid state in order to produce @@ -215,7 +215,7 @@ If available, these options have priority over the property path accessor and the default data mapper will still use the :doc:`PropertyAccess component ` for the other form fields. -.. caution:: +.. warning:: When a form has the ``inherit_data`` option set to ``true``, it does not use the data mapper and lets its parent map inner values. diff --git a/form/data_transformers.rst b/form/data_transformers.rst index 4e81fc3e930..db051a04bbc 100644 --- a/form/data_transformers.rst +++ b/form/data_transformers.rst @@ -8,7 +8,7 @@ can be rendered as a ``yyyy-MM-dd``-formatted input text box. Internally, a data converts the ``DateTime`` value of the field to a ``yyyy-MM-dd`` formatted string when rendering the form, and then back to a ``DateTime`` object on submit. -.. caution:: +.. warning:: When a form field has the ``inherit_data`` option set to ``true``, data transformers are not applied to that field. @@ -340,7 +340,7 @@ that, after a successful submission, the Form component will pass a real If the issue isn't found, a form error will be created for that field and its error message can be controlled with the ``invalid_message`` field option. -.. caution:: +.. warning:: Be careful when adding your transformers. For example, the following is **wrong**, as the transformer would be applied to the entire form, instead of just this @@ -472,7 +472,7 @@ Which transformer you need depends on your situation. To use the view transformer, call ``addViewTransformer()``. -.. caution:: +.. warning:: Be careful with model transformers and :doc:`Collection ` field types. diff --git a/form/direct_submit.rst b/form/direct_submit.rst index 7b98134af18..7a08fb6978a 100644 --- a/form/direct_submit.rst +++ b/form/direct_submit.rst @@ -65,7 +65,7 @@ the fields defined by the form class. Otherwise, you'll see a form validation er argument to ``submit()``. Passing ``false`` will remove any missing fields within the form object. Otherwise, the missing fields will be set to ``null``. -.. caution:: +.. warning:: When the second parameter ``$clearMissing`` is ``false``, like with the "PATCH" method, the validation will only apply to the submitted fields. If diff --git a/form/events.rst b/form/events.rst index 745df2df453..dad6c242ddd 100644 --- a/form/events.rst +++ b/form/events.rst @@ -192,7 +192,7 @@ Form view data Same as in ``FormEvents::POST_SET_DATA`` See all form events at a glance in the :ref:`Form Events Information Table `. -.. caution:: +.. warning:: At this point, you cannot add or remove fields to the form. @@ -225,7 +225,7 @@ Form view data Normalized data transformed using a view transformer See all form events at a glance in the :ref:`Form Events Information Table `. -.. caution:: +.. warning:: At this point, you cannot add or remove fields to the current form and its children. diff --git a/form/form_collections.rst b/form/form_collections.rst index f0ad76a8a61..2a0ba99657f 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -195,7 +195,7 @@ then set on the ``tag`` field of the ``Task`` and can be accessed via ``$task->g So far, this works great, but only to edit *existing* tags. It doesn't allow us yet to add new tags or delete existing ones. -.. caution:: +.. warning:: You can embed nested collections as many levels down as you like. However, if you use Xdebug, you may receive a ``Maximum function nesting level of '100' @@ -427,13 +427,13 @@ That was fine, but forcing the use of the "adder" method makes handling these new ``Tag`` objects easier (especially if you're using Doctrine, which you will learn about next!). -.. caution:: +.. warning:: You have to create **both** ``addTag()`` and ``removeTag()`` methods, otherwise the form will still use ``setTag()`` even if ``by_reference`` is ``false``. You'll learn more about the ``removeTag()`` method later in this article. -.. caution:: +.. warning:: Symfony can only make the plural-to-singular conversion (e.g. from the ``tags`` property to the ``addTag()`` method) for English words. Code diff --git a/form/form_customization.rst b/form/form_customization.rst index 3f3cd0bbc89..1c23601a883 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -74,7 +74,7 @@ control over how each form field is rendered, so you can fully customize them: -.. caution:: +.. warning:: If you're rendering each field manually, make sure you don't forget the ``_token`` field that is automatically added for CSRF protection. @@ -305,7 +305,7 @@ Renders any errors for the given field. {# render any "global" errors not associated to any form field #} {{ form_errors(form) }} -.. caution:: +.. warning:: In the Bootstrap 4 form theme, ``form_errors()`` is already included in ``form_label()``. Read more about this in the diff --git a/form/form_themes.rst b/form/form_themes.rst index eb6f6f2ae22..8b82982edaa 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -177,7 +177,7 @@ of form themes: {# ... #} -.. caution:: +.. warning:: When using the ``only`` keyword, none of Symfony's built-in form themes (``form_div_layout.html.twig``, etc.) will be applied. In order to render diff --git a/form/inherit_data_option.rst b/form/inherit_data_option.rst index 19b14b27bcd..2caa0afcdbe 100644 --- a/form/inherit_data_option.rst +++ b/form/inherit_data_option.rst @@ -165,6 +165,6 @@ Finally, make this work by adding the location form to your two original forms:: That's it! You have extracted duplicated field definitions to a separate location form that you can reuse wherever you need it. -.. caution:: +.. warning:: Forms with the ``inherit_data`` option set cannot have ``*_SET_DATA`` event listeners. diff --git a/form/type_guesser.rst b/form/type_guesser.rst index 111f1b77986..106eb4e7742 100644 --- a/form/type_guesser.rst +++ b/form/type_guesser.rst @@ -162,7 +162,7 @@ instance with the value of the option. This constructor has 2 arguments: ``null`` is guessed when you believe the value of the option should not be set. -.. caution:: +.. warning:: You should be very careful using the ``guessMaxLength()`` method. When the type is a float, you cannot determine a length (e.g. you want a float to be diff --git a/form/unit_testing.rst b/form/unit_testing.rst index bf57e6d1afc..9603c5bc0d2 100644 --- a/form/unit_testing.rst +++ b/form/unit_testing.rst @@ -1,7 +1,7 @@ How to Unit Test your Forms =========================== -.. caution:: +.. warning:: This article is intended for developers who create :doc:`custom form types `. If you are using @@ -121,7 +121,7 @@ variable exists and will be available in your form themes:: Use `PHPUnit data providers`_ to test multiple form conditions using the same test code. -.. caution:: +.. warning:: When your type relies on the ``EntityType``, you should register the :class:`Symfony\\Bridge\\Doctrine\\Form\\DoctrineOrmExtension`, which will @@ -214,7 +214,7 @@ allows you to return a list of extensions to register:: { $validator = Validation::createValidator(); - // or if you also need to read constraints from annotations + // or if you also need to read constraints from attributes $validator = Validation::createValidatorBuilder() ->enableAttributeMapping() ->getValidator(); diff --git a/form/without_class.rst b/form/without_class.rst index 589f8a4739e..436976bdfcc 100644 --- a/form/without_class.rst +++ b/form/without_class.rst @@ -121,7 +121,7 @@ but here's a short example:: submitted data is validated using the ``Symfony\Component\Validator\Constraints\Valid`` constraint, unless you :doc:`disable validation `. -.. caution:: +.. warning:: When a form is only partially submitted (for example, in an HTTP PATCH request), only the constraints from the submitted form fields will be diff --git a/forms.rst b/forms.rst index a90e4ee1772..008c60a66c6 100644 --- a/forms.rst +++ b/forms.rst @@ -869,7 +869,7 @@ pass ``null`` to it:: } } -.. caution:: +.. warning:: When using a specific :doc:`form validation group `, the field type guesser will still consider *all* validation constraints when diff --git a/frontend.rst b/frontend.rst index f498dc737b5..c28e6fcf222 100644 --- a/frontend.rst +++ b/frontend.rst @@ -61,6 +61,10 @@ be executed by a browser. AssetMapper (Recommended) ~~~~~~~~~~~~~~~~~~~~~~~~~ +.. screencast:: + + Do you prefer video tutorials? Check out the `AssetMapper screencast series`_. + AssetMapper is the recommended system for handling your assets. It runs entirely in PHP with no complex build step or dependencies. It does this by leveraging the ``importmap`` feature of your browser, which is available in all browsers thanks @@ -118,6 +122,10 @@ the `StimulusBundle Documentation`_ Using a Front-end Framework (React, Vue, Svelte, etc) ----------------------------------------------------- +.. screencast:: + + Do you prefer video tutorials? Check out the `API Platform screencast series`_. + If you want to use a front-end framework (Next.js, React, Vue, Svelte, etc), we recommend using their native tools and using Symfony as a pure API. A wonderful tool to do that is `API Platform`_. Their standard distribution comes with a @@ -143,3 +151,5 @@ Other Front-End Articles .. _`Symfony UX`: https://ux.symfony.com .. _`API Platform`: https://api-platform.com/ .. _`SensioLabs Minify Bundle`: https://github.com/sensiolabs/minify-bundle +.. _`AssetMapper screencast series`: https://symfonycasts.com/screencast/asset-mapper +.. _`API Platform screencast series`: https://symfonycasts.com/screencast/api-platform diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index 685474e66d3..d68c77c0105 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -12,7 +12,7 @@ The component has two main features: * :ref:`Mapping & Versioning Assets `: All files inside of ``assets/`` are made available publicly and **versioned**. You can reference the file ``assets/images/product.jpg`` in a Twig template with ``{{ asset('images/product.jpg') }}``. - The final URL will include a version hash, like ``/assets/images/product-3c16d9220694c0e56d8648f25e6035e9.jpg``. + The final URL will include a version hash, like ``/assets/images/product-3c16d92m.jpg``. * :ref:`Importmaps `: A native browser feature that makes it easier to use the JavaScript ``import`` statement (e.g. ``import { Modal } from 'bootstrap'``) @@ -70,7 +70,7 @@ The path - ``images/duck.png`` - is relative to your mapped directory (``assets/ This is known as the **logical path** to your asset. If you look at the HTML in your page, the URL will be something -like: ``/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png``. If you change +like: ``/assets/images/duck-3c16d92m.png``. If you change the file, the version part of the URL will also change automatically. .. _asset-mapper-compile-assets: @@ -78,7 +78,7 @@ the file, the version part of the URL will also change automatically. Serving Assets in dev vs prod ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the ``dev`` environment, the URL ``/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png`` +In the ``dev`` environment, the URL ``/assets/images/duck-3c16d92m.png`` is handled and returned by your Symfony app. For the ``prod`` environment, before deploy, you should run: @@ -91,7 +91,7 @@ This will physically copy all the files from your mapped directories to ``public/assets/`` so that they're served directly by your web server. See :ref:`Deployment ` for more details. -.. caution:: +.. warning:: If you run the ``asset-map:compile`` command on your development machine, you won't see any changes made to your assets when reloading the page. @@ -283,9 +283,9 @@ outputs an `importmap`_: @@ -342,8 +342,8 @@ The ``importmap()`` function also outputs a set of "preloads": .. code-block:: html - - + + This is a performance optimization and you can learn more about below in :ref:`Performance: Add Preloading `. @@ -415,6 +415,8 @@ from inside ``app.js``: // things on "window" become global variables window.$ = $; +.. _asset-mapper-handling-css: + Handling CSS ------------ @@ -492,9 +494,9 @@ for ``duck.png``: .. code-block:: css - /* public/assets/styles/app-3c16d9220694c0e56d8648f25e6035e9.css */ + /* public/assets/styles/app-3c16d92m.css */ .quack { - background-image: url('../images/duck-3c16d9220694c0e56d8648f25e6035e9.png'); + background-image: url('../images/duck-3c16d92m.png'); } .. _asset-mapper-tailwind: @@ -571,7 +573,7 @@ Sometimes a JavaScript file you're importing (e.g. ``import './duck.js'``), or a CSS/image file you're referencing won't be found, and you'll see a 404 error in your browser's console. You'll also notice that the 404 URL is missing the version hash in the filename (e.g. a 404 to ``/assets/duck.js`` instead of -a path like ``/assets/duck.1b7a64b3b3d31219c262cf72521a5267.js``). +a path like ``/assets/duck-1b7a64b3.js``). This is usually because the path is wrong. If you're referencing the file directly in a Twig template: @@ -646,7 +648,7 @@ To make your AssetMapper-powered site fly, there are a few things you need to do. If you want to take a shortcut, you can use a service like `Cloudflare`_, which will automatically do most of these things for you: -- **Use HTTP/2**: Your web server should be running HTTP/2 (or HTTP/3) so the +- **Use HTTP/2**: Your web server should be running HTTP/2 or HTTP/3 so the browser can download assets in parallel. HTTP/2 is automatically enabled in Caddy and can be activated in Nginx and Apache. Or, proxy your site through a service like Cloudflare, which will automatically enable HTTP/2 for you. @@ -654,7 +656,9 @@ which will automatically do most of these things for you: - **Compress your assets**: Your web server should compress (e.g. using gzip) your assets (JavaScript, CSS, images) before sending them to the browser. This is automatically enabled in Caddy and can be activated in Nginx and Apache. - In Cloudflare, assets are compressed by default. + In Cloudflare, assets are compressed by default. AssetMapper also supports + :ref:`precompressing your web assets ` to further + improve performance. - **Set long-lived cache expiry**: Your web server should set a long-lived ``Cache-Control`` HTTP header on your assets. Because the AssetMapper component includes a version @@ -702,6 +706,76 @@ even though it hasn't yet seen the ``import`` statement for them. Additionally, if the :doc:`WebLink Component ` is available in your application, Symfony will add a ``Link`` header in the response to preload the CSS files. +.. _performance-precompressing: + +Pre-Compressing Assets +---------------------- + +Although most servers (Caddy, Nginx, Apache, FrankenPHP) and services like Cloudflare +provide asset compression features, AssetMapper also allows you to compress all +your assets before serving them. + +This improves performance because you can compress assets using the highest (and +slowest) compression ratios beforehand and provide those compressed assets to the +server, which then returns them to the client without wasting CPU resources on +compression. + +AssetMapper supports `Brotli`_, `Zstandard`_ and `gzip`_ compression formats. +Before using any of them, the server that pre-compresses assets must have +installed the following PHP extensions or CLI commands: + +* Brotli: ``brotli`` CLI command; `brotli PHP extension`_; +* Zstandard: ``zstd`` CLI command; `zstd PHP extension`_; +* gzip: ``zopfli`` (better) or ``gzip`` CLI command; `zlib PHP extension`_. + +Then, update your AssetMapper configuration to define which compression to use +and which file extensions should be compressed: + +.. code-block:: yaml + + # config/packages/asset_mapper.yaml + framework: + asset_mapper: + # ... + + precompress: + format: 'zstandard' + # if you don't define the following option, AssetMapper will compress all + # the extensions considered safe (css, js, json, svg, xml, ttf, otf, wasm, etc.) + extensions: ['css', 'js', 'json', 'svg', 'xml'] + +Now, when running the ``asset-map:compile`` command, all matching files will be +compressed in the configured format and at the highest compression level. The +compressed files are created with the same name as the original but with the +``.br``, ``.zst``, or ``.gz`` extension appended. + +Then, you need to configure your web server to serve the precompressed assets +instead of the original ones: + +.. configuration-block:: + + .. code-block:: caddy + + file_server { + precompressed br zstd gzip + } + + .. code-block:: nginx + + gzip_static on; + + # Requires https://github.com/google/ngx_brotli + brotli_static on; + + # Requires https://github.com/tokers/zstd-nginx-module + zstd_static on; + +.. tip:: + + AssetMapper provides an ``assets:compress`` CLI command and a service called + ``asset_mapper.compressor`` that you can use anywhere in your application to + compress any kind of files (e.g. files uploaded by users to your application). + Frequently Asked Questions -------------------------- @@ -846,7 +920,7 @@ be versioned! It will output something like: .. code-block:: html+twig - + Overriding 3rd-Party Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1093,6 +1167,24 @@ it in the CSP header, and then pass the same nonce to the Twig function: {# the csp_nonce() function is defined by the NelmioSecurityBundle #} {{ importmap('app', {'nonce': csp_nonce('script')}) }} +Content Security Policy and CSS Files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your importmap includes CSS files, AssetMapper uses a trick to load those by +adding ``data:application/javascript`` to the rendered importmap (see +:ref:`Handling CSS `). + +This can cause browsers to report CSP violations and block the CSS files from +being loaded. To prevent this, you can add `strict-dynamic`_ to the ``script-src`` +directive of your Content Security Policy, to tell the browser that the importmap +is allowed to load other resources. + +.. note:: + + When using ``strict-dynamic``, the browser will ignore any other sources in + ``script-src`` such as ``'self'`` or ``'unsafe-inline'``, so any other + `` + +
+ Then retrieve it from your JS file: .. code-block:: javascript @@ -290,6 +295,9 @@ Then retrieve it from your JS file: const eventSource = new EventSource(url); // ... + // with Stimulus + this.eventSource = new EventSource(this.mercureUrlValue); + Mercure also allows subscribing to several topics, and to use URI Templates or the special value ``*`` (matched by all topics) as patterns: @@ -407,7 +415,7 @@ of the ``Update`` constructor to ``true``:: $update = new Update( 'https://example.com/books/1', json_encode(['status' => 'OutOfStock']), - true // private + private: true ); // Publisher's JWT must contain this topic, a URI template it matches or * in mercure.publish or you'll get a 401 @@ -704,6 +712,8 @@ enable it:: :alt: The Mercure panel of the Symfony Profiler, showing information like time, memory, topics and data of each message sent by Mercure. :class: with-browser +The Mercure hub itself provides a debug tool that can be enabled and available on `/.well-known/mercure/ui/` + Async dispatching ----------------- From 4a324e82ced465a1cebf186d694aa69f5703aded Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 18 Mar 2025 13:46:47 +0100 Subject: [PATCH 301/427] Tweaks --- mercure.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mercure.rst b/mercure.rst index 125511f6f2b..c2aa068167d 100644 --- a/mercure.rst +++ b/mercure.rst @@ -415,7 +415,7 @@ of the ``Update`` constructor to ``true``:: $update = new Update( 'https://example.com/books/1', json_encode(['status' => 'OutOfStock']), - private: true + true // private ); // Publisher's JWT must contain this topic, a URI template it matches or * in mercure.publish or you'll get a 401 @@ -712,7 +712,8 @@ enable it:: :alt: The Mercure panel of the Symfony Profiler, showing information like time, memory, topics and data of each message sent by Mercure. :class: with-browser -The Mercure hub itself provides a debug tool that can be enabled and available on `/.well-known/mercure/ui/` +The Mercure hub itself provides a debug tool that can be enabled and it's +available on ``/.well-known/mercure/ui/`` Async dispatching ----------------- From 1e8d50b5aac5e54cfd07214e2b3fdab15c205e01 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 18 Mar 2025 13:49:23 +0100 Subject: [PATCH 302/427] Update the docs builder dependencies --- _build/composer.lock | 519 +++++++++++++++++++------------------------ 1 file changed, 231 insertions(+), 288 deletions(-) diff --git a/_build/composer.lock b/_build/composer.lock index 89a4e7da3c6..a30ed16776b 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": "6524e63395216a3a297f1c78c7f39d86", "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", @@ -520,24 +474,24 @@ }, { "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,20 +564,20 @@ "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": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "aedf3cb0f5b929ec255d96bbb4909e9932c769e0" + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e" }, "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/cb23e97813c5837a041b73a6d63a9ddff0778f5e", + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e", "shasum": "" }, "require": { @@ -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/v6.4.13" }, "funding": [ { @@ -677,20 +629,20 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:44:56+00:00" + "time": "2024-09-25T14:18:03+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,20 +696,20 @@ "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": "v6.4.19", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "0e0d0f709997ad1224ef22bb0a28287c44b7840f" + "reference": "19073e3e0bb50cbc1cb286077069b3107085206f" }, "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/19073e3e0bb50cbc1cb286077069b3107085206f", + "reference": "19073e3e0bb50cbc1cb286077069b3107085206f", "shasum": "" }, "require": { @@ -767,10 +719,7 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/css-selector": "^5.4|^6.0" - }, - "suggest": { - "symfony/css-selector": "" + "symfony/css-selector": "^5.4|^6.0|^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/v6.4.19" }, "funding": [ { @@ -814,20 +763,20 @@ "type": "tidelift" } ], - "time": "2023-03-09T16:20:02+00:00" + "time": "2025-02-14T17:58:34+00:00" }, { "name": "symfony/filesystem", - "version": "v6.2.7", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "82b6c62b959f642d000456f08c6d219d749215b3" + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/82b6c62b959f642d000456f08c6d219d749215b3", - "reference": "82b6c62b959f642d000456f08c6d219d749215b3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", "shasum": "" }, "require": { @@ -835,6 +784,9 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^5.4|^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/v6.4.13" }, "funding": [ { @@ -877,27 +829,27 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:44:56+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/finder", - "version": "v6.2.7", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "20808dc6631aecafbe67c186af5dcb370be3a0eb" + "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/20808dc6631aecafbe67c186af5dcb370be3a0eb", - "reference": "20808dc6631aecafbe67c186af5dcb370be3a0eb", + "url": "https://api.github.com/repos/symfony/finder/zipball/1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", + "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.0|^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/v6.4.17" }, "funding": [ { @@ -941,28 +893,32 @@ "type": "tidelift" } ], - "time": "2023-02-16T09:57:23+00:00" + "time": "2024-12-29T13:51:37+00:00" }, { "name": "symfony/http-client", - "version": "v6.2.8", + "version": "v6.4.19", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "66391ba3a8862c560e1d9134c96d9bd2a619b477" + "reference": "3294a433fc9d12ae58128174896b5b1822c28dad" }, "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/3294a433fc9d12ae58128174896b5b1822c28dad", + "reference": "3294a433fc9d12ae58128174896b5b1822c28dad", "shasum": "" }, "require": { "php": ">=8.1", "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": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.3" }, "provide": { "php-http/async-client-implementation": "*", @@ -975,14 +931,15 @@ "amphp/http-client": "^4.2.1", "amphp/http-tunnel": "^1.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/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1013,7 +970,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.2.8" + "source": "https://github.com/symfony/http-client/tree/v6.4.19" }, "funding": [ { @@ -1029,36 +986,33 @@ "type": "tidelift" } ], - "time": "2023-03-31T09:14:44+00:00" + "time": "2025-02-13T09:55:13+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 +1048,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 +1064,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 +1091,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 +1127,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 +1143,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 +1205,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 +1221,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 +1286,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 +1302,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 +1329,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 +1366,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 +1382,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 +1427,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 +1443,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 +1510,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,20 +1526,20 @@ "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": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef" + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef", + "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", "shasum": "" }, "require": { @@ -1610,14 +1550,14 @@ "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/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1656,7 +1596,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.8" + "source": "https://github.com/symfony/string/tree/v6.4.15" }, "funding": [ { @@ -1672,42 +1612,42 @@ "type": "tidelift" } ], - "time": "2023-03-20T16:06:02+00:00" + "time": "2024-11-13T13:31:12+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 +1674,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 +1690,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 +1757,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 +1769,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" }, - "platform-dev": [], + "platform-dev": {}, "platform-overrides": { "php": "8.1.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From c679fe5d157635c1f02bedcfc2353199d1f12977 Mon Sep 17 00:00:00 2001 From: EtienneHosman <43244960+EtienneHosman@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:51:03 +0100 Subject: [PATCH 303/427] Update virtual-machine.rst Syntax error: made 'all' a string --- frontend/encore/virtual-machine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/virtual-machine.rst b/frontend/encore/virtual-machine.rst index d18026d3633..34587173b93 100644 --- a/frontend/encore/virtual-machine.rst +++ b/frontend/encore/virtual-machine.rst @@ -107,7 +107,7 @@ the dev-server. To fix this, set the ``allowedHosts`` option: // ... .configureDevServerOptions(options => { - options.allowedHosts = all; + options.allowedHosts = 'all'; }) .. warning:: From b8af29ce4c629060b2f167a45afe77acac4bdf32 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 18 Mar 2025 16:04:59 +0100 Subject: [PATCH 304/427] Reword --- routing.rst | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/routing.rst b/routing.rst index c5cf5cd7f33..68d6a30fc41 100644 --- a/routing.rst +++ b/routing.rst @@ -434,6 +434,21 @@ evaluates them: blog_show ANY ANY ANY /blog/{slug} ---------------- ------- ------- ----- -------------------------------------------- + # pass this option to also display all the defined route aliases + $ php bin/console debug:router --show-aliases + + # pass this option to only display routes that match the given HTTP method + # (you can use the special value ANY to see routes that match any method) + $ php bin/console debug:router --method=GET + $ php bin/console debug:router --method=ANY + + # pass the option more than once to display the routes that match all the given methods + $ php bin/console debug:router --method=GET --method=PATCH + +.. versionadded:: 7.3 + + The ``--method`` option was introduced in Symfony 7.3. + Pass the name (or part of the name) of some route to this argument to print the route details: @@ -451,15 +466,6 @@ route details: | | utf8: true | +-------------+---------------------------------------------------------+ -.. tip:: - - Use the ``--show-aliases`` option to show all available aliases for a given - route. - -.. tip:: - - Use the ``--method`` option to filter routes by HTTP method. For example, to only show routes that use the ``GET`` method, add ``--method=GET`` - The other command is called ``router:match`` and it shows which route will match the given URL. It's useful to find out why some URL is not executing the controller action that you expect: From 387943cee13b5c0dc01b7b85289cd46a12f2940b Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne Date: Sun, 23 Feb 2025 18:45:08 +0100 Subject: [PATCH 305/427] [Validator] Allow Unique constraint validation on all elements --- reference/constraints/Unique.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index a1be67d6f2f..a37eba30c61 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -216,4 +216,17 @@ trailing whitespace during validation. .. include:: /reference/constraints/_payload-option.rst.inc +``stopOnFirstError`` +~~~~~~~~~~~~~~~~~~~~ + +**type**: ``boolean`` **default**: ``true`` + +By default, this constraint stops at the first violation. If the option is set to ``false``, +validation will continue on all elements and return all detected +:class:`Symfony\\Component\\Validator\\ConstraintViolation` object. + +.. versionadded:: 7.3 + + The ``stopOnFirstError`` option was introduced in Symfony 7.3. + .. _`PHP callable`: https://www.php.net/callable From 8801059a62bcc91918964f46c28142c947a40d62 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 18 Mar 2025 16:17:32 +0100 Subject: [PATCH 306/427] Minor tweak --- reference/constraints/Unique.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index a37eba30c61..9ce84139cd5 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -221,9 +221,9 @@ trailing whitespace during validation. **type**: ``boolean`` **default**: ``true`` -By default, this constraint stops at the first violation. If the option is set to ``false``, -validation will continue on all elements and return all detected -:class:`Symfony\\Component\\Validator\\ConstraintViolation` object. +By default, this constraint stops at the first violation. If this option is set +to ``false``, validation continues on all elements and returns all detected +:class:`Symfony\\Component\\Validator\\ConstraintViolation` objects. .. versionadded:: 7.3 From 4213bb57c7f139451d8df44c1f6a91d07559ec5f Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Tue, 18 Mar 2025 22:26:31 +0100 Subject: [PATCH 307/427] [Serializer] Add SnakeCaseToCamelCaseNameConverter --- serializer.rst | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/serializer.rst b/serializer.rst index cd181787763..bd8506cbbe3 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1239,6 +1239,67 @@ setting the ``name_converter`` setting to ]; $serializer = new Serializer($normalizers, $encoders); +snake_case to CamelCase +~~~~~~~~~~~~~~~~~~~~~~~ + +In Symfony applications is common to use camelCase to name properties. However +some packages can use snake_case as convention. + +Symfony provides a built-in name converter designed to transform between +CamelCase and snake_cased styles during serialization and deserialization +processes. You can use it instead of the metadata aware name converter by +setting the ``name_converter`` setting to +``serializer.name_converter.snake_case_to_camel_case``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/serializer.yaml + framework: + serializer: + name_converter: 'serializer.name_converter.snake_case_to_camel_case' + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/serializer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework): void { + $framework->serializer() + ->nameConverter('serializer.name_converter.snake_case_to_camel_case') + ; + }; + + .. code-block:: php-standalone + + use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter; + use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; + + // ... + $normalizers = [ + new ObjectNormalizer(null, new SnakeCaseToCamelCaseNameConverter()), + ]; + $serializer = new Serializer($normalizers, $encoders); + .. _serializer-built-in-normalizers: Serializer Normalizers From a1647c609f11b860abf7de38aadb261fbbf9122a Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 18 Mar 2025 23:37:06 +0100 Subject: [PATCH 308/427] [Serializer] Add missing space + fix import --- serializer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serializer.rst b/serializer.rst index 5c82e6e566a..1c30ad89c6c 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1377,7 +1377,7 @@ Built-in Normalizers ~~~~~~~~~~~~~~~~~~~~ Besides the normalizers registered by default (see previous section), the -serializer component also provides some extra normalizers.You can register +serializer component also provides some extra normalizers. You can register these by defining a service and tag it with :ref:`serializer.normalizer `. For instance, to use the ``CustomNormalizer`` you have to define a service like: @@ -1421,7 +1421,7 @@ like: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; From 020ef3a702bb8b173d164d40d73626dc449d559a Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Tue, 18 Mar 2025 22:56:19 +0100 Subject: [PATCH 309/427] Replace TaggedIterator and TaggedLocator by Au*towireIterator and AutowireLocator --- .../service_subscribers_locators.rst | 20 +++++++++---------- service_container/tags.rst | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index 9c6451931d1..a2aabb48901 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -270,8 +270,8 @@ the following dependency injection attributes in the ``getSubscribedServices()`` method directly: * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Autowire` -* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator` -* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator` +* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator` +* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Target` * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireDecorated` @@ -282,8 +282,8 @@ This is done by having ``getSubscribedServices()`` return an array of use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; - use Symfony\Component\DependencyInjection\Attribute\TaggedIterator; - use Symfony\Component\DependencyInjection\Attribute\TaggedLocator; + use Symfony\Component\DependencyInjection\Attribute\AutowireIterator; + use Symfony\Component\DependencyInjection\Attribute\AutowireLocator; use Symfony\Component\DependencyInjection\Attribute\Target; use Symfony\Contracts\Service\Attribute\SubscribedService; @@ -299,11 +299,11 @@ This is done by having ``getSubscribedServices()`` return an array of // Target new SubscribedService('event.logger', LoggerInterface::class, attributes: new Target('eventLogger')), - // TaggedIterator - new SubscribedService('loggers', 'iterable', attributes: new TaggedIterator('logger.tag')), + // AutowireIterator + new SubscribedService('loggers', 'iterable', attributes: new AutowireIterator('logger.tag')), - // TaggedLocator - new SubscribedService('handlers', ContainerInterface::class, attributes: new TaggedLocator('handler.tag')), + // AutowireLocator + new SubscribedService('handlers', ContainerInterface::class, attributes: new AutowireLocator('handler.tag')), ]; } @@ -975,8 +975,8 @@ You can use the ``attributes`` argument of ``SubscribedService`` to add any of the following dependency injection attributes: * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Autowire` -* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator` -* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator` +* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator` +* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Target` * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireDecorated` diff --git a/service_container/tags.rst b/service_container/tags.rst index 270d6702f5a..39262fa51be 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -750,7 +750,7 @@ directly via PHP attributes: .. note:: - Some IDEs will show an error when using ``#[TaggedIterator]`` together + Some IDEs will show an error when using ``#[AutowireIterator]`` together with the `PHP constructor promotion`_: *"Attribute cannot be applied to a property because it does not contain the 'Attribute::TARGET_PROPERTY' flag"*. The reason is that those constructor arguments are both parameters and class From 10565283d5234c46b8ed4510d79d2d75310b2f9c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 19 Mar 2025 08:35:26 +0100 Subject: [PATCH 310/427] Tweaks --- serializer.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/serializer.rst b/serializer.rst index bd8506cbbe3..54555d7b340 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1242,12 +1242,12 @@ setting the ``name_converter`` setting to snake_case to CamelCase ~~~~~~~~~~~~~~~~~~~~~~~ -In Symfony applications is common to use camelCase to name properties. However -some packages can use snake_case as convention. +In Symfony applications, it is common to use camelCase for naming properties. +However some packages may follow a snake_case convention. Symfony provides a built-in name converter designed to transform between -CamelCase and snake_cased styles during serialization and deserialization -processes. You can use it instead of the metadata aware name converter by +CamelCase and snake_case styles during serialization and deserialization +processes. You can use it instead of the metadata-aware name converter by setting the ``name_converter`` setting to ``serializer.name_converter.snake_case_to_camel_case``: @@ -1300,6 +1300,10 @@ setting the ``name_converter`` setting to ]; $serializer = new Serializer($normalizers, $encoders); +.. versionadded:: 7.2 + + The snake_case to CamelCase converter was introduced in Symfony 7.2. + .. _serializer-built-in-normalizers: Serializer Normalizers From d0a17c54a538f747bf30968ac246d3adb6405b36 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Wed, 19 Mar 2025 09:34:50 +0100 Subject: [PATCH 311/427] [Serializer] Fix namespace --- serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer.rst b/serializer.rst index 1c30ad89c6c..7f2569eb104 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1421,7 +1421,7 @@ like: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; From d009744f9140c536a5ae3b4a578f7780fb53771a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 19 Mar 2025 09:58:18 +0100 Subject: [PATCH 312/427] Tweaks --- components/options_resolver.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 5063f5b11d9..6f3a6751f28 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -688,13 +688,13 @@ default value:: .. deprecated:: 7.3 - Defining nested option via :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefault` - was deprecated since Symfony 7.3, use the :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setOptions` - instead. Allowing to define default values for prototyped options. + Defining nested options via :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefault` + is deprecated since Symfony 7.3. Use the :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setOptions` + method instead, which also allows defining default values for prototyped options. .. versionadded:: 7.3 - The :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setOptions` was introduced in Symfony 7.3. + The ``setOptions()`` method was introduced in Symfony 7.3. Nested options also support required options, validation (type, value) and normalization of their values. If the default value of a nested option depends From c2b17b0f1bbaa0be008cd400757863862c186ae6 Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Wed, 19 Mar 2025 16:34:54 +0100 Subject: [PATCH 313/427] alias ref in autowiring doc --- service_container/autowiring.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index c711f86ecf1..ec25f2d7dae 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -408,8 +408,8 @@ Suppose you create a second class - ``UppercaseTransformer`` that implements If you register this as a service, you now have *two* services that implement the ``App\Util\TransformerInterface`` type. Autowiring subsystem can not decide which one to use. Remember, autowiring isn't magic; it looks for a service -whose id matches the type-hint. So you need to choose one by creating an alias -from the type to the correct service id (see :ref:`autowiring-interface-alias`). +whose id matches the type-hint. So you need to choose one by :ref:`creating an alias +` from the type to the correct service id. Additionally, you can define several named autowiring aliases if you want to use one implementation in some cases, and another implementation in some other cases. From 1b09d4c56c5d47cc928a49c249c5abc97457b282 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Wed, 19 Mar 2025 01:49:32 +0100 Subject: [PATCH 314/427] [Serializer] Document named serializers --- serializer.rst | 249 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) diff --git a/serializer.rst b/serializer.rst index 605946956ac..5f9144abae0 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1537,6 +1537,255 @@ like: PropertyNormalizer::NORMALIZE_VISIBILITY => PropertyNormalizer::NORMALIZE_PUBLIC | PropertyNormalizer::NORMALIZE_PROTECTED, ]); +Named Serializers +----------------- + +.. versionadded:: 7.2 + + Named serializers were introduced in Symfony 7.2. + +Sometimes, you may need multiple configurations for the serializer, such +as different default contexts, name converters, or sets of normalizers and +encoders, depending on the use case. For example, when your application +communicates with multiple APIs, each with its own set of rules. + +This can be achieved by configuring multiple instances of the serializer +using the ``named_serializers`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/serializer.yaml + framework: + serializer: + named_serializers: + api_client1: + name_converter: 'serializer.name_converter.camel_case_to_snake_case' + default_context: + enable_max_depth: true + api_client2: + default_context: + enable_max_depth: false + + .. code-block:: xml + + + + + + + + + + + true + + + + + + false + + + + + + + + .. code-block:: php + + // config/packages/serializer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework): void { + $framework->serializer() + ->namedSerializer('api_client1') + ->nameConverter('serializer.name_converter.camel_case_to_snake_case') + ->defaultContext([ + 'enable_max_depth' => true, + ]) + ; + $framework->serializer() + ->namedSerializer('api_client2') + ->defaultContext([ + 'enable_max_depth' => false, + ]) + ; + }; + +You can inject these different serializer instances +using :ref:`named aliases `:: + + namespace App\Controller; + + // ... + use Symfony\Component\DependencyInjection\Attribute\Target; + + class PersonController extends AbstractController + { + public function index( + SerializerInterface $serializer, // Default serializer + SerializerInterface $apiClient1Serializer, // api_client1 serializer + #[Target('apiClient2.serializer')] // api_client2 serializer + SerializerInterface $customName, + ) { + // ... + } + } + +Named serializers are configured with the default set of normalizers and encoders. + +You can register additional normalizers and encoders with a specific named +serializer by adding a ``serializer`` attribute to +the :ref:`serializer.normalizer ` +or :ref:`serializer.encoder ` tags: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + # ... + + Symfony\Component\Serializer\Normalizer\CustomNormalizer: + # Prevent this normalizer from automatically being included in the default serializer + autoconfigure: false + tags: + # Include this normalizer in a single serializer + - serializer.normalizer: { serializer: 'api_client1' } + # Include this normalizer in multiple serializers + - serializer.normalizer: { serializer: [ 'api_client1', 'api_client2' ] } + # Include this normalizer in all serializers (including the default one) + - serializer.normalizer: { serializer: '*' } + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\Serializer\Normalizer\CustomNormalizer; + + return function(ContainerConfigurator $container) { + // ... + + $services->set(CustomNormalizer::class) + // Prevent this normalizer from automatically being included in the default serializer + ->autoconfigure(false) + + // Include this normalizer in a single serializer + ->tag('serializer.normalizer', ['serializer' => 'api_client1']) + // Include this normalizer in multiple serializers + ->tag('serializer.normalizer', ['serializer' => ['api_client1', 'api_client2']]) + // Include this normalizer in all serializers (including the default one) + ->tag('serializer.normalizer', ['serializer' => '*']) + ; + }; + +When the ``serializer`` attribute is not set, the service is registered with +the default serializer. + +Each normalizer and encoder used in a named serializer is tagged with +a ``serializer.normalizer.`` or ``serializer.encoder.`` tag, +which can be used to list their priorities using the following command: + +.. code-block:: terminal + + $ php bin/console debug:container --tag serializer.. + +Additionally, you can exclude the default set of normalizers and encoders by +setting the ``include_built_in_normalizers`` and ``include_built_in_encoders`` +options to ``false``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/serializer.yaml + framework: + serializer: + named_serializers: + api_client1: + include_built_in_normalizers: false + include_built_in_encoders: true + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/serializer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework): void { + $framework->serializer() + ->namedSerializer('api_client1') + ->includeBuiltInNormalizers(false) + ->includeBuiltInEncoders(true) + ; + }; + Debugging the Serializer ------------------------ From fd26bacbbb4598f2f4d4f95cdd0546efe456bd58 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 20 Mar 2025 10:41:34 +0100 Subject: [PATCH 315/427] Minor tweaks --- messenger.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index 105bbaad8c9..6d1602f410c 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2314,8 +2314,8 @@ will take care of creating a new process with the parameters you passed:: } } -A static factory :method:`Symfony\\Component\\Process\\Messenger\\RunProcessMessage::fromShellCommandline` is also -available if you want to use features of your shell such as redirections or pipes:: +If you want to use shell features such as redirections or pipes, use the static +factory :method:Symfony\\Component\\Process\\Messenger\\RunProcessMessage::fromShellCommandline:: use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Process\Messenger\RunProcessMessage; @@ -2335,8 +2335,8 @@ available if you want to use features of your shell such as redirections or pipe } } -For more information, see the -dedicated :ref:`Using Features From the OS Shell ` documentation. +For more information, read the documentation about +:ref:`using features from the OS shell `. .. versionadded:: 7.3 From 081a975430c701cff5d876f3e4d962fd794953c6 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 20 Mar 2025 21:15:48 +0100 Subject: [PATCH 316/427] [TypeInfo] Add TypeFactoryTrait::fromValue method --- components/type_info.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/type_info.rst b/components/type_info.rst index b97fbf4cc8b..5418c765ce7 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -36,10 +36,15 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: Type::generic(Type::object(Collection::class), Type::int()); Type::list(Type::bool()); Type::intersection(Type::object(\Stringable::class), Type::object(\Iterator::class)); + Type::fromValue(1.1) // same as Type::float() // Many others are available and can be // found in Symfony\Component\TypeInfo\TypeFactoryTrait +.. versionadded:: 7.3 + + The ``fromValue()`` method was introduced in Symfony 7.3. + Resolvers ~~~~~~~~~ From d873aec48150e48f16afb2fa70b1a531c6827c85 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 20 Mar 2025 22:38:11 +0100 Subject: [PATCH 317/427] Document supported types #[MapQueryParameter] --- controller.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/controller.rst b/controller.rst index 3d4f84b4888..f09769ebc02 100644 --- a/controller.rst +++ b/controller.rst @@ -367,6 +367,16 @@ attribute, arguments of your controller's action can be automatically fulfilled: // ... } +:class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter` support +arguments of type: + +- ``string`` +- ``int`` +- ``float`` +- ``bool`` +- ``array`` +- ``\BackedEnum`` + ``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the `Validate Filters`_ constants defined in PHP:: From 005ad0266ce29494e1fa89df0b5fdb3596fb459f Mon Sep 17 00:00:00 2001 From: MrYamous Date: Fri, 21 Mar 2025 07:01:55 +0100 Subject: [PATCH 318/427] refer TypeFactoryTrait to github file --- components/type_info.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index 2a92a3db63e..3d1aa569fec 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -37,8 +37,8 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: Type::list(Type::bool()); Type::intersection(Type::object(\Stringable::class), Type::object(\Iterator::class)); - // Many others are available and can be - // found in Symfony\Component\TypeInfo\TypeFactoryTrait +Many others methods are available and can be found +in :class:`Symfony\\Component\\TypeInfo\\TypeFactoryTrait`. Resolvers ~~~~~~~~~ From 8967cd3617dfd0fd3be2f7f00b97b50e5f1b0060 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 21 Mar 2025 09:11:31 +0100 Subject: [PATCH 319/427] Reword --- components/type_info.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index 5418c765ce7..25d654995e0 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -36,10 +36,12 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: Type::generic(Type::object(Collection::class), Type::int()); Type::list(Type::bool()); Type::intersection(Type::object(\Stringable::class), Type::object(\Iterator::class)); - Type::fromValue(1.1) // same as Type::float() + // ... and more methods defined in Symfony\Component\TypeInfo\TypeFactoryTrait - // Many others are available and can be - // found in Symfony\Component\TypeInfo\TypeFactoryTrait + // you can also use a generic method that detects the type automatically + Type::fromValue(1.1) // same as Type::float() + Type::fromValue('...') // same as Type::string() + Type::fromValue(false) // same as Type::false() .. versionadded:: 7.3 From 0772b75238fbc4523113d97581400833fa570eca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 21 Mar 2025 09:20:30 +0100 Subject: [PATCH 320/427] Reword --- controller.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/controller.rst b/controller.rst index f09769ebc02..a198a6c9018 100644 --- a/controller.rst +++ b/controller.rst @@ -367,15 +367,14 @@ attribute, arguments of your controller's action can be automatically fulfilled: // ... } -:class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter` support -arguments of type: - -- ``string`` -- ``int`` -- ``float`` -- ``bool`` -- ``array`` -- ``\BackedEnum`` +The ``MapQueryParameter`` attribute supports the following argument types: + +* ``\BackedEnum`` +* ``array`` +* ``bool`` +* ``float`` +* ``int`` +* ``string`` ``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the `Validate Filters`_ constants defined in PHP:: From 006b41e3f87536a2f57accf755bb8b06225bb24c Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Fri, 21 Mar 2025 09:23:37 +0100 Subject: [PATCH 321/427] Update type_info.rst --- components/type_info.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/type_info.rst b/components/type_info.rst index 25d654995e0..7f767c1149e 100644 --- a/components/type_info.rst +++ b/components/type_info.rst @@ -39,9 +39,9 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following:: // ... and more methods defined in Symfony\Component\TypeInfo\TypeFactoryTrait // you can also use a generic method that detects the type automatically - Type::fromValue(1.1) // same as Type::float() - Type::fromValue('...') // same as Type::string() - Type::fromValue(false) // same as Type::false() + Type::fromValue(1.1); // same as Type::float() + Type::fromValue('...'); // same as Type::string() + Type::fromValue(false); // same as Type::false() .. versionadded:: 7.3 From 2243ab9246cb22dfe571f262ac30698d897b1585 Mon Sep 17 00:00:00 2001 From: Florian Cellier Date: Fri, 21 Mar 2025 12:37:40 +0100 Subject: [PATCH 322/427] doc: Add doc for option `--dry-run` for the command `importmap:require` of the AssetMapper component --- frontend/asset_mapper.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index d68c77c0105..2354485a2bf 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -215,6 +215,11 @@ to add any `npm package`_: $ php bin/console importmap:require bootstrap +.. tip:: + + The command takes the well-know ``--dry-run`` option to simulate the installation of the packages, useful + to show what will be installed without altering anything. + This adds the ``bootstrap`` package to your ``importmap.php`` file:: // importmap.php From 4372e674fa7f62efb1cc161dee39b6faf6508ac3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 21 Mar 2025 15:09:40 +0100 Subject: [PATCH 323/427] Update the doc builder dependencies --- _build/composer.json | 6 +- _build/composer.lock | 157 ++++++++++++++++++++++--------------------- 2 files changed, 83 insertions(+), 80 deletions(-) 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 a30ed16776b..b9a4646f8ae 100644 --- a/_build/composer.lock +++ b/_build/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6524e63395216a3a297f1c78c7f39d86", + "content-hash": "e38eca557458275428db96db370d2c74", "packages": [ { "name": "doctrine/event-manager", @@ -420,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" @@ -468,9 +468,9 @@ "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", @@ -568,20 +568,20 @@ }, { "name": "symfony/css-selector", - "version": "v6.4.13", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e" + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/cb23e97813c5837a041b73a6d63a9ddff0778f5e", - "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -613,7 +613,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.13" + "source": "https://github.com/symfony/css-selector/tree/v7.2.0" }, "funding": [ { @@ -629,7 +629,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:18:03+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/deprecation-contracts", @@ -700,26 +700,26 @@ }, { "name": "symfony/dom-crawler", - "version": "v6.4.19", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "19073e3e0bb50cbc1cb286077069b3107085206f" + "reference": "19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/19073e3e0bb50cbc1cb286077069b3107085206f", - "reference": "19073e3e0bb50cbc1cb286077069b3107085206f", + "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|^7.0" + "symfony/css-selector": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -747,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.4.19" + "source": "https://github.com/symfony/dom-crawler/tree/v7.2.4" }, "funding": [ { @@ -763,29 +763,29 @@ "type": "tidelift" } ], - "time": "2025-02-14T17:58:34+00:00" + "time": "2025-02-17T15:53:07+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.13", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", - "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", + "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": "^5.4|^6.4|^7.0" + "symfony/process": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -813,7 +813,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.13" + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" }, "funding": [ { @@ -829,27 +829,27 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:07:50+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/finder", - "version": "v6.4.17", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", - "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", + "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|^7.0" + "symfony/filesystem": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -877,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.4.17" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -893,32 +893,33 @@ "type": "tidelift" } ], - "time": "2024-12-29T13:51:37+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.19", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "3294a433fc9d12ae58128174896b5b1822c28dad" + "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/3294a433fc9d12ae58128174896b5b1822c28dad", - "reference": "3294a433fc9d12ae58128174896b5b1822c28dad", + "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.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.3" + "symfony/http-foundation": "<6.4" }, "provide": { "php-http/async-client-implementation": "*", @@ -927,19 +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|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "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": { @@ -970,7 +972,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.19" + "source": "https://github.com/symfony/http-client/tree/v7.2.4" }, "funding": [ { @@ -986,7 +988,7 @@ "type": "tidelift" } ], - "time": "2025-02-13T09:55:13+00:00" + "time": "2025-02-13T10:27:23+00:00" }, { "name": "symfony/http-client-contracts", @@ -1530,20 +1532,20 @@ }, { "name": "symfony/string", - "version": "v6.4.15", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "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", @@ -1553,11 +1555,12 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^7.0", + "symfony/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": "^5.4|^6.0|^7.0" + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -1596,7 +1599,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.15" + "source": "https://github.com/symfony/string/tree/v7.2.0" }, "funding": [ { @@ -1612,7 +1615,7 @@ "type": "tidelift" } ], - "time": "2024-11-13T13:31:12+00:00" + "time": "2024-11-13T13:31:26+00:00" }, { "name": "symfony/translation-contracts", @@ -1779,11 +1782,11 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=8.1" + "php": ">=8.3" }, "platform-dev": {}, "platform-overrides": { - "php": "8.1.0" + "php": "8.3" }, "plugin-api-version": "2.6.0" } From d802769826898db0def76c0cf1814c9b57b3033e Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Fri, 21 Mar 2025 17:32:40 +0100 Subject: [PATCH 324/427] [Security]: Removing duplicate sentence Page: https://symfony.com/doc/6.4/security.html#the-firewall Namely: > Here, all real URLs are handled by the ``main`` firewall (no ``pattern`` key means it matches *all* URLs). --- security.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/security.rst b/security.rst index b725672dd5f..5fff8725f93 100644 --- a/security.rst +++ b/security.rst @@ -575,7 +575,8 @@ Only one firewall is active on each request: Symfony uses the ``pattern`` key to find the first match (you can also :doc:`match by host or other things `). Here, all real URLs are handled by the ``main`` firewall (no ``pattern`` key means -it matches *all* URLs). +it matches *all* URLs). A firewall can have many modes of authentication, +in other words, it enables many ways to ask the question "Who are you?". The ``dev`` firewall is really a fake firewall: it makes sure that you don't accidentally block Symfony's dev tools - which live under URLs like @@ -630,10 +631,6 @@ don't accidentally block Symfony's dev tools - which live under URLs like The feature to use an array of regex was introduced in Symfony 6.4. -All *real* URLs are handled by the ``main`` firewall (no ``pattern`` key means -it matches *all* URLs). A firewall can have many modes of authentication, -in other words, it enables many ways to ask the question "Who are you?". - Often, the user is unknown (i.e. not logged in) when they first visit your website. If you visit your homepage right now, you *will* have access and you'll see that you're visiting a page behind the firewall in the toolbar: From 981b4e6fa1b9c8ad78b1dd349e666f53ceb56803 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 21 Mar 2025 17:51:46 +0100 Subject: [PATCH 325/427] Reword --- security.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/security.rst b/security.rst index 5fff8725f93..fc0cf9c9377 100644 --- a/security.rst +++ b/security.rst @@ -575,8 +575,7 @@ Only one firewall is active on each request: Symfony uses the ``pattern`` key to find the first match (you can also :doc:`match by host or other things `). Here, all real URLs are handled by the ``main`` firewall (no ``pattern`` key means -it matches *all* URLs). A firewall can have many modes of authentication, -in other words, it enables many ways to ask the question "Who are you?". +it matches *all* URLs). The ``dev`` firewall is really a fake firewall: it makes sure that you don't accidentally block Symfony's dev tools - which live under URLs like @@ -631,9 +630,10 @@ don't accidentally block Symfony's dev tools - which live under URLs like The feature to use an array of regex was introduced in Symfony 6.4. -Often, the user is unknown (i.e. not logged in) when they first visit your -website. If you visit your homepage right now, you *will* have access and -you'll see that you're visiting a page behind the firewall in the toolbar: +A firewall can have many modes of authentication, in other words, it enables many +ways to ask the question "Who are you?". Often, the user is unknown (i.e. not logged in) +when they first visit your website. If you visit your homepage right now, you *will* +have access and you'll see that you're visiting a page behind the firewall in the toolbar: .. image:: /_images/security/anonymous_wdt.png :alt: The Symfony profiler toolbar where the Security information shows "Authenticated: no" and "Firewall name: main" From 929ffc2b883af40fb5c2b681ee822275ad6e4710 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Fri, 21 Mar 2025 20:34:37 +0100 Subject: [PATCH 326/427] [Security] Chain Providers: Fixing PHP code sample Page: https://symfony.com/doc/6.4/security/user_providers.html#security-chain-user-provider When passing in the variables, I got: > Cannot use values of type "Symfony\Config\Security\ProviderConfig\EntityConfig" in service configuration files in .../config/packages/security.php (which is being imported from ".../src/Kernel.php"). --- security/user_providers.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/security/user_providers.rst b/security/user_providers.rst index 09d47c270f2..7e9de36eff1 100644 --- a/security/user_providers.rst +++ b/security/user_providers.rst @@ -347,23 +347,23 @@ providers until the user is found: return static function (SecurityConfig $security): void { // ... - $backendProvider = $security->provider('backend_users') + $security->provider('backend_users') ->ldap() // ... ; - $legacyProvider = $security->provider('legacy_users') + $security->provider('legacy_users') ->entity() // ... ; - $userProvider = $security->provider('users') + $security->provider('users') ->entity() // ... ; - $allProviders = $security->provider('all_users')->chain() - ->providers([$backendProvider, $legacyProvider, $userProvider]) + $security->provider('all_users')->chain() + ->providers(['backend_users', 'legacy_users', 'users']) ; }; From 20929b4a573a5cbf7bd344ffa2d08dece074a848 Mon Sep 17 00:00:00 2001 From: Julien Bonnier Date: Sat, 22 Mar 2025 12:13:55 -0400 Subject: [PATCH 327/427] fix: Change translation domain name for bundle translation and add an example --- bundles/best_practices.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 376984388db..37dc386b8e4 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -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 ------------- From 78eaf0d0715259cdc4c212b277861296ba552c0e Mon Sep 17 00:00:00 2001 From: Lucas Mlsna Date: Sat, 22 Mar 2025 23:33:16 -0500 Subject: [PATCH 328/427] Update micro_kernel_trait.rst Yielded classes in registerBundles() function example code require "new" keyword to work. Also removed getLogDir() and getCacheDir() functions in example code (these functions are already defined in an identical way by the parent class). --- configuration/micro_kernel_trait.rst | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 62e8c2d4128..dbe8d1b27b9 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -260,11 +260,11 @@ Now it looks like this:: public function registerBundles(): iterable { - yield FrameworkBundle(); - yield TwigBundle(); + yield new FrameworkBundle(); + yield new TwigBundle(); if ('dev' === $this->getEnvironment()) { - yield WebProfilerBundle(); + yield new WebProfilerBundle(); } } @@ -305,18 +305,6 @@ Now it looks like this:: // (use 'annotation' as the second argument if you define routes as annotations) $routes->import(__DIR__.'/Controller/', 'attribute'); } - - // optional, to use the standard Symfony cache directory - public function getCacheDir(): string - { - return __DIR__.'/../var/cache/'.$this->getEnvironment(); - } - - // optional, to use the standard Symfony logs directory - public function getLogDir(): string - { - return __DIR__.'/../var/log'; - } } Before continuing, run this command to add support for the new dependencies: From 0bf6bc3bd0ec2c9a806384e06b90a78fde226522 Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Sun, 23 Mar 2025 14:39:47 -0300 Subject: [PATCH 329/427] Fix documentation on router method option usage --- routing.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/routing.rst b/routing.rst index 68d6a30fc41..445f4a4d886 100644 --- a/routing.rst +++ b/routing.rst @@ -442,9 +442,6 @@ evaluates them: $ php bin/console debug:router --method=GET $ php bin/console debug:router --method=ANY - # pass the option more than once to display the routes that match all the given methods - $ php bin/console debug:router --method=GET --method=PATCH - .. versionadded:: 7.3 The ``--method`` option was introduced in Symfony 7.3. From 2a2faa4f4689920cbade1fc1867e9f5e587794c7 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 20 Mar 2025 22:45:30 +0100 Subject: [PATCH 330/427] [HttpKernel] Support Uid in #[MapQueryParameter] --- controller.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/controller.rst b/controller.rst index b33eed08360..693784885da 100644 --- a/controller.rst +++ b/controller.rst @@ -371,6 +371,11 @@ The ``MapQueryParameter`` attribute supports the following argument types: * ``float`` * ``int`` * ``string`` +* Objects that extend :class:`Symfony\\Component\\Uid\\AbstractUid` + +.. versionadded:: 7.3 + + The support of ``AbstractUid`` was introduced in Symfony 7.3. ``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the `Validate Filters`_ constants defined in PHP:: From 996f3d374d798c1b5d76916018ba8aa9186681b5 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 20 Mar 2025 21:53:05 +0100 Subject: [PATCH 331/427] [Serializer] Add NumberNormalizer --- serializer.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/serializer.rst b/serializer.rst index 7f2f7d7c2f1..18f1b06b92c 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1387,6 +1387,14 @@ normalizers (in order of priority): By default, an exception is thrown when data is not a valid backed enumeration. If you want ``null`` instead, you can set the ``BackedEnumNormalizer::ALLOW_INVALID_VALUES`` option. +:class:`Symfony\\Component\\Serializer\\Normalizer\\NumberNormalizer` + This normalizer converts between :phpclass:`BcMath\Number` or :phpclass:`GMP` objects and + strings or integers. + +.. versionadded:: 7.2 + + The ``NumberNormalizer`` was introduced in Symfony 7.2. + :class:`Symfony\\Component\\Serializer\\Normalizer\\DataUriNormalizer` This normalizer converts between :phpclass:`SplFileInfo` objects and a `data URI`_ string (``data:...``) such that files can be embedded into From e24fb9a8b3176f6b07ed23c72df57a8742610001 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Sun, 23 Mar 2025 19:19:44 +0100 Subject: [PATCH 332/427] [Scheduler] Add MessageHandler result to the PostRunEvent --- scheduler.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scheduler.rst b/scheduler.rst index 0c6c14915c7..64a5a9f7612 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -723,10 +723,15 @@ after a message is consumed:: $schedule = $event->getSchedule(); $context = $event->getMessageContext(); $message = $event->getMessage(); + $result = $event->getResult(); - // do something with the schedule, context or message + // do something with the schedule, context, message or result } +.. versionadded:: 7.3 + + The ``getResult()`` method was introduced in Symfony 7.3. + Execute this command to find out which listeners are registered for this event and their priorities: From b67e277663beeb002583b470cd01670d4292621c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 24 Mar 2025 09:19:44 +0100 Subject: [PATCH 333/427] Minor tweak --- configuration/micro_kernel_trait.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index dbe8d1b27b9..f919b1f7a74 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -305,6 +305,9 @@ Now it looks like this:: // (use 'annotation' as the second argument if you define routes as annotations) $routes->import(__DIR__.'/Controller/', 'attribute'); } + + // optionally, you can define the getCacheDir() and getLogDir() methods + // to override the default locations for these directories } Before continuing, run this command to add support for the new dependencies: From b95b1041d2840213468e1714d4a0d09cc39a9273 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Mon, 24 Mar 2025 11:41:00 +0300 Subject: [PATCH 334/427] Update custom_normalizer.rst --- serializer/custom_normalizer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serializer/custom_normalizer.rst b/serializer/custom_normalizer.rst index d6ba66f89b6..8072b590ced 100644 --- a/serializer/custom_normalizer.rst +++ b/serializer/custom_normalizer.rst @@ -33,9 +33,9 @@ to customize the normalized data. To do that, leverage the ``ObjectNormalizer``: ) { } - public function normalize($topic, ?string $format = null, array $context = []): array + public function normalize(mixed $object, ?string $format = null, array $context = []): array { - $data = $this->normalizer->normalize($topic, $format, $context); + $data = $this->normalizer->normalize($object, $format, $context); // Here, add, edit, or delete some data: $data['href']['self'] = $this->router->generate('topic_show', [ From d9a48bea00bb340b407402a3f6ada1a265e5eba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 21 Mar 2025 03:23:02 +0100 Subject: [PATCH 335/427] [Console] Document the `TreeHelper` --- components/console/helpers/map.rst.inc | 1 + components/console/helpers/tree.rst | 237 +++++++++++++++++++++++++ console/style.rst | 26 +++ 3 files changed, 264 insertions(+) create mode 100644 components/console/helpers/tree.rst diff --git a/components/console/helpers/map.rst.inc b/components/console/helpers/map.rst.inc index 8f9ce0ca0f3..b190d1dce44 100644 --- a/components/console/helpers/map.rst.inc +++ b/components/console/helpers/map.rst.inc @@ -3,5 +3,6 @@ * :doc:`/components/console/helpers/progressbar` * :doc:`/components/console/helpers/questionhelper` * :doc:`/components/console/helpers/table` +* :doc:`/components/console/helpers/tree` * :doc:`/components/console/helpers/debug_formatter` * :doc:`/components/console/helpers/cursor` diff --git a/components/console/helpers/tree.rst b/components/console/helpers/tree.rst new file mode 100644 index 00000000000..2e688770c65 --- /dev/null +++ b/components/console/helpers/tree.rst @@ -0,0 +1,237 @@ +Tree Helper +=========== + +The Tree Helper allows you to build and display tree structures in the console. + +.. versionadded:: 7.3 + + The ``TreeHelper`` class was introduced in Symfony 7.3. + +Rendering a Tree +---------------- + +The :method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` method creates a tree structure from an array and returns a :class:`Symfony\\Component\\Console\\Helper\\Tree` +object that can be rendered in the console. + +Building a Tree from an Array +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can build a tree from an array by passing the array to the :method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` +method:: + + use Symfony\Component\Console\Helper\TreeHelper; + + $tree = TreeHelper::createTree($io, null, [ + 'src' => [ + 'Command', + 'Controller' => [ + 'DefaultController.php', + ], + 'Kernel.php', + ], + 'templates' => [ + 'base.html.twig', + ], + ]); + + $tree->render(); + +The above code will output the following tree: + +.. code-block:: text + + ├── src + │ ├── Command + │ ├── Controller + │ │ └── DefaultController.php + │ └── Kernel.php + └── templates + └── base.html.twig + +Manually Creating a Tree +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can manually create a tree by creating a new instance of the :class:`Symfony\\Component\\Console\\Helper\\Tree` class and adding nodes to it:: + + use Symfony\Component\Console\Helper\TreeHelper; + use Symfony\Component\Console\Helper\TreeNode; + + $node = TreeNode::fromValues([ + 'Command', + 'Controller' => [ + 'DefaultController.php', + ], + 'Kernel.php', + ]); + $node->addChild('templates'); + $node->addChild('tests'); + + $tree = TreeHelper::createTree($io, $node); + $tree->render(); + +Customizing the Tree Style +-------------------------- + +Built-in Tree Styles +~~~~~~~~~~~~~~~~~~~~ + +The tree helper provides a few built-in styles that you can use to customize the output of the tree. + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::default` + + .. code-block:: text + + ├── config + │ ├── packages + │ └── routes + │ ├── framework.yaml + │ └── web_profiler.yaml + ├── src + │ ├── Command + │ ├── Controller + │ │ └── DefaultController.php + │ └── Kernel.php + └── templates + └── base.html.twig + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::box` + + .. code-block:: text + + ┃╸ config + ┃ ┃╸ packages + ┃ ┗╸ routes + ┃ ┃╸ framework.yaml + ┃ ┗╸ web_profiler.yaml + ┃╸ src + ┃ ┃╸ Command + ┃ ┃╸ Controller + ┃ ┃ ┗╸ DefaultController.php + ┃ ┗╸ Kernel.php + ┗╸ templates + ┗╸ base.html.twig + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::doubleBox` + + .. code-block:: text + + ╠═ config + ║ ╠═ packages + ║ ╚═ routes + ║ ╠═ framework.yaml + ║ ╚═ web_profiler.yaml + ╠═ src + ║ ╠═ Command + ║ ╠═ Controller + ║ ║ ╚═ DefaultController.php + ║ ╚═ Kernel.php + ╚═ templates + ╚═ base.html.twig + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::compact` + + .. code-block:: text + + ├ config + │ ├ packages + │ └ routes + │ ├ framework.yaml + │ └ web_profiler.yaml + ├ src + │ ├ Command + │ ├ Controller + │ │ └ DefaultController.php + │ └ Kernel.php + └ templates + └ base.html.twig + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::light` + + .. code-block:: text + + |-- config + | |-- packages + | `-- routes + | |-- framework.yaml + | `-- web_profiler.yaml + |-- src + | |-- Command + | |-- Controller + | | `-- DefaultController.php + | `-- Kernel.php + `-- templates + `-- base.html.twig + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::minimal` + + .. code-block:: text + + . config + . . packages + . . routes + . . framework.yaml + . . web_profiler.yaml + . src + . . Command + . . Controller + . . . DefaultController.php + . . Kernel.php + . templates + . base.html.twig + +:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::rounded` + + .. code-block:: text + + ├─ config + │ ├─ packages + │ ╰─ routes + │ ├─ framework.yaml + │ ╰─ web_profiler.yaml + ├─ src + │ ├─ Command + │ ├─ Controller + │ │ ╰─ DefaultController.php + │ ╰─ Kernel.php + ╰─ templates + ╰─ base.html.twig + +Making a Custom Tree Style +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can create your own tree style by passing the characters to the constructor +of the :class:`Symfony\\Component\\Console\\Helper\\TreeStyle` class:: + + use Symfony\Component\Console\Helper\TreeHelper; + use Symfony\Component\Console\Helper\TreeStyle; + + $customStyle = new TreeStyle('🟣 ', '🟠 ', '🔵 ', '🟢 ', '🔴 ', '🟡 '); + + // Pass the custom style to the createTree method + + $tree = TreeHelper::createTree($io, null, [ + 'src' => [ + 'Command', + 'Controller' => [ + 'DefaultController.php', + ], + 'Kernel.php', + ], + 'templates' => [ + 'base.html.twig', + ], + ], $customStyle); + + $tree->render(); + +The above code will output the following tree: + +.. code-block:: text + + 🔵 🟣 🟡 src + 🔵 🟢 🟣 🟡 Command + 🔵 🟢 🟣 🟡 Controller + 🔵 🟢 🟢 🟠 🟡 DefaultController.php + 🔵 🟢 🟠 🟡 Kernel.php + 🔵 🟠 🟡 templates + 🔵 🔴 🟠 🟡 base.html.twig diff --git a/console/style.rst b/console/style.rst index 0aaaa3f675e..e1e5df38ffe 100644 --- a/console/style.rst +++ b/console/style.rst @@ -169,6 +169,32 @@ Content Methods styled according to the Symfony Style Guide, which allows you to use features such as dynamically appending rows. +:method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::tree` + It displays the given nested array as a formatted directory/file tree + structure in the console output:: + + $io->tree([ + 'src' => [ + 'Controller' => [ + 'DefaultController.php', + ], + 'Kernel.php', + ], + 'templates' => [ + 'base.html.twig', + ], + ]); + +.. versionadded:: 7.3 + + The ``SymfonyStyle::tree()`` and the ``SymfonyStyle::createTree()`` methods + were introduced in Symfony 7.3. + +:method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::createTree` + Creates an instance of :class:`Symfony\\Component\\Console\\Helper\\TreeHelper` + styled according to the Symfony Style Guide, which allows you to use + features such as dynamically nesting nodes. + :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::newLine` It displays a blank line in the command output. Although it may seem useful, most of the times you won't need it at all. The reason is that every helper From a0758ac62303e037fb903ba59fe807fd798f561d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 24 Mar 2025 09:52:46 +0100 Subject: [PATCH 336/427] Tweaks --- components/console/helpers/tree.rst | 86 +++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/components/console/helpers/tree.rst b/components/console/helpers/tree.rst index 2e688770c65..4203f8bc790 100644 --- a/components/console/helpers/tree.rst +++ b/components/console/helpers/tree.rst @@ -2,6 +2,8 @@ Tree Helper =========== The Tree Helper allows you to build and display tree structures in the console. +It's commonly used to render directory hierarchies, but you can also use it to render +any tree-like content, such us organizational charts, product category trees, taxonomies, etc. .. versionadded:: 7.3 @@ -10,16 +12,62 @@ The Tree Helper allows you to build and display tree structures in the console. Rendering a Tree ---------------- -The :method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` method creates a tree structure from an array and returns a :class:`Symfony\\Component\\Console\\Helper\\Tree` +The :method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` method +creates a tree structure from an array and returns a :class:`Symfony\\Component\\Console\\Helper\\Tree` object that can be rendered in the console. -Building a Tree from an Array -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Rendering a Tree from an Array +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can build a tree from an array by passing the array to the +:method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` method +inside your console command:: -You can build a tree from an array by passing the array to the :method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` -method:: + namespace App\Command; + use Symfony\Component\Console\Attribute\AsCommand; + use Symfony\Component\Console\Command\Command; + use Symfony\Component\Console\Input\InputInterface; + use Symfony\Component\Console\Output\OutputInterface; + use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Helper\TreeHelper; + use Symfony\Component\Console\Helper\TreeNode; + + #[AsCommand(name: 'app:some-command', description: '...')] + class SomeCommand extends Command + { + // ... + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $node = TreeNode::fromValues([ + 'config/', + 'public/', + 'src/', + 'templates/', + 'tests/', + ]); + + $tree = TreeHelper::createTree($io, $node); + $tree->render(); + + // ... + } + } + +This exampe would output the following: + +.. code-block:: terminal + + ├── config/ + ├── public/ + ├── src/ + ├── templates/ + └── tests/ + +The given contents can be defined in a multi-dimensional array: $tree = TreeHelper::createTree($io, null, [ 'src' => [ @@ -38,7 +86,7 @@ method:: The above code will output the following tree: -.. code-block:: text +.. code-block:: terminal ├── src │ ├── Command @@ -48,10 +96,11 @@ The above code will output the following tree: └── templates └── base.html.twig -Manually Creating a Tree -~~~~~~~~~~~~~~~~~~~~~~~~ +Building and Rendering a Tree +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can manually create a tree by creating a new instance of the :class:`Symfony\\Component\\Console\\Helper\\Tree` class and adding nodes to it:: +You can build a tree by creating a new instance of the +:class:`Symfony\\Component\\Console\\Helper\\Tree` class and adding nodes to it:: use Symfony\Component\Console\Helper\TreeHelper; use Symfony\Component\Console\Helper\TreeNode; @@ -75,11 +124,12 @@ Customizing the Tree Style Built-in Tree Styles ~~~~~~~~~~~~~~~~~~~~ -The tree helper provides a few built-in styles that you can use to customize the output of the tree. +The tree helper provides a few built-in styles that you can use to customize the +output of the tree. :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::default` - .. code-block:: text + .. code-block:: terminal ├── config │ ├── packages @@ -96,7 +146,7 @@ The tree helper provides a few built-in styles that you can use to customize the :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::box` - .. code-block:: text + .. code-block:: terminal ┃╸ config ┃ ┃╸ packages @@ -113,7 +163,7 @@ The tree helper provides a few built-in styles that you can use to customize the :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::doubleBox` - .. code-block:: text + .. code-block:: terminal ╠═ config ║ ╠═ packages @@ -130,7 +180,7 @@ The tree helper provides a few built-in styles that you can use to customize the :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::compact` - .. code-block:: text + .. code-block:: terminal ├ config │ ├ packages @@ -147,7 +197,7 @@ The tree helper provides a few built-in styles that you can use to customize the :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::light` - .. code-block:: text + .. code-block:: terminal |-- config | |-- packages @@ -164,7 +214,7 @@ The tree helper provides a few built-in styles that you can use to customize the :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::minimal` - .. code-block:: text + .. code-block:: terminal . config . . packages @@ -181,7 +231,7 @@ The tree helper provides a few built-in styles that you can use to customize the :method:`Symfony\\Component\\Console\\Helper\\TreeStyle::rounded` - .. code-block:: text + .. code-block:: terminal ├─ config │ ├─ packages @@ -226,7 +276,7 @@ of the :class:`Symfony\\Component\\Console\\Helper\\TreeStyle` class:: The above code will output the following tree: -.. code-block:: text +.. code-block:: terminal 🔵 🟣 🟡 src 🔵 🟢 🟣 🟡 Command From 16861e3df96cedc24460d3a134c34e7278ac8624 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 24 Mar 2025 13:14:22 +0100 Subject: [PATCH 337/427] order use statements alphabetically --- components/console/helpers/tree.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/console/helpers/tree.rst b/components/console/helpers/tree.rst index 4203f8bc790..ae0c24ff01f 100644 --- a/components/console/helpers/tree.rst +++ b/components/console/helpers/tree.rst @@ -27,11 +27,11 @@ inside your console command:: use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; + use Symfony\Component\Console\Helper\TreeHelper; + use Symfony\Component\Console\Helper\TreeNode; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; - use Symfony\Component\Console\Helper\TreeHelper; - use Symfony\Component\Console\Helper\TreeNode; #[AsCommand(name: 'app:some-command', description: '...')] class SomeCommand extends Command From bdca4e901550d29fd3ec5c38adb02365459b1460 Mon Sep 17 00:00:00 2001 From: Arnaud De Abreu Date: Mon, 24 Mar 2025 09:25:46 +0100 Subject: [PATCH 338/427] [Messenger] Add `--class-filter` option to the `messenger:failed:remove` command --- messenger.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/messenger.rst b/messenger.rst index 6d1602f410c..8632ebdb4e0 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1312,6 +1312,9 @@ to retry them: # remove all messages in the failure transport $ php bin/console messenger:failed:remove --all + # remove only MyClass messages + $ php bin/console messenger:failed:remove --class-filter='MyClass' + If the message fails again, it will be re-sent back to the failure transport due to the normal :ref:`retry rules `. Once the max retry has been hit, the message will be discarded permanently. @@ -1321,6 +1324,11 @@ retry has been hit, the message will be discarded permanently. The option to skip a message in the ``messenger:failed:retry`` command was introduced in Symfony 7.2 +.. versionadded:: 7.3 + + The option to filter by a message class in the ``messenger:failed:remove`` command was + introduced in Symfony 7.3 + Multiple Failed Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~ From da62e32f9693a21f4b3130110abf6c8e2c6beab1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 24 Mar 2025 13:56:01 +0100 Subject: [PATCH 339/427] minor --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 8632ebdb4e0..cbd79784555 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1313,7 +1313,7 @@ to retry them: $ php bin/console messenger:failed:remove --all # remove only MyClass messages - $ php bin/console messenger:failed:remove --class-filter='MyClass' + $ php bin/console messenger:failed:remove --class-filter='App\Message\MyMessage' If the message fails again, it will be re-sent back to the failure transport due to the normal :ref:`retry rules `. Once the max From a93e2656a9583fa44aa93befe0db7660c689eab1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 24 Mar 2025 13:56:46 +0100 Subject: [PATCH 340/427] minor --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index d25800ef00d..e86bc73d1c6 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1161,8 +1161,8 @@ to retry them: # see the 10 first messages $ php bin/console messenger:failed:show --max=10 - # see only MyClass messages - $ php bin/console messenger:failed:show --class-filter='MyClass' + # see only App\Message\MyMessage messages + $ php bin/console messenger:failed:show --class-filter='App\Message\MyMessage' # see the number of messages by message class $ php bin/console messenger:failed:show --stats From 137134ad97da5b2fecc4a61027c1701c50d9faff Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 24 Mar 2025 13:57:13 +0100 Subject: [PATCH 341/427] minor --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 59f2aa0cc19..0f1eba49a9f 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1312,7 +1312,7 @@ to retry them: # remove all messages in the failure transport $ php bin/console messenger:failed:remove --all - # remove only MyClass messages + # remove only App\Message\MyMessage messages $ php bin/console messenger:failed:remove --class-filter='App\Message\MyMessage' If the message fails again, it will be re-sent back to the failure transport From bc3412b33493e9a2d03a189f073a863f6030e909 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 24 Mar 2025 15:23:03 +0100 Subject: [PATCH 342/427] Fix syntax issue --- serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer.rst b/serializer.rst index 18f1b06b92c..7b42ea9485c 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1388,7 +1388,7 @@ normalizers (in order of priority): want ``null`` instead, you can set the ``BackedEnumNormalizer::ALLOW_INVALID_VALUES`` option. :class:`Symfony\\Component\\Serializer\\Normalizer\\NumberNormalizer` - This normalizer converts between :phpclass:`BcMath\Number` or :phpclass:`GMP` objects and + This normalizer converts between :phpclass:`BcMath\\Number` or :phpclass:`GMP` objects and strings or integers. .. versionadded:: 7.2 From c018ddc9c619c68c09551e21d5d4fa86d028a71f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 24 Mar 2025 16:01:48 +0100 Subject: [PATCH 343/427] Minor tweak --- controller.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller.rst b/controller.rst index 693784885da..05abdaee4ea 100644 --- a/controller.rst +++ b/controller.rst @@ -375,7 +375,7 @@ The ``MapQueryParameter`` attribute supports the following argument types: .. versionadded:: 7.3 - The support of ``AbstractUid`` was introduced in Symfony 7.3. + Support for ``AbstractUid`` objects was introduced in Symfony 7.3. ``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the `Validate Filters`_ constants defined in PHP:: From 5f722a34043d63e3f778ce4d9a485784d6879e45 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 24 Mar 2025 16:07:22 +0100 Subject: [PATCH 344/427] Add Tugdual Saunier as a core team member --- contributing/core_team.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contributing/core_team.rst b/contributing/core_team.rst index d461aa44485..2edb42a842d 100644 --- a/contributing/core_team.rst +++ b/contributing/core_team.rst @@ -86,6 +86,7 @@ Active Core Members * **Berislav Balogović** (`hypemc`_); * **Mathias Arlaud** (`mtarld`_); * **Florent Morselli** (`spomky`_); + * **Tugdual Saunier** (`tucksaun`_); * **Alexandre Daubois** (`alexandre-daubois`_). * **Security Team** (``@symfony/security`` on GitHub): @@ -263,3 +264,4 @@ discretion of the **Project Leader**. .. _`mtarld`: https://github.com/mtarld/ .. _`spomky`: https://github.com/spomky/ .. _`alexandre-daubois`: https://github.com/alexandre-daubois/ +.. _`tucksaun`: https://github.com/tucksaun/ \ No newline at end of file From ce6c3a9992c30ddef1cd27a7c1a31b81625dc939 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 24 Mar 2025 17:09:08 +0100 Subject: [PATCH 345/427] Reword --- frontend/asset_mapper.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index 2354485a2bf..8b27cd8ba16 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -217,8 +217,12 @@ to add any `npm package`_: .. tip:: - The command takes the well-know ``--dry-run`` option to simulate the installation of the packages, useful - to show what will be installed without altering anything. + Add the ``--dry-run`` option to simulate package installation without actually + making any changes (e.g. ``php bin/console importmap:require bootstrap --dry-run``) + + .. versionadded:: 7.3 + + The ``--dry-run`` option was introduced in Symfony 7.3. This adds the ``bootstrap`` package to your ``importmap.php`` file:: From 0dd6f3462e07172e8d8f7825ef0d175b62b74d85 Mon Sep 17 00:00:00 2001 From: Massimiliano Arione Date: Mon, 24 Mar 2025 17:52:45 +0100 Subject: [PATCH 346/427] document DatePointType --- components/clock.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/components/clock.rst b/components/clock.rst index 5b20e6000b9..e1a631a9548 100644 --- a/components/clock.rst +++ b/components/clock.rst @@ -269,6 +269,31 @@ timestamps:: .. _clock_writing-tests: +Storing DatePoints in Databases +------------------------------- + +If you :doc:`use Doctrine `, consider using the ``date_point`` Doctrine +type, which converts to/from ``DatePoint`` objects automatically:: + + // src/Entity/Product.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + use Symfony\Component\Clock\DatePoint; + + #[ORM\Entity] + class Product + { + #[ORM\Column] + private DatePoint $created; + + // ... + } + +.. versionadded:: 7.3 + + The `DatePointType` was introduced in Symfony 7.3. + Writing Time-Sensitive Tests ---------------------------- From 823c8432df0cd3ddd685e023ea863ab4051b71f9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 25 Mar 2025 09:58:07 +0100 Subject: [PATCH 347/427] Minor tweaks --- components/clock.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/components/clock.rst b/components/clock.rst index e1a631a9548..c4ac88e9092 100644 --- a/components/clock.rst +++ b/components/clock.rst @@ -267,13 +267,11 @@ timestamps:: :method:`Symfony\\Component\\Clock\\DatePoint::getMicrosecond` methods were introduced in Symfony 7.1. -.. _clock_writing-tests: - -Storing DatePoints in Databases -------------------------------- +Storing DatePoints in the Database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you :doc:`use Doctrine `, consider using the ``date_point`` Doctrine -type, which converts to/from ``DatePoint`` objects automatically:: +If you :doc:`use Doctrine ` to work with databases, consider using the +``date_point`` Doctrine type, which converts to/from ``DatePoint`` objects automatically:: // src/Entity/Product.php namespace App\Entity; @@ -284,15 +282,22 @@ type, which converts to/from ``DatePoint`` objects automatically:: #[ORM\Entity] class Product { + // if you don't define the Doctrine type explicitly, Symfony will autodetect it: #[ORM\Column] - private DatePoint $created; + private DatePoint $createdAt; + + // if you prefer to define the Doctrine type explicitly: + #[ORM\Column(type: 'date_point')] + private DatePoint $updatedAt; // ... } .. versionadded:: 7.3 - The `DatePointType` was introduced in Symfony 7.3. + The ``DatePointType`` was introduced in Symfony 7.3. + +.. _clock_writing-tests: Writing Time-Sensitive Tests ---------------------------- From 5844ee66a68c19bbcff3f7300756ed1df31c4c3a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 25 Mar 2025 16:39:30 +0100 Subject: [PATCH 348/427] [Console] Tweak the tree helper --- components/console/helpers/tree.rst | 250 ++++++++++++++-------------- 1 file changed, 129 insertions(+), 121 deletions(-) diff --git a/components/console/helpers/tree.rst b/components/console/helpers/tree.rst index ae0c24ff01f..1161d00e942 100644 --- a/components/console/helpers/tree.rst +++ b/components/console/helpers/tree.rst @@ -67,7 +67,7 @@ This exampe would output the following: ├── templates/ └── tests/ -The given contents can be defined in a multi-dimensional array: +The given contents can be defined in a multi-dimensional array:: $tree = TreeHelper::createTree($io, null, [ 'src' => [ @@ -125,126 +125,132 @@ Built-in Tree Styles ~~~~~~~~~~~~~~~~~~~~ The tree helper provides a few built-in styles that you can use to customize the -output of the tree. - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::default` - - .. code-block:: terminal - - ├── config - │ ├── packages - │ └── routes - │ ├── framework.yaml - │ └── web_profiler.yaml - ├── src - │ ├── Command - │ ├── Controller - │ │ └── DefaultController.php - │ └── Kernel.php - └── templates - └── base.html.twig - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::box` - - .. code-block:: terminal - - ┃╸ config - ┃ ┃╸ packages - ┃ ┗╸ routes - ┃ ┃╸ framework.yaml - ┃ ┗╸ web_profiler.yaml - ┃╸ src - ┃ ┃╸ Command - ┃ ┃╸ Controller - ┃ ┃ ┗╸ DefaultController.php - ┃ ┗╸ Kernel.php - ┗╸ templates - ┗╸ base.html.twig - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::doubleBox` - - .. code-block:: terminal - - ╠═ config - ║ ╠═ packages - ║ ╚═ routes - ║ ╠═ framework.yaml - ║ ╚═ web_profiler.yaml - ╠═ src - ║ ╠═ Command - ║ ╠═ Controller - ║ ║ ╚═ DefaultController.php - ║ ╚═ Kernel.php - ╚═ templates - ╚═ base.html.twig - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::compact` - - .. code-block:: terminal - - ├ config - │ ├ packages - │ └ routes - │ ├ framework.yaml - │ └ web_profiler.yaml - ├ src - │ ├ Command - │ ├ Controller - │ │ └ DefaultController.php - │ └ Kernel.php - └ templates - └ base.html.twig - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::light` - - .. code-block:: terminal - - |-- config - | |-- packages - | `-- routes - | |-- framework.yaml - | `-- web_profiler.yaml - |-- src - | |-- Command - | |-- Controller - | | `-- DefaultController.php - | `-- Kernel.php - `-- templates - `-- base.html.twig - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::minimal` - - .. code-block:: terminal - - . config - . . packages - . . routes - . . framework.yaml - . . web_profiler.yaml - . src - . . Command - . . Controller - . . . DefaultController.php - . . Kernel.php - . templates - . base.html.twig - -:method:`Symfony\\Component\\Console\\Helper\\TreeStyle::rounded` - - .. code-block:: terminal - - ├─ config - │ ├─ packages - │ ╰─ routes - │ ├─ framework.yaml - │ ╰─ web_profiler.yaml - ├─ src - │ ├─ Command - │ ├─ Controller - │ │ ╰─ DefaultController.php - │ ╰─ Kernel.php - ╰─ templates - ╰─ base.html.twig +output of the tree:: + + use Symfony\Component\Console\Helper\TreeStyle; + // ... + + $tree = TreeHelper::createTree($io, $node, [], TreeStyle::compact()); + $tree->render(); + +``TreeHelper::createTree($io, $node, [], TreeStyle::default())`` (`details`_) + +.. code-block:: terminal + + ├── config + │ ├── packages + │ └── routes + │ ├── framework.yaml + │ └── web_profiler.yaml + ├── src + │ ├── Command + │ ├── Controller + │ │ └── DefaultController.php + │ └── Kernel.php + └── templates + └── base.html.twig + +``TreeHelper::createTree($io, $node, [], TreeStyle::box())`` (`details`_) + +.. code-block:: terminal + + ┃╸ config + ┃ ┃╸ packages + ┃ ┗╸ routes + ┃ ┃╸ framework.yaml + ┃ ┗╸ web_profiler.yaml + ┃╸ src + ┃ ┃╸ Command + ┃ ┃╸ Controller + ┃ ┃ ┗╸ DefaultController.php + ┃ ┗╸ Kernel.php + ┗╸ templates + ┗╸ base.html.twig + +``TreeHelper::createTree($io, $node, [], TreeStyle::doubleBox())`` (`details`_) + +.. code-block:: terminal + + ╠═ config + ║ ╠═ packages + ║ ╚═ routes + ║ ╠═ framework.yaml + ║ ╚═ web_profiler.yaml + ╠═ src + ║ ╠═ Command + ║ ╠═ Controller + ║ ║ ╚═ DefaultController.php + ║ ╚═ Kernel.php + ╚═ templates + ╚═ base.html.twig + +``TreeHelper::createTree($io, $node, [], TreeStyle::compact())`` (`details`_) + +.. code-block:: terminal + + ├ config + │ ├ packages + │ └ routes + │ ├ framework.yaml + │ └ web_profiler.yaml + ├ src + │ ├ Command + │ ├ Controller + │ │ └ DefaultController.php + │ └ Kernel.php + └ templates + └ base.html.twig + +``TreeHelper::createTree($io, $node, [], TreeStyle::light())`` (`details`_) + +.. code-block:: terminal + + |-- config + | |-- packages + | `-- routes + | |-- framework.yaml + | `-- web_profiler.yaml + |-- src + | |-- Command + | |-- Controller + | | `-- DefaultController.php + | `-- Kernel.php + `-- templates + `-- base.html.twig + +``TreeHelper::createTree($io, $node, [], TreeStyle::minimal())`` (`details`_) + +.. code-block:: terminal + + . config + . . packages + . . routes + . . framework.yaml + . . web_profiler.yaml + . src + . . Command + . . Controller + . . . DefaultController.php + . . Kernel.php + . templates + . base.html.twig + +``TreeHelper::createTree($io, $node, [], TreeStyle::rounded())`` (`details`_) + +.. code-block:: terminal + + ├─ config + │ ├─ packages + │ ╰─ routes + │ ├─ framework.yaml + │ ╰─ web_profiler.yaml + ├─ src + │ ├─ Command + │ ├─ Controller + │ │ ╰─ DefaultController.php + │ ╰─ Kernel.php + ╰─ templates + ╰─ base.html.twig Making a Custom Tree Style ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -285,3 +291,5 @@ The above code will output the following tree: 🔵 🟢 🟠 🟡 Kernel.php 🔵 🟠 🟡 templates 🔵 🔴 🟠 🟡 base.html.twig + +.. _`details`: https://github.com/symfony/symfony/blob/7.3/src/Symfony/Component/Console/Helper/TreeStyle.php From 4191969aff9f5737264eb238e9403199af9f3278 Mon Sep 17 00:00:00 2001 From: Pierre Ambroise Date: Mon, 24 Mar 2025 21:17:09 +0100 Subject: [PATCH 349/427] Document log_channel --- reference/configuration/framework.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 528543a5178..7986140e050 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1025,7 +1025,7 @@ exceptions **type**: ``array`` -Defines the :ref:`log level ` and HTTP status code applied to the +Defines the :ref:`log level `, :ref:`log channel ` and HTTP status code applied to the exceptions that match the given exception class: .. configuration-block:: @@ -1038,6 +1038,7 @@ exceptions that match the given exception class: Symfony\Component\HttpKernel\Exception\BadRequestHttpException: log_level: 'debug' status_code: 422 + log_channel: 'custom_channel' .. code-block:: xml @@ -1055,6 +1056,7 @@ exceptions that match the given exception class: class="Symfony\Component\HttpKernel\Exception\BadRequestHttpException" log-level="debug" status-code="422" + log-channel="custom_channel" /> @@ -1070,9 +1072,14 @@ exceptions that match the given exception class: $framework->exception(BadRequestHttpException::class) ->logLevel('debug') ->statusCode(422) + ->logChannel('custom_channel') ; }; +.. versionadded:: 7.3 + + The ``log_channel`` option was introduced in Symfony 7.3. + The order in which you configure exceptions is important because Symfony will use the configuration of the first exception that matches ``instanceof``: From dae33e402c969606c0c6daa58d99b0caadaf749a Mon Sep 17 00:00:00 2001 From: Silas Joisten Date: Wed, 26 Mar 2025 11:10:39 +0200 Subject: [PATCH 350/427] Adds missing use statement --- routing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/routing.rst b/routing.rst index a41b9bba6a6..7d489912345 100644 --- a/routing.rst +++ b/routing.rst @@ -969,6 +969,7 @@ optional ``priority`` parameter in those routes to control their priority: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; class BlogController extends AbstractController From 6d7c87f8eaea42c26004206fd1dc465df44e29cd Mon Sep 17 00:00:00 2001 From: Oviglo Date: Mon, 24 Mar 2025 10:51:29 +0100 Subject: [PATCH 351/427] [Security] Add methods param doc for isCsrfTokenValid attribute --- security/csrf.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/security/csrf.rst b/security/csrf.rst index be8348597c7..fa15cee3db3 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -288,6 +288,15 @@ object evaluated to the id:: // ... do something, like deleting an object } +You can use the ``methods`` parameter to the attribute to specify the HTTP methods that are allowed for +the token validation, :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid` is ignored for other methods. By default, the attribute allows all methods:: + + #[IsCsrfTokenValid('delete-item', tokenKey: 'token', methods: ['DELETE'])] + public function delete(Post $post): Response + { + // ... delete the object + } + .. versionadded:: 7.1 The :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid` From 84634a2c44d66ea4931e3ab991252a8e03a3000d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 26 Mar 2025 10:31:19 +0100 Subject: [PATCH 352/427] Reword --- security/csrf.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/security/csrf.rst b/security/csrf.rst index fa15cee3db3..cc9b15253bc 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -288,8 +288,10 @@ object evaluated to the id:: // ... do something, like deleting an object } -You can use the ``methods`` parameter to the attribute to specify the HTTP methods that are allowed for -the token validation, :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid` is ignored for other methods. By default, the attribute allows all methods:: +By default, the ``IsCsrfTokenValid`` attribute performs the CSRF token check for +all HTTP methods. You can restrict this validation to specific methods using the +``methods`` parameter. If the request uses a method not listed in the ``methods`` +array, the attribute is ignored for that request, and no CSRF validation occurs:: #[IsCsrfTokenValid('delete-item', tokenKey: 'token', methods: ['DELETE'])] public function delete(Post $post): Response @@ -302,6 +304,10 @@ the token validation, :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsC The :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid` attribute was introduced in Symfony 7.1. +.. versionadded:: 7.3 + + The ``methods`` parameter was introduced in Symfony 7.3. + CSRF Tokens and Compression Side-Channel Attacks ------------------------------------------------ From 2153ebbc5dc3918794514e16004ae497a4b84cf6 Mon Sep 17 00:00:00 2001 From: Silas Joisten Date: Wed, 26 Mar 2025 11:03:49 +0200 Subject: [PATCH 353/427] Add type hint --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 7d489912345..79a513ba8dd 100644 --- a/routing.rst +++ b/routing.rst @@ -595,7 +595,7 @@ the ``{page}`` parameter using the ``requirements`` option: } #[Route('/blog/{slug}', name: 'blog_show')] - public function show($slug): Response + public function show(string $slug): Response { // ... } From 2f28d22096fab76a30caed3acd096b5b61bfaf1b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 26 Mar 2025 11:05:49 +0100 Subject: [PATCH 354/427] Minor fix --- serializer/custom_normalizer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer/custom_normalizer.rst b/serializer/custom_normalizer.rst index 8072b590ced..4221b3ad808 100644 --- a/serializer/custom_normalizer.rst +++ b/serializer/custom_normalizer.rst @@ -39,7 +39,7 @@ to customize the normalized data. To do that, leverage the ``ObjectNormalizer``: // Here, add, edit, or delete some data: $data['href']['self'] = $this->router->generate('topic_show', [ - 'id' => $topic->getId(), + 'id' => $object->getId(), ], UrlGeneratorInterface::ABSOLUTE_URL); return $data; From d6b4ff9e7bfd146eb037894705d6a9ff95b7d611 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 4 Mar 2025 22:06:02 +0100 Subject: [PATCH 355/427] Add more information about core team processes --- contributing/core_team.rst | 140 ++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 16 deletions(-) diff --git a/contributing/core_team.rst b/contributing/core_team.rst index 2edb42a842d..88c9edf45ab 100644 --- a/contributing/core_team.rst +++ b/contributing/core_team.rst @@ -27,10 +27,24 @@ Core Team Member Responsibilities Core Team members are unpaid volunteers and as such, they are not expected to dedicate any specific amount of time on Symfony. They are expected to help the -project in any way they can, from reviewing pull requests, writing documentation -to participating in discussions and helping the community in general, but their -involvement is completely voluntary and can be as much or as little as they -want. +project in any way they can. From reviewing pull requests and writing documentation, +to participating in discussions and helping the community in general. However, +their involvement is completely voluntary and can be as much or as little as +they want. + +Core Team Communication +~~~~~~~~~~~~~~~~~~~~~~~ + +As an open source project, public discussions and documentation is favored +over private ones. All communication in the Symfony community conforms to +the :doc:`/contributing/code_of_conduct/code_of_conduct`. Request +assistance from other Core and CARE team members when getting in situations +not following the Code of Conduct. + +Core Team members are invited in a private Slack channel, for quick +interactions and private processes (e.g. security issues). Each member +should feel free to ask for assistance for anything they may encounter. +Expect no judgement from other team members. Core Organization ----------------- @@ -146,6 +160,14 @@ A Symfony Core membership can be revoked for any of the following reasons: * Willful negligence or intent to harm the Symfony project; * Upon decision of the **Project Leader**. +Core Membership Compensation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Core Team members work on Symfony on a purely voluntary basis. In return +for their work for the Symfony project, members can get free access to +Symfony conferences. Personal vouchers for Symfony conferences are handed out +on request by the **Project Leader**. + Code Development Rules ---------------------- @@ -170,7 +192,7 @@ Pull Request Merging Policy A pull request **can be merged** if: -* It is a :ref:`minor change `; +* It is a :ref:`unsubstantial change `; * Enough time was given for peer reviews; * It is a bug fix and at least two **Mergers Team** members voted ``+1`` (only one if the submitter is part of the Mergers team) and no Core @@ -179,12 +201,20 @@ A pull request **can be merged** if: ``+1`` (if the submitter is part of the Mergers team, two *other* members) and no Core member voted ``-1`` (via GitHub reviews or as comments). +.. _core-team_unsubstantial-changes: + +.. note:: + + Unsubstantial changes comprise typos, DocBlock fixes, code standards + fixes, comment, exception message tweaks, and minor CSS, JavaScript and + HTML modifications. + Pull Request Merging Process ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -All code must be committed to the repository through pull requests, except for -:ref:`minor change ` which can be committed directly -to the repository. +All code must be committed to the repository through pull requests, except +for :ref:`unsubstantial change ` which can be +committed directly to the repository. **Mergers** must always use the command-line ``gh`` tool provided by the **Project Leader** to merge pull requests. @@ -206,6 +236,90 @@ following these rules: Getting the right category is important as it is used by automated tools to generate the CHANGELOG files when releasing new versions. +.. tip:: + + Core team members are part of the ``mergers`` group on the ``symfony`` + Github organization. This gives them write-access to many repositories, + including the main ``symfony/symfony`` mono-repository. + + To avoid unintentional pushes to the main project (which in turn creates + new versions on Packagist), Core team members are encouraged to have + two clones of the project locally: + + #. A clone for their own contributions, which they use to push to their + fork on GitHub. Clear out the push URL for the Symfony repository using + ``git remote set-url --push origin dev://null`` (change ``origin`` + to the Git remote poiting to the Symfony repository); + #. A clone for merging, which they use in combination with ``gh`` and + allows them to push to the main repository. + +Upmerging Version Branches +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To synchronize changes in all versions, version branches are regularly +merged from oldest to latest, called "upmerging". This is a manual process. +There is no strict policy on when this occurs, but usually not more than +once a day and at least once before monthly releases. + +Before starting the upmerge, Git must be configured to provide a merge +summary by running: + +.. code-block:: terminal + + # Run command in the "symfony" repository + $ git config merge.stat true + +The upmerge should always be done on all maintained versions at the same +time. Refer to `the releases page`_ to find all actively maintained +versions (indicated by a green color). + +The process follows these steps: + +#. Start on the oldest version and make sure it's up to date with the + upstream repository; +#. Check-out the second oldest version, update from upstream and merge the + previous version from the local branch; +#. Continue this process until you reached the latest version; +#. Push the branches to the repository and monitor the test suite. Failure + might indicate hidden/missed merge conflicts. + +.. code-block:: terminal + + # 'origin' is refered to as the main upstream project + $ git fetch origin + + # update the local branches + $ git checkout 6.4 + $ git reset --hard origin/6.4 + $ git checkout 7.2 + $ git reset --hard origin/7.2 + $ git checkout 7.3 + $ git reset --hard origin/7.3 + + # upmerge 6.4 into 7.2 + $ git checkout 7.2 + $ git merge --no-ff 6.4 + # ... resolve conflicts + $ git commit + + # upmerge 7.2 into 7.3 + $ git checkout 7.3 + $ git merge --no-ff 7.2 + # ... resolve conflicts + $ git commit + + $ git push origin 7.3 7.2 6.4 + +.. warning:: + + Upmerges must be explicit, i.e. no fast-forward merges. + +.. tip:: + + Solving merge conflicts can be challenging. You can always ping other + Core team members to help you in the process (e.g. members that merged + a specific conflicting change). + Release Policy ~~~~~~~~~~~~~~ @@ -217,13 +331,6 @@ Symfony Core Rules and Protocol Amendments The rules described in this document may be amended at any time at the discretion of the **Project Leader**. -.. _core-team_minor-changes: - -.. note:: - - Minor changes comprise typos, DocBlock fixes, code standards - violations, and minor CSS, JavaScript and HTML modifications. - .. _`symfony-docs repository`: https://github.com/symfony/symfony-docs .. _`UX repositories`: https://github.com/symfony/ux .. _`fabpot`: https://github.com/fabpot/ @@ -264,4 +371,5 @@ discretion of the **Project Leader**. .. _`mtarld`: https://github.com/mtarld/ .. _`spomky`: https://github.com/spomky/ .. _`alexandre-daubois`: https://github.com/alexandre-daubois/ -.. _`tucksaun`: https://github.com/tucksaun/ \ No newline at end of file +.. _`tucksaun`: https://github.com/tucksaun/ +.. _`the releases page`: https://symfony.com/releases From 89e37c14121ed155d84a295554343f1ff1674057 Mon Sep 17 00:00:00 2001 From: MrYamous Date: Fri, 28 Mar 2025 08:28:17 +0100 Subject: [PATCH 356/427] messenger: allow to close connection --- messenger.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/messenger.rst b/messenger.rst index 0f1eba49a9f..06ad586407d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2254,6 +2254,20 @@ on a case-by-case basis via the :class:`Symfony\\Component\\Messenger\\Stamp\\Se provides that control. See `SymfonyCasts' message serializer tutorial`_ for details. +Closing connection +~~~~~~~~~~~~~~~~~~ + +When using a transport that requires a connection, you can close it using +the :method:`Symfony\\Component\\Messenger\\Transport\\CloseableTransportInterface::close` +method to allow free resources for long-running processes. + +This interface is implemented by the following transports: AmazonSqs, Amqp and Redis. +If you want to close a Doctrine connection, this can be achieved :ref:`using middleware `. + +.. versionadded:: 7.3 + + The ``CloseableTransportInterface`` and ``close`` method were introduced in Symfony 7.3. + Running Commands And External Processes --------------------------------------- From 76f7e6e9506ebc8f04d956af63d9c4b723eca446 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 28 Mar 2025 16:59:53 +0100 Subject: [PATCH 357/427] Minor tweak --- reference/configuration/framework.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 7986140e050..3f34f792630 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1025,8 +1025,8 @@ exceptions **type**: ``array`` -Defines the :ref:`log level `, :ref:`log channel ` and HTTP status code applied to the -exceptions that match the given exception class: +Defines the :ref:`log level `, :ref:`log channel ` +and HTTP status code applied to the exceptions that match the given exception class: .. configuration-block:: From 5b9b62ea671b4894c733dccd4a49e1acc5d20686 Mon Sep 17 00:00:00 2001 From: Tugdual Saunier Date: Sun, 30 Mar 2025 10:45:20 +0200 Subject: [PATCH 358/427] Add CLI team description --- contributing/core_team.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contributing/core_team.rst b/contributing/core_team.rst index 88c9edf45ab..f895dcd00d8 100644 --- a/contributing/core_team.rst +++ b/contributing/core_team.rst @@ -69,6 +69,7 @@ In addition, there are other groups created to manage specific topics: * **Security Team**: manages the whole security process (triaging reported vulnerabilities, fixing the reported issues, coordinating the release of security fixes, etc.); * **Symfony UX Team**: manages the `UX repositories`_; +* **Symfony CLI Team**: manages the `CLI repositories`_; * **Documentation Team**: manages the whole `symfony-docs repository`_. Active Core Members @@ -100,7 +101,6 @@ Active Core Members * **Berislav Balogović** (`hypemc`_); * **Mathias Arlaud** (`mtarld`_); * **Florent Morselli** (`spomky`_); - * **Tugdual Saunier** (`tucksaun`_); * **Alexandre Daubois** (`alexandre-daubois`_). * **Security Team** (``@symfony/security`` on GitHub): @@ -116,6 +116,11 @@ Active Core Members * **Hugo Alliaume** (`kocal`_); * **Matheo Daninos** (`webmamba`_). +* **Symfony CLI Team** (``@symfony-cli/core`` on GitHub): + + * **Fabien Potencier** (`fabpot`_); + * **Tugdual Saunier** (`tucksaun`_). + * **Documentation Team** (``@symfony/team-symfony-docs`` on GitHub): * **Fabien Potencier** (`fabpot`_); @@ -333,6 +338,7 @@ discretion of the **Project Leader**. .. _`symfony-docs repository`: https://github.com/symfony/symfony-docs .. _`UX repositories`: https://github.com/symfony/ux +.. _`CLI repositories`: https://github.com/symfony-cli .. _`fabpot`: https://github.com/fabpot/ .. _`webmozart`: https://github.com/webmozart/ .. _`Tobion`: https://github.com/Tobion/ From 1d02e0ca8e4be30395bcd45b183b3b1129de4cd6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 31 Mar 2025 08:02:46 +0200 Subject: [PATCH 359/427] Minor tweaks --- messenger.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/messenger.rst b/messenger.rst index 06ad586407d..fc8f9491022 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2254,19 +2254,21 @@ on a case-by-case basis via the :class:`Symfony\\Component\\Messenger\\Stamp\\Se provides that control. See `SymfonyCasts' message serializer tutorial`_ for details. -Closing connection -~~~~~~~~~~~~~~~~~~ +Closing Connections +~~~~~~~~~~~~~~~~~~~ -When using a transport that requires a connection, you can close it using -the :method:`Symfony\\Component\\Messenger\\Transport\\CloseableTransportInterface::close` -method to allow free resources for long-running processes. +When using a transport that requires a connection, you can close it by calling the +:method:`Symfony\\Component\\Messenger\\Transport\\CloseableTransportInterface::close` +method to free up resources in long-running processes. -This interface is implemented by the following transports: AmazonSqs, Amqp and Redis. -If you want to close a Doctrine connection, this can be achieved :ref:`using middleware `. +This interface is implemented by the following transports: AmazonSqs, Amqp, and Redis. +If you need to close a Doctrine connection, you can do so +:ref:`using middleware `. .. versionadded:: 7.3 - The ``CloseableTransportInterface`` and ``close`` method were introduced in Symfony 7.3. + The ``CloseableTransportInterface`` and its ``close()`` method were introduced + in Symfony 7.3. Running Commands And External Processes --------------------------------------- From bffad6daf493a377863a6389799623defd92de52 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 1 Apr 2025 09:05:00 +0200 Subject: [PATCH 360/427] Minor tweaks --- serializer.rst | 61 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/serializer.rst b/serializer.rst index 5f9144abae0..1fca42a3572 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1544,13 +1544,13 @@ Named Serializers Named serializers were introduced in Symfony 7.2. -Sometimes, you may need multiple configurations for the serializer, such -as different default contexts, name converters, or sets of normalizers and -encoders, depending on the use case. For example, when your application -communicates with multiple APIs, each with its own set of rules. +Sometimes, you may need multiple configurations for the serializer, such as +different default contexts, name converters, or sets of normalizers and encoders, +depending on the use case. For example, when your application communicates with +multiple APIs, each of which follows its own set of serialization rules. -This can be achieved by configuring multiple instances of the serializer -using the ``named_serializers`` option: +You can achieve this by configuring multiple serializer instances using +the ``named_serializers`` option: .. configuration-block:: @@ -1633,7 +1633,7 @@ using :ref:`named aliases `:: class PersonController extends AbstractController { public function index( - SerializerInterface $serializer, // Default serializer + SerializerInterface $serializer, // default serializer SerializerInterface $apiClient1Serializer, // api_client1 serializer #[Target('apiClient2.serializer')] // api_client2 serializer SerializerInterface $customName, @@ -1642,10 +1642,10 @@ using :ref:`named aliases `:: } } -Named serializers are configured with the default set of normalizers and encoders. - -You can register additional normalizers and encoders with a specific named -serializer by adding a ``serializer`` attribute to +By default, named serializers use the built-in set of normalizers and encoders, +just like the main serializer service. However, you can customize them by +registering additional normalizers or encoders for a specific named serializer. +To do that, add a ``serializer`` attribute to the :ref:`serializer.normalizer ` or :ref:`serializer.encoder ` tags: @@ -1658,14 +1658,14 @@ or :ref:`serializer.encoder ` tags: # ... Symfony\Component\Serializer\Normalizer\CustomNormalizer: - # Prevent this normalizer from automatically being included in the default serializer + # prevent this normalizer from being automatically added to the default serializer autoconfigure: false tags: - # Include this normalizer in a single serializer + # add this normalizer only to a specific named serializer - serializer.normalizer: { serializer: 'api_client1' } - # Include this normalizer in multiple serializers + # add this normalizer to several named serializers - serializer.normalizer: { serializer: [ 'api_client1', 'api_client2' ] } - # Include this normalizer in all serializers (including the default one) + # add this normalizer to all serializers, including the default one - serializer.normalizer: { serializer: '*' } .. code-block:: xml @@ -1680,20 +1680,19 @@ or :ref:`serializer.encoder ` tags: - - + - + - + - + @@ -1710,32 +1709,32 @@ or :ref:`serializer.encoder ` tags: // ... $services->set(CustomNormalizer::class) - // Prevent this normalizer from automatically being included in the default serializer + // prevent this normalizer from being automatically added to the default serializer ->autoconfigure(false) - // Include this normalizer in a single serializer + // add this normalizer only to a specific named serializer ->tag('serializer.normalizer', ['serializer' => 'api_client1']) - // Include this normalizer in multiple serializers + // add this normalizer to several named serializers ->tag('serializer.normalizer', ['serializer' => ['api_client1', 'api_client2']]) - // Include this normalizer in all serializers (including the default one) + // add this normalizer to all serializers, including the default one ->tag('serializer.normalizer', ['serializer' => '*']) ; }; -When the ``serializer`` attribute is not set, the service is registered with +When the ``serializer`` attribute is not set, the service is registered only with the default serializer. -Each normalizer and encoder used in a named serializer is tagged with -a ``serializer.normalizer.`` or ``serializer.encoder.`` tag, -which can be used to list their priorities using the following command: +Each normalizer or encoder used in a named serializer is tagged with a +``serializer.normalizer.`` or ``serializer.encoder.`` tag. +You can inspect their priorities using the following command: .. code-block:: terminal $ php bin/console debug:container --tag serializer.. -Additionally, you can exclude the default set of normalizers and encoders by -setting the ``include_built_in_normalizers`` and ``include_built_in_encoders`` -options to ``false``: +Additionally, you can exclude the default set of normalizers and encoders from a +named serializer by setting the ``include_built_in_normalizers`` and +``include_built_in_encoders`` options to ``false``: .. configuration-block:: From 8d35db9a1f83b31f7828f8910c744a91f60a82c3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 1 Apr 2025 09:57:29 +0200 Subject: [PATCH 361/427] Tweaks --- .../service_subscribers_locators.rst | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index d154f2dce3d..14cdb010152 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -298,10 +298,10 @@ This is done by having ``getSubscribedServices()`` return an array of The above example requires using ``3.2`` version or newer of ``symfony/service-contracts``. .. _service-locator_autowire-locator: -.. _service-locator_autowire-iterator: +.. _the-autowirelocator-and-autowireiterator-attributes: -The AutowireLocator and AutowireIterator Attributes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The AutowireLocator Attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Another way to define a service locator is to use the :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` @@ -381,16 +381,17 @@ attribute:: :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator` attribute was introduced in Symfony 6.4. +.. _service-locator_autowire-iterator: + The AutowireIterator Attribute ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Variant of the ``AutowireLocator`` that specifically provides an iterable of services -based on a tag. This allows you to collect all services with a particular tag into -an iterable, which can be useful when you need to iterate over a set of services -rather than retrieving them individually. -For example, if you want to collect all the handlers for different command types, -you can use the ``AutowireIterator`` attribute to automatically inject all services -tagged with a specific tag:: +A variant of ``AutowireLocator`` that injects an iterable of services tagged +with a specific :doc:`tag `. This is useful to loop +over a set of tagged services instead of retrieving them individually. + +For example, to collect all handlers for different command types, use the +``AutowireIterator`` attribute and pass the tag used by those services:: // src/CommandBus.php namespace App; @@ -404,7 +405,7 @@ tagged with a specific tag:: { public function __construct( #[AutowireIterator('command_handler')] - private iterable $handlers, // Collects all services tagged with 'command_handler' + private iterable $handlers, // collects all services tagged with 'command_handler' ) { } From 6fd2b0e53a6bf8700152c05ec384f5b27bc14d85 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 1 Apr 2025 16:06:08 +0200 Subject: [PATCH 362/427] Minor tweaks --- translation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/translation.rst b/translation.rst index 231969f9487..5565c65bdba 100644 --- a/translation.rst +++ b/translation.rst @@ -497,9 +497,9 @@ Symfony looks for message files (i.e. translations) in the following default loc ``Resources/translations/`` directory, which is no longer recommended for bundles). The locations are listed here with the highest priority first. That is, you can -override the translation messages of a bundle in the first directory. Bundles are processed -in the order they are given in the ``config/bundles.php`` file, so bundles listed first have -higher priority. +override the translation messages of a bundle in the first directory. Bundles are +processed in the order in which they are listed in the ``config/bundles.php`` file, +so bundles appearing earlier have higher priority. The override mechanism works at a key level: only the overridden keys need to be listed in a higher priority message file. When a key is not found From 4742f5d77f54ed153beefbb510b8591c0830bae4 Mon Sep 17 00:00:00 2001 From: Fabian Freiburg Date: Wed, 5 Feb 2025 15:14:38 +0100 Subject: [PATCH 363/427] Readd handling of fallback of bundles directory in Apache config --- setup/web_server_configuration.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/setup/web_server_configuration.rst b/setup/web_server_configuration.rst index 0612f609721..fdedfc81794 100644 --- a/setup/web_server_configuration.rst +++ b/setup/web_server_configuration.rst @@ -178,6 +178,14 @@ directive to pass requests for PHP files to PHP FPM: # Options FollowSymlinks # + # optionally disable the fallback resource for the asset directories + # which will allow Apache to return a 404 error when files are + # not found instead of passing the request to Symfony + # + # DirectoryIndex disabled + # FallbackResource disabled + # + ErrorLog /var/log/apache2/project_error.log CustomLog /var/log/apache2/project_access.log combined From 671eba4dc083e285978a5fb723f2bad4b93976e6 Mon Sep 17 00:00:00 2001 From: MrYamous Date: Wed, 2 Apr 2025 05:45:39 +0200 Subject: [PATCH 364/427] [FrameworkBundle] Deprecate setting the collect_serializer_data to false --- reference/configuration/framework.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 3f34f792630..bcf99d989c7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2352,12 +2352,16 @@ Combine it with the ``collect`` option to enable/disable the profiler on demand: collect_serializer_data ....................... -**type**: ``boolean`` **default**: ``false`` +**type**: ``boolean`` **default**: ``true`` -Set this option to ``true`` to enable the serializer data collector and its -profiler panel. When this option is ``true``, all normalizers and encoders are +When this option is ``true``, all normalizers and encoders are decorated by traceable implementations that collect profiling information about them. +.. deprecated:: 7.3 + + Setting the ``collect_serializer_data`` option to ``false`` is deprecated + since Symfony 7.3. + .. _profiler-dsn: dsn From 7b9ffb28b276674ae330e113c07e578b87055200 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 2 Apr 2025 17:00:44 +0200 Subject: [PATCH 365/427] Tweaks --- service_container/tags.rst | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/service_container/tags.rst b/service_container/tags.rst index ae10f8ef51a..fab25ea910a 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -155,24 +155,8 @@ In a Symfony application, call this method in your kernel class:: } } -In a Symfony bundle, call this method in the ``load()`` method of the -:doc:`bundle extension class `:: - - // src/DependencyInjection/MyBundleExtension.php - class MyBundleExtension extends Extension - { - // ... - - public function load(array $configs, ContainerBuilder $container): void - { - $container->registerForAutoconfiguration(CustomInterface::class) - ->addTag('app.custom_tag') - ; - } - } - -or if you are following the recommended way for new bundles and for bundles following the -:ref:`recommended directory structure `:: +In bundles extending the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle` +class, call this method in the ``loadExtension()`` method of the main bundle class:: // ... use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -190,6 +174,11 @@ or if you are following the recommended way for new bundles and for bundles foll } } +.. note:: + + For bundles not extending the ``AbstractBundle`` class, call this method in + the ``load()`` method of the :doc:`bundle extension class `. + Autoconfiguration registering is not limited to interfaces. It is possible to use PHP attributes to autoconfigure services by using the :method:`Symfony\\Component\\DependencyInjection\\ContainerBuilder::registerAttributeForAutoconfiguration` From b1e2c53a4bc85add8633e13b02e676961503b2a9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Apr 2025 08:49:41 +0200 Subject: [PATCH 366/427] Tweaks --- reference/configuration/security.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index b4ba6696e18..3ccea5f9026 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -1004,11 +1004,11 @@ the session must not be used when authenticating users: .. _reference-security-lazy: lazy -~~~~~~~~~ +~~~~ -Firewalls can configure a ``lazy`` boolean option in order to load the user and start the session only -if the application actually accesses the User object, -(e.g. via a is_granted() call in a template or isGranted() in a controller or service): +Firewalls can configure a ``lazy`` boolean option to load the user and start the +session only if the application actually accesses the User object, (e.g. calling +``is_granted()`` in a template or ``isGranted()`` in a controller or service): .. configuration-block:: @@ -1048,8 +1048,8 @@ if the application actually accesses the User object, use Symfony\Config\SecurityConfig; return static function (SecurityConfig $security): void { - $mainFirewall = $security->firewall('main'); - $mainFirewall->lazy(true); + $security->firewall('main') + ->lazy(true); // ... }; From 6cfc92a41d05b0034ab643ab86538cd65b353670 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Apr 2025 08:57:25 +0200 Subject: [PATCH 367/427] Minor tweaks --- messenger.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index c0822f97fdd..cefa6b8c0d4 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1865,9 +1865,9 @@ under the transport in ``messenger.yaml``: The Redis consumer group name ``consumer`` (default: ``consumer``) - Consumer name used in Redis. Allows to set explicit consumer name identifier. - Recommended for environments with multiple workers to prevent duplicate message processing. - Typically set via environment variable: + Consumer name used in Redis. Allows setting an explicit consumer name identifier. + Recommended in environments with multiple workers to prevent duplicate message + processing. Typically set via an environment variable: .. code-block:: yaml From 111956866e03a6fbbc015e0af60a16bbe5278554 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Apr 2025 08:59:29 +0200 Subject: [PATCH 368/427] [Messenger] Add consumer name documentation --- messenger.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index e86bc73d1c6..6fbfd36385d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1698,7 +1698,20 @@ under the transport in ``messenger.yaml``: The Redis consumer group name ``consumer`` (default: ``consumer``) - Consumer name used in Redis + Consumer name used in Redis. Allows setting an explicit consumer name identifier. + Recommended in environments with multiple workers to prevent duplicate message + processing. Typically set via an environment variable: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + redis: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + options: + consumer: '%env(MESSENGER_CONSUMER_NAME)%' ``auto_setup`` (default: ``true``) Whether to create the Redis group automatically From 0ff840444f265d5492238a92df8081e01eaaf6d2 Mon Sep 17 00:00:00 2001 From: Adam Prancz Date: Wed, 18 Dec 2024 09:48:18 +0100 Subject: [PATCH 369/427] [Serializer] Update serializer.rst --- serializer.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/serializer.rst b/serializer.rst index 7f2569eb104..24ec7e325e0 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1352,6 +1352,31 @@ normalizers (in order of priority): This denormalizer converts an array of arrays to an array of objects (with the given type). See :ref:`Handling Arrays `. + ByUsing the PropertyInfoExtractor you can simply annotate the arrays by '@var Person[]' + + .. configuration-block:: + + .. code-block:: php-standalone + + use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; + use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; + use Symfony\Component\PropertyInfo\PropertyInfoExtractor; + use Symfony\Component\Serializer\Encoder\JsonEncoder; + use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; + use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; + use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; + use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; + use Symfony\Component\Serializer\Serializer; + + $reflectionExtractor = new ReflectionExtractor(); + $phpDocExtractor = new PhpDocExtractor(); + $propertyInfo = new PropertyInfoExtractor([], [$phpDocExtractor, $reflectionExtractor]); + + $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); + $normalizers = [new ObjectNormalizer($classMetadataFactory, null, null, $propertyInfo), new ArrayDenormalizer()]; + + $this->serializer = new Serializer($normalizers, [new JsonEncoder()]); + :class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer` This is the most powerful default normalizer and used for any object that could not be normalized by the other normalizers. From 5e6d3b08c2aab43c19e319928f23769764214366 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Apr 2025 09:12:44 +0200 Subject: [PATCH 370/427] Minor tweaks --- serializer.rst | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/serializer.rst b/serializer.rst index 24ec7e325e0..6e20a651341 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1352,7 +1352,8 @@ normalizers (in order of priority): This denormalizer converts an array of arrays to an array of objects (with the given type). See :ref:`Handling Arrays `. - ByUsing the PropertyInfoExtractor you can simply annotate the arrays by '@var Person[]' + Use :class:`Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor` to provide + hints with annotations like ``@var Person[]``: .. configuration-block:: @@ -1367,13 +1368,9 @@ normalizers (in order of priority): use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; - - $reflectionExtractor = new ReflectionExtractor(); - $phpDocExtractor = new PhpDocExtractor(); - $propertyInfo = new PropertyInfoExtractor([], [$phpDocExtractor, $reflectionExtractor]); - - $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); - $normalizers = [new ObjectNormalizer($classMetadataFactory, null, null, $propertyInfo), new ArrayDenormalizer()]; + + $propertyInfo = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); + $normalizers = [new ObjectNormalizer(new ClassMetadataFactory(new AttributeLoader()), null, null, $propertyInfo), new ArrayDenormalizer()]; $this->serializer = new Serializer($normalizers, [new JsonEncoder()]); From 05ff5258e27fd36bc5fdec0391b6833ab302a4f8 Mon Sep 17 00:00:00 2001 From: Ignacio Aguirre <52148018+nachoaguirre@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:47:02 -0300 Subject: [PATCH 371/427] Update dynamic_form_modification.rst Update the namespace of the class to subscribe to events. Currently it points to \EventListener, but I find it more coherent to associate it with \EventSubscriber --- form/dynamic_form_modification.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/form/dynamic_form_modification.rst b/form/dynamic_form_modification.rst index 09be80ebb5a..a1f32c7c16c 100644 --- a/form/dynamic_form_modification.rst +++ b/form/dynamic_form_modification.rst @@ -138,8 +138,8 @@ For better reusability or if there is some heavy logic in your event listener, you can also move the logic for creating the ``name`` field to an :ref:`event subscriber `:: - // src/Form/EventListener/AddNameFieldSubscriber.php - namespace App\Form\EventListener; + // src/Form/EventSubscriber/AddNameFieldSubscriber.php + namespace App\Form\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -172,7 +172,7 @@ Great! Now use that in your form class:: namespace App\Form\Type; // ... - use App\Form\EventListener\AddNameFieldSubscriber; + use App\Form\EventSubscriber\AddNameFieldSubscriber; class ProductType extends AbstractType { From 850666f30df9503367b415410c083df1fb44da73 Mon Sep 17 00:00:00 2001 From: sarah-eit Date: Wed, 27 Nov 2024 14:59:57 +0100 Subject: [PATCH 372/427] [Twig] [twig reference] add examples to functions and filter --- reference/twig_reference.rst | 199 +++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 21f251dc6de..4b145364b0e 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -110,6 +110,22 @@ asset ``packageName`` *(optional)* **type**: ``string`` | ``null`` **default**: ``null`` +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + assets: + packages: + foo_package: + base_path: /avatars + +.. code-block:: twig + + {# the image lives at "public/avatars/avatar.png" #} + {{ asset(path = 'avatar.png', packageName = 'foo_package') }} + {# output: /avatars/avatar.png #} + Returns the public path of the given asset path (which can be a CSS file, a JavaScript file, an image path, etc.). This function takes into account where the application is installed (e.g. in case the project is accessed in a host @@ -187,6 +203,30 @@ logout_path Generates a relative logout URL for the given firewall. If no key is provided, the URL is generated for the current firewall the user is logged into. +.. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + logout: + path: '/logout' + othername: + # ... + logout: + path: '/other/logout' + +.. code-block:: twig + + {{ logout_path(key = 'main') }} + {# output: /logout #} + + {{ logout_path(key = 'othername') }} + {# output: /other/logout #} + logout_url ~~~~~~~~~~ @@ -200,6 +240,30 @@ logout_url Equal to the `logout_path`_ function, but it'll generate an absolute URL instead of a relative one. +.. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + logout: + path: '/logout' + othername: + # ... + logout: + path: '/other/logout' + +.. code-block:: twig + + {{ logout_url(key = 'main') }} + {# output: http://example.org/logout #} + + {{ logout_url(key = 'othername') }} + {# output: http://example.org/other/logout #} + path ~~~~ @@ -217,6 +281,14 @@ path Returns the relative URL (without the scheme and host) for the given route. If ``relative`` is enabled, it'll create a path relative to the current path. +.. code-block:: twig + + {{ path(name = 'app_blog', parameters = {page: 3}, relative = false) }} + {# output (depending on the route configuration): /blog/3 or /blog?page=3 #} + + {{ path(name = 'app_blog', parameters = {page: 3}, relative = true) }} + {# output (depending on the route configuration): blog/3 or ?page=3 #} + .. seealso:: Read more about :doc:`Symfony routing ` and about @@ -239,6 +311,16 @@ url Returns the absolute URL (with scheme and host) for the given route. If ``schemeRelative`` is enabled, it'll create a scheme-relative URL. +.. code-block:: twig + + {{ url(name = 'app_blog', parameters = {page: 3}, schemeRelative = false) }} + {# output (depending on the route configuration): http://example.org/blog/3 + or http://example.org/blog?page=3 #} + + {{ url(name = 'app_blog', parameters = {page: 3}, schemeRelative = true) }} + {# output (depending on the route configuration): //example.org/blog/3 + or //example.org/blog?page=3 #} + .. seealso:: Read more about :doc:`Symfony routing ` and about @@ -290,6 +372,11 @@ expression Creates an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` related to the :doc:`ExpressionLanguage component `. +.. code-block:: twig + + {{ expression(1 + 2) }} + {# output: 3 #} + impersonation_path ~~~~~~~~~~~~~~~~~~ @@ -373,6 +460,42 @@ t Creates a ``Translatable`` object that can be passed to the :ref:`trans filter `. +.. configuration-block:: + + .. code-block:: yaml + + # translations/blog.en.yaml + message: Hello %name% + + .. code-block:: xml + + + + + + + + message + Hello %name% + + + + + + .. code-block:: php + + // translations/blog.en.php + return [ + 'message' => "Hello %name%", + ]; + +Using the filter will be rendered as: + +.. code-block:: twig + + {{ t(message = 'message', parameters = {'%name%': 'John'}, domain = 'blog')|trans }} + {# output: Hello John #} + importmap ~~~~~~~~~ @@ -452,6 +575,42 @@ trans Translates the text into the current language. More information in :ref:`Translation Filters `. +.. configuration-block:: + + .. code-block:: yaml + + # translations/messages.en.yaml + message: Hello %name% + + .. code-block:: xml + + + + + + + + message + Hello %name% + + + + + + .. code-block:: php + + // translations/messages.en.php + return [ + 'message' => "Hello %name%", + ]; + +Using the filter will be rendered as: + +.. code-block:: twig + + {{ 'message'|trans(arguments = {'%name%': 'John'}, domain = 'messages', locale = 'en') }} + {# output: Hello John #} + sanitize_html ~~~~~~~~~~~~~ @@ -593,6 +752,16 @@ abbr_class Generates an ```` element with the short name of a PHP class (the FQCN will be shown in a tooltip when a user hovers over the element). +.. code-block:: twig + + {{ 'App\\Entity\\Product'|abbr_class }} + +The above example will be rendered as: + +.. code-block:: html + + Product + abbr_method ~~~~~~~~~~~ @@ -607,6 +776,16 @@ Generates an ```` element using the ``FQCN::method()`` syntax. If ``method`` is ``Closure``, ``Closure`` will be used instead and if ``method`` doesn't have a class name, it's shown as a function (``method()``). +.. code-block:: twig + + {{ 'App\\Controller\\ProductController::list'|abbr_method }} + +The above example will be rendered as: + +.. code-block:: html + + ProductController + format_args ~~~~~~~~~~~ @@ -694,6 +873,11 @@ file_link Generates a link to the provided file and line number using a preconfigured scheme. +.. code-block:: twig + + {{ 'path/to/file/file.txt'|file_link(line = 3) }} + {# output: file://path/to/file/file.txt#L3 #} + file_relative ~~~~~~~~~~~~~ @@ -736,6 +920,21 @@ serialize Accepts any data that can be serialized by the :doc:`Serializer component ` and returns a serialized string in the specified ``format``. +For example:: + + $object = new \stdClass(); + $object->foo = 'bar'; + $object->content = []; + $object->createdAt = new \DateTime('2024-11-30'); + +.. code-block:: twig + + {{ object|serialize(format = 'json', context = { + 'datetime_format': 'D, Y-m-d', + 'empty_array_as_object': true, + }) }} + {# output: {"foo":"bar","content":{},"createdAt":"Sat, 2024-11-30"} #} + .. _reference-twig-tags: Tags From f187ace7bf11d80568cf20731aa2bf09e9e9aeb2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Apr 2025 10:33:39 +0200 Subject: [PATCH 373/427] Minor tweaks --- reference/twig_reference.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 4b145364b0e..825ad3b0af7 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -283,11 +283,13 @@ If ``relative`` is enabled, it'll create a path relative to the current path. .. code-block:: twig + {# consider that the app defines an 'app_blog' route with the path '/blog/{page}' #} + {{ path(name = 'app_blog', parameters = {page: 3}, relative = false) }} - {# output (depending on the route configuration): /blog/3 or /blog?page=3 #} + {# output: /blog/3 #} {{ path(name = 'app_blog', parameters = {page: 3}, relative = true) }} - {# output (depending on the route configuration): blog/3 or ?page=3 #} + {# output: blog/3 #} .. seealso:: @@ -313,13 +315,13 @@ Returns the absolute URL (with scheme and host) for the given route. If .. code-block:: twig + {# consider that the app defines an 'app_blog' route with the path '/blog/{page}' #} + {{ url(name = 'app_blog', parameters = {page: 3}, schemeRelative = false) }} - {# output (depending on the route configuration): http://example.org/blog/3 - or http://example.org/blog?page=3 #} + {# output: http://example.org/blog/3 #} {{ url(name = 'app_blog', parameters = {page: 3}, schemeRelative = true) }} - {# output (depending on the route configuration): //example.org/blog/3 - or //example.org/blog?page=3 #} + {# output: //example.org/blog/3 #} .. seealso:: @@ -784,7 +786,7 @@ The above example will be rendered as: .. code-block:: html - ProductController + ProductController::list() format_args ~~~~~~~~~~~ From 82fea87c3de14d6f56f7d707dd29d890f19902ab Mon Sep 17 00:00:00 2001 From: Edgar Brunet Date: Fri, 29 Nov 2024 14:45:51 +0100 Subject: [PATCH 374/427] =?UTF-8?q?[Twig]=20[twig=20reference]=20add=20exa?= =?UTF-8?q?mples=20to=20functions=20(format=5Ffile,=20file=5F=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reference/twig_reference.rst | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 825ad3b0af7..50da312f29f 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -98,6 +98,21 @@ like :ref:`render() ` and .. _reference-twig-function-asset: +.. code-block:: html+twig + + {% set myArray = {'a': 'foo', 'b': 'bar'} %} + + + +Output: + +.. code-block:: html + + + asset ~~~~~ @@ -171,6 +186,11 @@ csrf_token Renders a CSRF token. Use this function if you want :doc:`CSRF protection ` in a regular HTML form not managed by the Symfony Form component. +.. code-block:: twig + + {{ csrf_token(intention = 'my_form') }} + {# output: generates a variable token #} + is_granted ~~~~~~~~~~ @@ -830,6 +850,28 @@ Generates an excerpt of a code file around the given ``line`` number. The ``srcContext`` argument defines the total number of lines to display around the given line number (use ``-1`` to display the whole file). +Let's assume this is the content of a file : + +.. code-block:: text + + a + b + c + d + e + +.. code-block:: twig + + {{ "/path/to/file/file.txt"|file_excerpt(line = 4, srcContext = 1) }} + {# output: + 3.c + 4.d + 5.e #} + + {{ "/path/to/file/file.txt"|file_excerpt(line = 1, srcContext = 0) }} + {# output: + 1.a #} + format_file ~~~~~~~~~~~ @@ -848,6 +890,36 @@ Generates the file path inside an ```` element. If the path is inside the kernel root directory, the kernel root directory path is replaced by ``kernel.project_dir`` (showing the full path in a tooltip on hover). +Example 1 + +.. code-block:: twig + + {{ "path/to/file/file.txt"|format_file(line = 1, text = "my_text") }} + +Output: + +.. code-block:: html + + my_text at line 1 + + +Example 2 + +.. code-block:: twig + + {{ "path/to/file/file.txt"|format_file(line = 3) }} + +Output: + +.. code-block:: html + + + file.txt + / at line 3 + + format_file_from_text ~~~~~~~~~~~~~~~~~~~~~ From 3c4f75387112e4e5f755f7925517edcbf86ab668 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Apr 2025 12:33:55 +0200 Subject: [PATCH 375/427] Tweaks and rewords --- reference/configuration/framework.rst | 2 + reference/twig_reference.rst | 84 ++++++++++++--------------- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 8838a6a61b2..2274addf1aa 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -271,6 +271,8 @@ The ``trusted_proxies`` option is needed to get precise information about the client (e.g. their IP address) when running Symfony behind a load balancer or a reverse proxy. See :doc:`/deployment/proxies`. +.. _reference-framework-ide: + ide ~~~ diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 50da312f29f..08ea8f1d581 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -96,22 +96,12 @@ Returns an instance of ``ControllerReference`` to be used with functions like :ref:`render() ` and :ref:`render_esi() `. -.. _reference-twig-function-asset: - .. code-block:: html+twig - {% set myArray = {'a': 'foo', 'b': 'bar'} %} - - - -Output: - -.. code-block:: html + {{ render(controller('App\\Controller\\BlogController:latest', {max: 3})) }} + {# output: the content returned by the controller method; e.g. a rendered Twig template #} - +.. _reference-twig-function-asset: asset ~~~~~ @@ -188,8 +178,9 @@ in a regular HTML form not managed by the Symfony Form component. .. code-block:: twig - {{ csrf_token(intention = 'my_form') }} - {# output: generates a variable token #} + {{ csrf_token('my_form') }} + {# output: a random alphanumeric string like: + a.YOosAd0fhT7BEuUCFbROzrvgkW8kpEmBDQ_DKRMUi2o.Va8ZQKt5_2qoa7dLW-02_PLYwDBx9nnWOluUHUFCwC5Zo0VuuVfQCqtngg #} is_granted ~~~~~~~~~~ @@ -850,7 +841,7 @@ Generates an excerpt of a code file around the given ``line`` number. The ``srcContext`` argument defines the total number of lines to display around the given line number (use ``-1`` to display the whole file). -Let's assume this is the content of a file : +Consider the following as the content of ``file.txt``: .. code-block:: text @@ -862,15 +853,21 @@ Let's assume this is the content of a file : .. code-block:: twig - {{ "/path/to/file/file.txt"|file_excerpt(line = 4, srcContext = 1) }} + {{ '/path/to/file.txt'|file_excerpt(line = 4, srcContext = 1) }} {# output: - 3.c - 4.d - 5.e #} - - {{ "/path/to/file/file.txt"|file_excerpt(line = 1, srcContext = 0) }} +
    +
  1. c
  2. +
  3. d
  4. +
  5. e
  6. +
+ #} + + {{ '/path/to/file.txt'|file_excerpt(line = 1, srcContext = 0) }} {# output: - 1.a #} +
    +
  1. a
  2. +
+ #} format_file ~~~~~~~~~~~ @@ -890,35 +887,28 @@ Generates the file path inside an ```` element. If the path is inside the kernel root directory, the kernel root directory path is replaced by ``kernel.project_dir`` (showing the full path in a tooltip on hover). -Example 1 - .. code-block:: twig - {{ "path/to/file/file.txt"|format_file(line = 1, text = "my_text") }} - -Output: - -.. code-block:: html - - my_text at line 1 - - -Example 2 - -.. code-block:: twig - - {{ "path/to/file/file.txt"|format_file(line = 3) }} + {{ '/path/to/file.txt'|format_file(line = 1, text = "my_text") }} + {# output: + my_text at line 1 + + #} -Output: + {{ "/path/to/file.txt"|format_file(line = 3) }} + {# output: + /path/to/file.txt at line 3 + + #} -.. code-block:: html +.. tip:: - - file.txt - / at line 3 - + If you set the :ref:`framework.ide ` option, the + generated links will change to open the file in that IDE/editor. For example, + when using PhpStorm, the `` Date: Thu, 3 Apr 2025 12:40:55 +0200 Subject: [PATCH 376/427] Fix some syntax issues --- reference/twig_reference.rst | 46 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 08ea8f1d581..8ad72575e82 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -96,7 +96,7 @@ Returns an instance of ``ControllerReference`` to be used with functions like :ref:`render() ` and :ref:`render_esi() `. -.. code-block:: html+twig +.. code-block:: twig {{ render(controller('App\\Controller\\BlogController:latest', {max: 3})) }} {# output: the content returned by the controller method; e.g. a rendered Twig template #} @@ -851,23 +851,21 @@ Consider the following as the content of ``file.txt``: d e -.. code-block:: twig +.. code-block:: html+twig {{ '/path/to/file.txt'|file_excerpt(line = 4, srcContext = 1) }} - {# output: -
    -
  1. c
  2. -
  3. d
  4. -
  5. e
  6. -
- #} + {# output: #} +
    +
  1. c
  2. +
  3. d
  4. +
  5. e
  6. +
{{ '/path/to/file.txt'|file_excerpt(line = 1, srcContext = 0) }} - {# output: -
    -
  1. a
  2. -
- #} + {# output: #} +
    +
  1. a
  2. +
format_file ~~~~~~~~~~~ @@ -887,21 +885,19 @@ Generates the file path inside an ```` element. If the path is inside the kernel root directory, the kernel root directory path is replaced by ``kernel.project_dir`` (showing the full path in a tooltip on hover). -.. code-block:: twig +.. code-block:: html+twig {{ '/path/to/file.txt'|format_file(line = 1, text = "my_text") }} - {# output: - my_text at line 1 - - #} + {# output: #} + my_text at line 1 + {{ "/path/to/file.txt"|format_file(line = 3) }} - {# output: - /path/to/file.txt at line 3 - - #} + {# output: #} + /path/to/file.txt at line 3 + .. tip:: From 534c9837e20c0049a2cdcf93f6b93a647a581bae Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 4 Apr 2025 08:31:32 +0200 Subject: [PATCH 377/427] Reword --- scheduler.rst | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/scheduler.rst b/scheduler.rst index e9c729ab986..63ec32962cf 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -290,32 +290,25 @@ defined by PHP datetime functions:: You can also define periodic tasks using :ref:`the AsPeriodicTask attribute `. -Be aware that the message isn't passed to the messenger when you start the -scheduler. The message will only be executed after the first frequency period -has passed. - -It's also possible to pass a from and until time for your schedule. For -example, if you want to execute a command every day at 13:00:: +You can also define ``from`` and ``until`` times for your schedule:: + // create a message every day at 13:00 $from = new \DateTimeImmutable('13:00', new \DateTimeZone('Europe/Paris')); - RecurringMessage::every('1 day', new Message(), from: $from); - -Or if you want to execute a message every day until a specific date:: + RecurringMessage::every('1 day', new Message(), $from); + // create a message every day until a specific date:: $until = '2023-06-12'; - RecurringMessage::every('1 day', new Message(), until: $until); - -And you can even combine the from and until parameters for more granular -control:: + RecurringMessage::every('1 day', new Message(), null, $until); + // combine from and until for more precise control $from = new \DateTimeImmutable('2023-01-01 13:47', new \DateTimeZone('Europe/Paris')); $until = '2023-06-12'; - RecurringMessage::every('first Monday of next month', new Message(), from: $from, until: $until); + RecurringMessage::every('first Monday of next month', new Message(), $from, $until); -If you don't pass a from parameter to your schedule, the first frequency period -is counted from the moment the scheduler is started. So if you start your -scheduler at 8:33 and the message is scheduled to perform every hour, it -will be executed at 9:33, 10:33, 11:33 and so on. +When starting the scheduler, the message isn't sent to the messenger immediately. +If you don't set a ``from`` parameter, the first frequency period starts from the +moment the scheduler runs. For example, if you start it at 8:33 and the message +is scheduled hourly, it will run at 9:33, 10:33, 11:33, etc. Custom Triggers ~~~~~~~~~~~~~~~ From 9c2d1d9198e70676f45a34119d7d563718840db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9?= Date: Sun, 25 Aug 2024 21:23:24 +1200 Subject: [PATCH 378/427] [Mailer] Update mailer.rst --- mailer.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mailer.rst b/mailer.rst index 53a6475a093..27a90c73191 100644 --- a/mailer.rst +++ b/mailer.rst @@ -834,6 +834,13 @@ The exceptions related to mailer transports (those which implement :class:`Symfony\\Component\\Mailer\\Exception\\TransportException`) also provide this debug information via the ``getDebug()`` method. +But you have to keep in mind that using :class:`Symfony\\Component\\Mailer\\Transport\\TransportInterface` +you can't rely on asynchronous sending emails. +It doesn't use a bus to dispatch :class:`Symfony\\Component\\Mailer\\Messenger\\SendEmailMessage`. + +Use :class:`Symfony\\Component\\Mailer\\MailerInterface` if you want to have an opportunity +to send emails asynchronously. + .. _mailer-twig: Twig: HTML & CSS From eb5f908bc97bd2b40d9bbe644d8c61674d1a7714 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Fri, 4 Apr 2025 10:44:13 -0400 Subject: [PATCH 379/427] [RateLimiter] default `lock_factory` to `auto` --- rate_limiter.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 6c158ee52d0..1cef90828f5 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -461,9 +461,10 @@ simultaneous requests (e.g. three servers of a company hitting your API at the same time). Rate limiters use :doc:`locks ` to protect their operations against these race conditions. -By default, Symfony uses the global lock configured by ``framework.lock``, but -you can use a specific :ref:`named lock ` via the -``lock_factory`` option (or none at all): +By default, if the :doc:`lock ` component is installed, Symfony uses the +global lock configured by ``framework.lock``, but you can use a specific +:ref:`named lock ` via the ``lock_factory`` option (or none +at all): .. configuration-block:: From 74a146ee4f74fbc7dae98fa695040dd8da81dcc3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 4 Apr 2025 16:51:36 +0200 Subject: [PATCH 380/427] Reword --- mailer.rst | 65 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/mailer.rst b/mailer.rst index 27a90c73191..52c6ee7dded 100644 --- a/mailer.rst +++ b/mailer.rst @@ -807,40 +807,59 @@ Catch that exception to recover from the error or to display some message:: Debugging Emails ---------------- -The :class:`Symfony\\Component\\Mailer\\SentMessage` object returned by the -``send()`` method of the :class:`Symfony\\Component\\Mailer\\Transport\\TransportInterface` -provides access to the original message (``getOriginalMessage()``) and to some -debug information (``getDebug()``) such as the HTTP calls done by the HTTP -transports, which is useful to debug errors. +The ``send()`` method of the mailer service injected when using ``MailerInterface`` +doesn't return anything, so you can't access the sent email information. This is because +it sends email messages **asynchronously** when the :doc:`Messenger component ` +is used in the application. -You can also access :class:`Symfony\\Component\\Mailer\\SentMessage` by listening -to the :ref:`SentMessageEvent ` and retrieve ``getDebug()`` -by listening to the :ref:`FailedMessageEvent `. +To access information about the sent email, update your code to replace the +:class:`Symfony\\Component\\Mailer\\MailerInterface` with +:class:`Symfony\\Component\\Mailer\\Transport\\TransportInterface`: -.. note:: +.. code-block:: diff + + -use Symfony\Component\Mailer\MailerInterface; + +use Symfony\Component\Mailer\Transport\TransportInterface; + // ... + + class MailerController extends AbstractController + { + #[Route('/email')] + - public function sendEmail(MailerInterface $mailer): Response + + public function sendEmail(TransportInterface $mailer): Response + { + $email = (new Email()) + // ... + + $sentEmail = $mailer->send($email); - If your code used :class:`Symfony\\Component\\Mailer\\MailerInterface`, you - need to replace it by :class:`Symfony\\Component\\Mailer\\Transport\\TransportInterface` - to have the ``SentMessage`` object returned. + // ... + } + } + +The ``send()`` method of ``TransportInterface`` returns an object of type +:class:`Symfony\\Component\\Mailer\\SentMessage`. This is because it always sends +the emails **synchronously**, even if your application uses the Messenger component. + +The ``SentMessage`` object provides access to the original message +(``getOriginalMessage()``) and to some debug information (``getDebug()``) such +as the HTTP calls done by the HTTP transports, which is useful to debug errors. + +You can also access the :class:`Symfony\\Component\\Mailer\\SentMessage` object +by listening to the :ref:`SentMessageEvent `, and retrieve +``getDebug()`` by listening to the :ref:`FailedMessageEvent `. .. note:: Some mailer providers change the ``Message-Id`` when sending the email. The - ``getMessageId()`` method from ``SentMessage`` always returns the definitive - ID of the message (being the original random ID generated by Symfony or the - new ID generated by the mailer provider). + ``getMessageId()`` method from ``SentMessage`` always returns the final ID + of the message - whether it's the original random ID generated by Symfony or + a new one generated by the provider. -The exceptions related to mailer transports (those which implement +Exceptions related to mailer transports (those implementing :class:`Symfony\\Component\\Mailer\\Exception\\TransportException`) also provide this debug information via the ``getDebug()`` method. -But you have to keep in mind that using :class:`Symfony\\Component\\Mailer\\Transport\\TransportInterface` -you can't rely on asynchronous sending emails. -It doesn't use a bus to dispatch :class:`Symfony\\Component\\Mailer\\Messenger\\SendEmailMessage`. - -Use :class:`Symfony\\Component\\Mailer\\MailerInterface` if you want to have an opportunity -to send emails asynchronously. - .. _mailer-twig: Twig: HTML & CSS From 8ed84b509d7a062e4991024d71770e0411f2f77c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 4 Apr 2025 16:53:55 +0200 Subject: [PATCH 381/427] Fix RST syntax issue --- scheduler.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scheduler.rst b/scheduler.rst index 63ec32962cf..e7d855db249 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -296,7 +296,7 @@ You can also define ``from`` and ``until`` times for your schedule:: $from = new \DateTimeImmutable('13:00', new \DateTimeZone('Europe/Paris')); RecurringMessage::every('1 day', new Message(), $from); - // create a message every day until a specific date:: + // create a message every day until a specific date $until = '2023-06-12'; RecurringMessage::every('1 day', new Message(), null, $until); From 19b99dbe1b32290052fd6d211e75836efa00f20b Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 4 Apr 2025 17:04:03 +0200 Subject: [PATCH 382/427] [Config] Add `NodeDefinition::docUrl()` --- components/config/definition.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/config/definition.rst b/components/config/definition.rst index 44189d9dd6f..4848af33ffe 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -546,6 +546,30 @@ and in XML: +You can also provide a URL to a full documentation page:: + + $rootNode + ->docUrl('Full documentation is available at https://example.com/docs/{version:major}.{version:minor}/reference.html') + ->children() + ->integerNode('entries_per_page') + ->defaultValue(25) + ->end() + ->end() + ; + +A few placeholders are available to customize the URL: + +* ``{version:major}``: The major version of the package currently installed +* ``{version:minor}``: The minor version of the package currently installed +* ``{package}``: The name of the package + +The placeholders will be replaced when printing the configuration tree with the +``config:dump-reference`` command. + +.. versionadded:: 7.3 + + The ``docUrl()`` method was introduced in Symfony 7.3. + Optional Sections ----------------- From 50b6ffdac765fad51e6c087a00667711840aea10 Mon Sep 17 00:00:00 2001 From: RisingSunLight Date: Mon, 7 Apr 2025 00:49:36 +0200 Subject: [PATCH 383/427] fix command explanation --- templates.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates.rst b/templates.rst index 77e10bc5596..98742058988 100644 --- a/templates.rst +++ b/templates.rst @@ -849,7 +849,8 @@ errors. It's useful to run it before deploying your application to production $ php bin/console lint:twig templates/email/ $ php bin/console lint:twig templates/article/recent_list.html.twig - # you can also show the deprecated features used in your templates + # you can also show the first deprecated feature used in your templates + # as it shows only the first one found, you may need to run it until no more deprecations are found $ php bin/console lint:twig --show-deprecations templates/email/ When running the linter inside `GitHub Actions`_, the output is automatically From 20ce1892efe75de46c9447a7a40baab5f6a5a2a0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Apr 2025 08:09:16 +0200 Subject: [PATCH 384/427] Added a versionadded directive --- rate_limiter.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rate_limiter.rst b/rate_limiter.rst index 1cef90828f5..81bd7f5689e 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -535,6 +535,12 @@ at all): ; }; +.. versionadded:: 7.3 + + Before Symfony 7.3, configuring a rate limiter and using the default configured + lock factory (``lock.factory``) failed if the Symfony Lock component was not + installed in the application. + .. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html .. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html .. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/ From 03321a8e0246365b1a17ac998f1de895f28b94ad Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Apr 2025 08:36:00 +0200 Subject: [PATCH 385/427] Minor reword --- templates.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates.rst b/templates.rst index 98742058988..5e34b930d0e 100644 --- a/templates.rst +++ b/templates.rst @@ -849,8 +849,8 @@ errors. It's useful to run it before deploying your application to production $ php bin/console lint:twig templates/email/ $ php bin/console lint:twig templates/article/recent_list.html.twig - # you can also show the first deprecated feature used in your templates - # as it shows only the first one found, you may need to run it until no more deprecations are found + # you can also show the deprecated features used in your templates + # (only the first deprecation is shown, so run multiple times to catch all) $ php bin/console lint:twig --show-deprecations templates/email/ When running the linter inside `GitHub Actions`_, the output is automatically From b5efbcd9a777ac3e913a93fdfb96e1c0ef934fc7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Apr 2025 08:41:41 +0200 Subject: [PATCH 386/427] [Templates] Add a versionadded diretive for a command change --- templates.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/templates.rst b/templates.rst index a93bbe742c6..c6312abb33c 100644 --- a/templates.rst +++ b/templates.rst @@ -870,7 +870,6 @@ errors. It's useful to run it before deploying your application to production $ php bin/console lint:twig templates/article/recent_list.html.twig # you can also show the deprecated features used in your templates - # (only the first deprecation is shown, so run multiple times to catch all) $ php bin/console lint:twig --show-deprecations templates/email/ # you can also excludes directories @@ -880,6 +879,11 @@ errors. It's useful to run it before deploying your application to production The option to exclude directories was introduced in Symfony 7.1. +.. versionadded:: 7.3 + + Before Symfony 7.3, the ``--show-deprecations`` option only displayed the + first deprecation found, so you had to run the command repeatedly. + When running the linter inside `GitHub Actions`_, the output is automatically adapted to the format required by GitHub, but you can force that format too: From 97de6eb32ef3f5d8d1b7d2c1fca5fffe04806c1f Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Mon, 7 Apr 2025 08:42:34 +0200 Subject: [PATCH 387/427] [Translator] document global variables feature configuration --- translation.rst | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/translation.rst b/translation.rst index c8996c08b48..7800161d77b 100644 --- a/translation.rst +++ b/translation.rst @@ -1160,6 +1160,67 @@ service argument with the :class:`Symfony\\Component\\Translation\\LocaleSwitche class to inject the locale switcher service. Otherwise, configure your services manually and inject the ``translation.locale_switcher`` service. +.. _translation-global-variables: + +Global Variables +~~~~~~~~~~~~~~~~ + +The translator allows you to automatically configure global variables that will be available +for the translation process. These global variables are defined in the ``translations.globals`` +option inside the main configuration file: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/translator.yaml + translator: + # ... + globals: + '%%app_name%%': 'My application' + '{app_version}': '1.2.3' + '{url}': { message: 'url', parameters: { scheme: 'https://' }, domain: 'global' } + + .. code-block:: xml + + + + + + + + + My application + + + https:// + + + + + + .. code-block:: php + + // config/packages/translator.php + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $translator): void { + // ... + $translator->globals('%%app_name%%')->value('My application'); + $translator->globals('{app_version}')->value('1.2.3'); + $translator->globals('{url}')->value(['message' => 'url', 'parameters' => ['scheme' => 'https://']); + }; + +.. versionadded:: 7.3 + + The ``translator:globals`` option was introduced in Symfony 7.3. + .. _translation-debug: How to Find Missing or Unused Translation Messages From 97d301a5c1c4a69f3958777b95d9c8ffcd4b928b Mon Sep 17 00:00:00 2001 From: Pierre Ambroise Date: Wed, 2 Apr 2025 11:41:05 +0200 Subject: [PATCH 388/427] [Messenger] Document stamps in HandleTrait::handle --- messenger.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/messenger.rst b/messenger.rst index fc8f9491022..159dd567a34 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2512,6 +2512,20 @@ wherever you need a query bus behavior instead of the ``MessageBusInterface``:: } } +You also can also add stamps when handling a message. For example, you can +add an ``DoctrineFlushStamp`` to flush the entity manager after handling the message:: + + $this->handle(new SomeMessage($data), [new DoctrineFlushStamp()]); + +.. note:: + + If adding a stamp of the same type that already exists in the envelope, + both stamps will be kept (see `Envelopes & Stamps`_). + +.. versionadded:: 7.3 + + The ``$stamps`` parameter on the handle method was introduced in Symfony 7.3. + Customizing Handlers -------------------- From c2c14fd74b50128ffd986919aec8c1fc7cf49cca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Apr 2025 09:40:08 +0200 Subject: [PATCH 389/427] Minor tweak --- messenger.rst | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/messenger.rst b/messenger.rst index 47e0ad61906..b05056243c2 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2525,19 +2525,15 @@ wherever you need a query bus behavior instead of the ``MessageBusInterface``:: } } -You also can also add stamps when handling a message. For example, you can -add an ``DoctrineFlushStamp`` to flush the entity manager after handling the message:: +You can also add new stamps when handling a message; they will be appended +to the existing ones. For example, you can add a ``DoctrineFlushStamp`` to +flush the entity manager after handling the message:: $this->handle(new SomeMessage($data), [new DoctrineFlushStamp()]); -.. note:: - - If adding a stamp of the same type that already exists in the envelope, - both stamps will be kept (see `Envelopes & Stamps`_). - .. versionadded:: 7.3 - The ``$stamps`` parameter on the handle method was introduced in Symfony 7.3. + The ``$stamps`` parameter of the ``handle()`` method was introduced in Symfony 7.3. Customizing Handlers -------------------- From 7f9f20fcd83889b0725ec7d6e7192af8dc2391c8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Apr 2025 10:16:39 +0200 Subject: [PATCH 390/427] [Mesenger] Fix code example --- messenger.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index b05056243c2..9078a500d11 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2526,10 +2526,9 @@ wherever you need a query bus behavior instead of the ``MessageBusInterface``:: } You can also add new stamps when handling a message; they will be appended -to the existing ones. For example, you can add a ``DoctrineFlushStamp`` to -flush the entity manager after handling the message:: +to the existing ones:: - $this->handle(new SomeMessage($data), [new DoctrineFlushStamp()]); + $this->handle(new SomeMessage($data), [new SomeStamp(), new AnotherStamp()]); .. versionadded:: 7.3 From 11b256998374bdfbfa7a0155cf1274661a15811b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 8 Apr 2025 11:03:16 +0200 Subject: [PATCH 391/427] Tweaks and rewords --- translation.rst | 139 +++++++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 61 deletions(-) diff --git a/translation.rst b/translation.rst index 7800161d77b..35751d7db5f 100644 --- a/translation.rst +++ b/translation.rst @@ -416,6 +416,84 @@ You can also specify the message domain and pass some additional variables: major difference: automatic output escaping is **not** applied to translations using a tag. +Global Translation Parameters +----------------------------- + +.. versionadded:: 7.3 + + The global translation parameters feature was introduced in Symfony 7.3. + +If the content of a translation parameter is repeated across multiple +translation messages (e.g. a company name, or a version number), you can define +it as a global translation parameter. This helps you avoid repeating the same +values manually in each message. + +You can configure these global parameters in the ``translations.globals`` option +of your main configuration file using either ``%...%`` or ``{...}`` syntax: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/translator.yaml + translator: + # ... + globals: + # when using the '%' wrapping characters, you must escape them + '%%app_name%%': 'My application' + '{app_version}': '1.2.3' + '{url}': { message: 'url', parameters: { scheme: 'https://' }, domain: 'global' } + + .. code-block:: xml + + + + + + + + + + My application + + + https:// + + + + + + .. code-block:: php + + // config/packages/translator.php + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $translator): void { + // ... + // when using the '%' wrapping characters, you must escape them + $translator->globals('%%app_name%%')->value('My application'); + $translator->globals('{app_version}')->value('1.2.3'); + $translator->globals('{url}')->value(['message' => 'url', 'parameters' => ['scheme' => 'https://']]); + }; + +Once defined, you can use these parameters in translation messages anywhere in +your application: + +.. code-block:: twig + + {{ 'Application version: {version}'|trans }} + {# output: "Application version: 1.2.3" #} + + {# parameters passed to the message override global parameters #} + {{ 'Package version: {version}'|trans({'{version}': '2.3.4'}) }} + # Displays "Package version: 2.3.4" + Forcing the Translator Locale ----------------------------- @@ -1160,67 +1238,6 @@ service argument with the :class:`Symfony\\Component\\Translation\\LocaleSwitche class to inject the locale switcher service. Otherwise, configure your services manually and inject the ``translation.locale_switcher`` service. -.. _translation-global-variables: - -Global Variables -~~~~~~~~~~~~~~~~ - -The translator allows you to automatically configure global variables that will be available -for the translation process. These global variables are defined in the ``translations.globals`` -option inside the main configuration file: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/translator.yaml - translator: - # ... - globals: - '%%app_name%%': 'My application' - '{app_version}': '1.2.3' - '{url}': { message: 'url', parameters: { scheme: 'https://' }, domain: 'global' } - - .. code-block:: xml - - - - - - - - - My application - - - https:// - - - - - - .. code-block:: php - - // config/packages/translator.php - use Symfony\Config\TwigConfig; - - return static function (TwigConfig $translator): void { - // ... - $translator->globals('%%app_name%%')->value('My application'); - $translator->globals('{app_version}')->value('1.2.3'); - $translator->globals('{url}')->value(['message' => 'url', 'parameters' => ['scheme' => 'https://']); - }; - -.. versionadded:: 7.3 - - The ``translator:globals`` option was introduced in Symfony 7.3. - .. _translation-debug: How to Find Missing or Unused Translation Messages From fff52938f54f32cb6b246f73423affbe1365660b Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 8 Apr 2025 07:23:44 -0400 Subject: [PATCH 392/427] [RateLimiter] deprecate injecting `RateLimiterFactory` --- rate_limiter.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 81bd7f5689e..1036e80e682 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -230,6 +230,12 @@ prevents that number from being higher than 5,000). Rate Limiting in Action ----------------------- +.. versionadded:: 7.3 + + :class:`Symfony\\Component\\RateLimiter\\RateLimiterFactoryInterface` was + added and should now be used for autowiring instead of + :class:`Symfony\\Component\\RateLimiter\\RateLimiterFactory`. + After having installed and configured the rate limiter, inject it in any service or controller and call the ``consume()`` method to try to consume a given number of tokens. For example, this controller uses the previous rate limiter to control @@ -242,13 +248,13 @@ the number of requests to the API:: use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; - use Symfony\Component\RateLimiter\RateLimiterFactory; + use Symfony\Component\RateLimiter\RateLimiterFactoryInterface; class ApiController extends AbstractController { // if you're using service autowiring, the variable name must be: // "rate limiter name" (in camelCase) + "Limiter" suffix - public function index(Request $request, RateLimiterFactory $anonymousApiLimiter): Response + public function index(Request $request, RateLimiterFactoryInterface $anonymousApiLimiter): Response { // create a limiter based on a unique identifier of the client // (e.g. the client's IP address, a username/email, an API key, etc.) @@ -291,11 +297,11 @@ using the ``reserve()`` method:: use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\RateLimiter\RateLimiterFactory; + use Symfony\Component\RateLimiter\RateLimiterFactoryInterface; class ApiController extends AbstractController { - public function registerUser(Request $request, RateLimiterFactory $authenticatedApiLimiter): Response + public function registerUser(Request $request, RateLimiterFactoryInterface $authenticatedApiLimiter): Response { $apiKey = $request->headers->get('apikey'); $limiter = $authenticatedApiLimiter->create($apiKey); @@ -350,11 +356,11 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\RateLimiter\RateLimiterFactory; + use Symfony\Component\RateLimiter\RateLimiterFactoryInterface; class ApiController extends AbstractController { - public function index(Request $request, RateLimiterFactory $anonymousApiLimiter): Response + public function index(Request $request, RateLimiterFactoryInterface $anonymousApiLimiter): Response { $limiter = $anonymousApiLimiter->create($request->getClientIp()); $limit = $limiter->consume(); From 35349c17b05de94e156ca0247b2f4d9f887aaa3a Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 8 Apr 2025 07:45:37 -0400 Subject: [PATCH 393/427] [RateLimiter] compound rate limiter --- rate_limiter.rst | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/rate_limiter.rst b/rate_limiter.rst index 81bd7f5689e..906e787e7e1 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -541,6 +541,123 @@ at all): lock factory (``lock.factory``) failed if the Symfony Lock component was not installed in the application. +Compound Rate Limiter +--------------------- + +.. versionadded:: 7.3 + + Configuring compound rate limiters was added in 7.3. + +You can configure multiple rate limiters to work together: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + two_per_minute: + policy: 'fixed_window' + limit: 2 + interval: '1 minute' + five_per_hour: + policy: 'fixed_window' + limit: 5 + interval: '1 hour' + contact_form: + policy: 'compound' + limiters: [two_per_minute, five_per_hour] + + .. code-block:: xml + + + + + + + + + + + + + two_per_minute + five_per_hour + + + + + + .. code-block:: php + + // config/packages/rate_limiter.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework): void { + $framework->rateLimiter() + ->limiter('two_per_minute') + ->policy('fixed_window') + ->limit(2) + ->interval('1 minute') + ; + + $framework->rateLimiter() + ->limiter('two_per_minute') + ->policy('fixed_window') + ->limit(5) + ->interval('1 hour') + ; + + $framework->rateLimiter() + ->limiter('contact_form') + ->policy('compound') + ->limiters(['two_per_minute', 'five_per_hour']) + ; + }; + +Then, inject and use as normal:: + + // src/Controller/ContactController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\RateLimiter\RateLimiterFactory; + + class ContactController extends AbstractController + { + public function registerUser(Request $request, RateLimiterFactoryInterface $contactFormLimiter): Response + { + $limiter = $contactFormLimiter->create($request->getClientIp()); + + if (false === $limiter->consume(1)->isAccepted()) { + // either of the two limiters has been reached + } + + // ... + } + + // ... + } + .. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html .. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html .. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/ From 70716ab76d3e4066668c81ad1be465e3dc1a772e Mon Sep 17 00:00:00 2001 From: Hubert Lenoir Date: Tue, 8 Apr 2025 17:57:53 +0200 Subject: [PATCH 394/427] Update service_container.rst to 7.3 --- service_container.rst | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/service_container.rst b/service_container.rst index 30b69b8aa14..9a024e5e320 100644 --- a/service_container.rst +++ b/service_container.rst @@ -162,10 +162,6 @@ each time you ask for it. # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/' - exclude: - - '../src/DependencyInjection/' - - '../src/Entity/' - - '../src/Kernel.php' # order is important in this file because service definitions # always *replace* previous ones; add your own service configuration below @@ -187,7 +183,7 @@ each time you ask for it. - + @@ -212,8 +208,7 @@ each time you ask for it. // makes classes in src/ available to be used as services // this creates a service per class whose id is the fully-qualified class name - $services->load('App\\', '../src/') - ->exclude('../src/{DependencyInjection,Entity,Kernel.php}'); + $services->load('App\\', '../src/'); // order is important in this file because service definitions // always *replace* previous ones; add your own service configuration below @@ -221,9 +216,7 @@ each time you ask for it. .. tip:: - The value of the ``resource`` and ``exclude`` options can be any valid - `glob pattern`_. The value of the ``exclude`` option can also be an - array of glob patterns. + The value of the ``resource`` option can be any valid `glob pattern`_. Thanks to this configuration, you can automatically use any classes from the ``src/`` directory as a service, without needing to manually configure From c0f12c7408489bb8031b77d2caea5e3ce547781f Mon Sep 17 00:00:00 2001 From: "hubert.lenoir" Date: Tue, 8 Apr 2025 20:36:41 +0200 Subject: [PATCH 395/427] [Translation] Fix Lint (DOCtor-RST) --- translation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index 35751d7db5f..86282090801 100644 --- a/translation.rst +++ b/translation.rst @@ -461,7 +461,7 @@ of your main configuration file using either ``%...%`` or ``{...}`` syntax: My application - + https:// From ac9e20cad5195c101d843bcb6cb391f0b9316011 Mon Sep 17 00:00:00 2001 From: Mokhtar Tlili Date: Tue, 8 Apr 2025 21:05:43 +0200 Subject: [PATCH 396/427] Add docs for bridge twig validator #20836 --- bridge/twig/validation.rst | 63 ++++++++++++++++++++++++++++++++++++++ index.rst | 1 + twig_bridge.rst | 9 ++++++ 3 files changed, 73 insertions(+) create mode 100644 bridge/twig/validation.rst create mode 100644 twig_bridge.rst diff --git a/bridge/twig/validation.rst b/bridge/twig/validation.rst new file mode 100644 index 00000000000..e7b887f5588 --- /dev/null +++ b/bridge/twig/validation.rst @@ -0,0 +1,63 @@ +Validating Twig Template Syntax +=============================== + +The Twig Bridge provides a custom `Twig` constraint that allows validating +whether a given string contains valid Twig syntax. + +This is particularly useful when template content is user-generated or +configurable, and you want to ensure it can be safely rendered by the Twig engine. + +Installation +------------ + +This constraint is part of the `symfony/twig-bridge` package. Make sure it's installed: + +.. code-block:: terminal + + $ composer require symfony/twig-bridge + +Usage +----- + +To use the `Twig` constraint, annotate the property that should contain a valid +Twig template:: + + use Symfony\Bridge\Twig\Validator\Constraints\Twig; + + class Template + { + #[Twig] + private string $templateCode; + } + +If the template contains a syntax error, a validation error will be thrown. + +Constraint Options +------------------ + +**message** +Customize the default error message when the template is invalid:: + + // ... + class Template + { + #[Twig(message: 'Your template contains a syntax error.')] + private string $templateCode; + } + +**skipDeprecations** +By default, this option is set to `true`, which means Twig deprecation warnings +are ignored during validation. + +If you want validation to fail when deprecated features are used in the template, +set this to `false`:: + + // ... + class Template + { + #[Twig(skipDeprecations: false)] + private string $templateCode; + } + +This can be helpful when enforcing stricter template rules or preparing for major +Twig version upgrades. diff --git a/index.rst b/index.rst index c566e5f8671..2bd09c8c0dc 100644 --- a/index.rst +++ b/index.rst @@ -60,6 +60,7 @@ Topics web_link webhook workflow + twig_bridge Components ---------- diff --git a/twig_bridge.rst b/twig_bridge.rst new file mode 100644 index 00000000000..bb7d84f7e9a --- /dev/null +++ b/twig_bridge.rst @@ -0,0 +1,9 @@ +Twig Bridge +=========== + +This bridge integrates Symfony with the Twig templating engine. + +.. toctree:: + :maxdepth: 1 + + bridge/twig/validation From a7a6c1d23db3430752cbdf59354aad47aaa4ef32 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 8 Apr 2025 07:13:46 -0400 Subject: [PATCH 397/427] [Scheduler][Webhook] add screencast links --- scheduler.rst | 6 ++++++ webhook.rst | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/scheduler.rst b/scheduler.rst index a09fabfc4ca..1630fd8dada 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -1,6 +1,11 @@ Scheduler ========= +.. admonition:: Screencast + :class: screencast + + Like video tutorials? Check out this `Scheduler quick-start screencast`_. + The scheduler component manages task scheduling within your PHP application, like running a task each night at 3 AM, every two weeks except for holidays or any other custom schedule you might need. @@ -1008,3 +1013,4 @@ helping you identify those messages when needed. .. _`cron command-line utility`: https://en.wikipedia.org/wiki/Cron .. _`crontab.guru website`: https://crontab.guru/ .. _`relative formats`: https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative +.. _`Scheduler quick-start screencast`: https://symfonycasts.com/screencast/mailtrap/bonus-symfony-scheduler diff --git a/webhook.rst b/webhook.rst index aba95cffb04..9d6b56c7ef0 100644 --- a/webhook.rst +++ b/webhook.rst @@ -15,6 +15,11 @@ Installation Usage in Combination with the Mailer Component ---------------------------------------------- +.. admonition:: Screencast + :class: screencast + + Like video tutorials? Check out the `Webhook Component for Email Events screencast`_. + When using a third-party mailer provider, you can use the Webhook component to receive webhook calls from this provider. @@ -207,3 +212,4 @@ Creating a Custom Webhook Webhook. .. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html +.. _`Webhook Component for Email Events screencast`: https://symfonycasts.com/screencast/mailtrap/email-event-webhook From 59fd3a3f167c8c799fad3256ace24dc8a72501de Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 9 Apr 2025 12:31:13 +0200 Subject: [PATCH 398/427] Tweaks --- service_container.rst | 44 ++++++++++++++++++++++++++++++++++++ service_container/import.rst | 7 ++---- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/service_container.rst b/service_container.rst index 9a024e5e320..6ae601cf724 100644 --- a/service_container.rst +++ b/service_container.rst @@ -223,6 +223,50 @@ each time you ask for it. it. Later, you'll learn how to :ref:`import many services at once ` with resource. + If some files or directories in your project should not become services, you + can exclude them using the ``exclude`` option: + + .. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + # ... + App\: + resource: '../src/' + exclude: + - '../src/SomeDirectory/' + - '../src/AnotherDirectory/' + - '../src/SomeFile.php' + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $container): void { + // ... + + $services->load('App\\', '../src/') + ->exclude('../src/{SomeDirectory,AnotherDirectory,Kernel.php}'); + }; + If you'd prefer to manually wire your service, you can :ref:`use explicit configuration `. diff --git a/service_container/import.rst b/service_container/import.rst index d5056032115..293cb5b97c2 100644 --- a/service_container/import.rst +++ b/service_container/import.rst @@ -82,7 +82,6 @@ a relative or absolute path to the imported file: App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' # ... @@ -104,8 +103,7 @@ a relative or absolute path to the imported file: - + @@ -127,8 +125,7 @@ a relative or absolute path to the imported file: ->autoconfigure() ; - $services->load('App\\', '../src/*') - ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + $services->load('App\\', '../src/*'); }; When loading a configuration file, Symfony loads first the imported files and From 518fc3a24cfd03eff976cf296997edc8e2aea2f8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 9 Apr 2025 16:22:11 +0200 Subject: [PATCH 399/427] Minor tweak --- rate_limiter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 4bd213d2363..3a517c37bd4 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -552,7 +552,7 @@ Compound Rate Limiter .. versionadded:: 7.3 - Configuring compound rate limiters was added in 7.3. + Support for configuring compound rate limiters was introduced in Symfony 7.3. You can configure multiple rate limiters to work together: From fcfcacb6afdd7b6fcbdf5587f9c59140b9d5f887 Mon Sep 17 00:00:00 2001 From: Van Truong PHAN Date: Thu, 10 Apr 2025 04:44:59 +0200 Subject: [PATCH 400/427] Franken PHP can perform some action after the response has been streamed to the user Franken also implements fastcgi_finish_request PHP function. kernel.terminate event works well with franken. --- components/http_kernel.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/http_kernel.rst b/components/http_kernel.rst index 351a2123b90..cf16de9fe61 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -497,8 +497,8 @@ as possible to the client (e.g. sending emails). .. warning:: Internally, the HttpKernel makes use of the :phpfunction:`fastcgi_finish_request` - PHP function. This means that at the moment, only the `PHP FPM`_ server - API is able to send a response to the client while the server's PHP process + PHP function. This means that at the moment, only the `PHP FPM`_ and `FrankenPHP`_ servers + API are able to send a response to the client while the server's PHP process still performs some tasks. With all other server APIs, listeners to ``kernel.terminate`` are still executed, but the response is not sent to the client until they are all completed. @@ -770,3 +770,4 @@ Learn more .. _FOSRestBundle: https://github.com/friendsofsymfony/FOSRestBundle .. _`PHP FPM`: https://www.php.net/manual/en/install.fpm.php .. _variadic: https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list +.. _`FrankenPHP`: https://frankenphp.dev From ccd113706035d4d5c09342c2d8de207d138cf53c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 10 Apr 2025 08:03:25 +0200 Subject: [PATCH 401/427] Minor tweak --- components/http_kernel.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/http_kernel.rst b/components/http_kernel.rst index cf16de9fe61..91643086a18 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -497,8 +497,8 @@ as possible to the client (e.g. sending emails). .. warning:: Internally, the HttpKernel makes use of the :phpfunction:`fastcgi_finish_request` - PHP function. This means that at the moment, only the `PHP FPM`_ and `FrankenPHP`_ servers - API are able to send a response to the client while the server's PHP process + PHP function. This means that at the moment, only the `PHP FPM`_ API and the + `FrankenPHP`_ server are able to send a response to the client while the server's PHP process still performs some tasks. With all other server APIs, listeners to ``kernel.terminate`` are still executed, but the response is not sent to the client until they are all completed. From 344d8baac24247f9a0637bec61a2896e9404c43b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 10 Apr 2025 09:12:48 +0200 Subject: [PATCH 402/427] Reorganized the contents of the new constraint --- bridge/twig/validation.rst | 63 --------------- index.rst | 1 - reference/constraints/Twig.rst | 130 ++++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + twig_bridge.rst | 9 --- 5 files changed, 131 insertions(+), 73 deletions(-) delete mode 100644 bridge/twig/validation.rst create mode 100644 reference/constraints/Twig.rst delete mode 100644 twig_bridge.rst diff --git a/bridge/twig/validation.rst b/bridge/twig/validation.rst deleted file mode 100644 index e7b887f5588..00000000000 --- a/bridge/twig/validation.rst +++ /dev/null @@ -1,63 +0,0 @@ -Validating Twig Template Syntax -=============================== - -The Twig Bridge provides a custom `Twig` constraint that allows validating -whether a given string contains valid Twig syntax. - -This is particularly useful when template content is user-generated or -configurable, and you want to ensure it can be safely rendered by the Twig engine. - -Installation ------------- - -This constraint is part of the `symfony/twig-bridge` package. Make sure it's installed: - -.. code-block:: terminal - - $ composer require symfony/twig-bridge - -Usage ------ - -To use the `Twig` constraint, annotate the property that should contain a valid -Twig template:: - - use Symfony\Bridge\Twig\Validator\Constraints\Twig; - - class Template - { - #[Twig] - private string $templateCode; - } - -If the template contains a syntax error, a validation error will be thrown. - -Constraint Options ------------------- - -**message** -Customize the default error message when the template is invalid:: - - // ... - class Template - { - #[Twig(message: 'Your template contains a syntax error.')] - private string $templateCode; - } - -**skipDeprecations** -By default, this option is set to `true`, which means Twig deprecation warnings -are ignored during validation. - -If you want validation to fail when deprecated features are used in the template, -set this to `false`:: - - // ... - class Template - { - #[Twig(skipDeprecations: false)] - private string $templateCode; - } - -This can be helpful when enforcing stricter template rules or preparing for major -Twig version upgrades. diff --git a/index.rst b/index.rst index 2bd09c8c0dc..c566e5f8671 100644 --- a/index.rst +++ b/index.rst @@ -60,7 +60,6 @@ Topics web_link webhook workflow - twig_bridge Components ---------- diff --git a/reference/constraints/Twig.rst b/reference/constraints/Twig.rst new file mode 100644 index 00000000000..8435c191855 --- /dev/null +++ b/reference/constraints/Twig.rst @@ -0,0 +1,130 @@ +Twig Constraint +=============== + +.. versionadded:: 7.3 + + The ``Twig`` constraint was introduced in Symfony 7.3. + +Validates that a given string contains valid :ref:`Twig syntax `. +This is particularly useful when template content is user-generated or +configurable, and you want to ensure it can be rendered by the Twig engine. + +.. note:: + + Using this constraint requires having the ``symfony/twig-bridge`` package + installed in your application (e.g. by running ``composer require symfony/twig-bridge``). + +========== =================================================================== +Applies to :ref:`property or method ` +Class :class:`Symfony\\Bridge\\Twig\\Validator\\Constraints\\Twig` +Validator :class:`Symfony\\Bridge\\Twig\\Validator\\Constraints\\TwigValidator` +========== =================================================================== + +Basic Usage +----------- + +Apply the ``Twig`` constraint to validate the contents of any property or the +returned value of any method: + + use Symfony\Bridge\Twig\Validator\Constraints\Twig; + + class Template + { + #[Twig] + private string $templateCode; + } + +.. configuration-block:: + + .. code-block:: php-attributes + + // src/Entity/Page.php + namespace App\Entity; + + use Symfony\Bridge\Twig\Validator\Constraints\Twig; + + class Page + { + #[Twig] + private string $templateCode; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\Page: + properties: + templateCode: + - Symfony\Bridge\Twig\Validator\Constraints\Twig: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Page.php + namespace App\Entity; + + use Symfony\Bridge\Twig\Validator\Constraints\Twig; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class Page + { + // ... + + public static function loadValidatorMetadata(ClassMetadata $metadata): void + { + $metadata->addPropertyConstraint('templateCode', new Twig()); + } + } + +Constraint Options +------------------ + +``message`` +~~~~~~~~~~~ + +**type**: ``message`` **default**: ``This value is not a valid Twig template.`` + +This is the message displayed when the given string does *not* contain valid Twig syntax:: + + // ... + + class Page + { + #[Twig(message: 'Check this Twig code; it contains errors.')] + private string $templateCode; + } + +This message has no parameters. + +``skipDeprecations`` +~~~~~~~~~~~~~~~~~~~~ + +**type**: ``boolean`` **default**: ``true`` + +If ``true``, Twig deprecation warnings are ignored during validation. Set it to +``false`` to trigger validation errors when the given Twig code contains any deprecations:: + + // ... + + class Page + { + #[Twig(skipDeprecations: false)] + private string $templateCode; + } + +This can be helpful when enforcing stricter template rules or preparing for major +Twig version upgrades. diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 58801a8c653..c2396ae3af7 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -34,6 +34,7 @@ String Constraints * :doc:`PasswordStrength ` * :doc:`Regex ` * :doc:`Slug ` +* :doc:`Twig ` * :doc:`Ulid ` * :doc:`Url ` * :doc:`UserPassword ` diff --git a/twig_bridge.rst b/twig_bridge.rst deleted file mode 100644 index bb7d84f7e9a..00000000000 --- a/twig_bridge.rst +++ /dev/null @@ -1,9 +0,0 @@ -Twig Bridge -=========== - -This bridge integrates Symfony with the Twig templating engine. - -.. toctree:: - :maxdepth: 1 - - bridge/twig/validation From b5f3bf13ed6858bb79901593bac9b3571ad53388 Mon Sep 17 00:00:00 2001 From: Antoine M Date: Fri, 11 Apr 2025 14:43:37 +0200 Subject: [PATCH 403/427] Update end_to_end.rst --- testing/end_to_end.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/end_to_end.rst b/testing/end_to_end.rst index bb4a316f347..83d61b1e60f 100644 --- a/testing/end_to_end.rst +++ b/testing/end_to_end.rst @@ -26,7 +26,7 @@ to install the needed dependencies: .. code-block:: terminal - $ composer require symfony/panther + $ composer require --dev symfony/panther .. include:: /components/require_autoload.rst.inc From ce286296c47b9d53358a75df75f3f267b0286a75 Mon Sep 17 00:00:00 2001 From: Antoine M Date: Thu, 10 Apr 2025 19:43:53 +0200 Subject: [PATCH 404/427] [Serializer] (re)document PRESERVE_EMPTY_OBJECTS --- serializer.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/serializer.rst b/serializer.rst index 6e20a651341..b7deb6f5bff 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1571,6 +1571,13 @@ to ``true``:: ]); // $jsonContent contains {"name":"Jane Doe"} +Preserving Empty Objetcs +~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, the Serializer will transform an empty array to `[]`. +You can change this behavior by setting the ``AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS`` context option +to ``true``, when the value is `\ArrayObject()` the serialization would be `{}`. + Handling Uninitialized Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From e384239df47030f05c3547139678c37218400ab2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 14 Apr 2025 10:40:54 +0200 Subject: [PATCH 405/427] Tweaks --- serializer.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/serializer.rst b/serializer.rst index b7deb6f5bff..440494d0be1 100644 --- a/serializer.rst +++ b/serializer.rst @@ -1571,12 +1571,13 @@ to ``true``:: ]); // $jsonContent contains {"name":"Jane Doe"} -Preserving Empty Objetcs +Preserving Empty Objects ~~~~~~~~~~~~~~~~~~~~~~~~ -By default, the Serializer will transform an empty array to `[]`. -You can change this behavior by setting the ``AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS`` context option -to ``true``, when the value is `\ArrayObject()` the serialization would be `{}`. +By default, the Serializer transforms an empty array to ``[]``. You can change +this behavior by setting the ``AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS`` +context option to ``true``. When the value is an instance of ``\ArrayObject()``, +the serialized data will be ``{}``. Handling Uninitialized Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 3a572358ae6cfafa90748178292a6e24c9ab9321 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 14 Apr 2025 10:59:37 +0200 Subject: [PATCH 406/427] Update the build script to mention that it does not support Windows --- _build/build.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/_build/build.php b/_build/build.php index 454553d459e..b80d8e0e51e 100755 --- a/_build/build.php +++ b/_build/build.php @@ -15,6 +15,13 @@ ->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...'); From cb186580124e06ed65024404856642ffb29ab1f9 Mon Sep 17 00:00:00 2001 From: jdevinemt <65512359+jdevinemt@users.noreply.github.com> Date: Thu, 20 Mar 2025 17:07:39 -0600 Subject: [PATCH 407/427] [Deployment] - More accurate local .env file recommendation --- deployment.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/deployment.rst b/deployment.rst index 864ebc7a963..87e88f10ff8 100644 --- a/deployment.rst +++ b/deployment.rst @@ -134,14 +134,13 @@ B) Configure your Environment Variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Most Symfony applications read their configuration from environment variables. -While developing locally, you'll usually store these in ``.env`` and ``.env.local`` -(for local overrides). On production, you have two options: +While developing locally, you'll usually store these in :ref:`.env files `. On production, you have two options: 1. Create "real" environment variables. How you set environment variables, depends on your setup: they can be set at the command line, in your Nginx configuration, or via other methods provided by your hosting service; -2. Or, create a ``.env.local`` file like your local development. +2. Or, create a ``.env.prod.local`` file containing values specific to your production environment. There is no significant advantage to either of the two options: use whatever is most natural in your hosting environment. From 059ecfa24b88db20e962a8e6a4cee88244de65ec Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 14 Apr 2025 17:42:27 +0200 Subject: [PATCH 408/427] Minor tweaks --- deployment.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/deployment.rst b/deployment.rst index 87e88f10ff8..07187f53cba 100644 --- a/deployment.rst +++ b/deployment.rst @@ -134,16 +134,18 @@ B) Configure your Environment Variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Most Symfony applications read their configuration from environment variables. -While developing locally, you'll usually store these in :ref:`.env files `. On production, you have two options: +While developing locally, you'll usually store these in :ref:`.env files `. +On production, you have two options: 1. Create "real" environment variables. How you set environment variables, depends on your setup: they can be set at the command line, in your Nginx configuration, or via other methods provided by your hosting service; -2. Or, create a ``.env.prod.local`` file containing values specific to your production environment. +2. Or, create a ``.env.prod.local`` file that contains values specific to your + production environment. -There is no significant advantage to either of the two options: use whatever is -most natural in your hosting environment. +There is no significant advantage to either option: use whichever is most natural +for your hosting environment. .. tip:: From 0ce5ffbbbd24e0230e7ec527b372958e0cb53e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 14 Apr 2025 17:23:22 +0200 Subject: [PATCH 409/427] [HttpFoundation] Add FrankenPHP docs for X-Sendfile --- components/http_foundation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 9a4f0b61516..5a0c24ef618 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -854,7 +854,7 @@ Alternatively, if you are serving a static file, you can use a The ``BinaryFileResponse`` will automatically handle ``Range`` and ``If-Range`` headers from the request. It also supports ``X-Sendfile`` -(see for `nginx`_ and `Apache`_). To make use of it, you need to determine +(see for `FrankenPHP`_, `nginx`_ and `Apache`_). To make use of it, you need to determine whether or not the ``X-Sendfile-Type`` header should be trusted and call :method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::trustXSendfileTypeHeader` if it should:: @@ -1061,6 +1061,7 @@ Learn More /session /http_cache/* +.. _FrankenPHP: https://frankenphp.dev/docs/x-sendfile/ .. _nginx: https://mattbrictson.com/blog/accelerated-rails-downloads .. _Apache: https://tn123.org/mod_xsendfile/ .. _`JSON Hijacking`: https://haacked.com/archive/2009/06/25/json-hijacking.aspx/ From afc84e2242147e1c7137a4d380b9e0736d86626c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 14 Apr 2025 17:58:24 +0200 Subject: [PATCH 410/427] Update the links related to X-Sendfile and X-Accel-Redirect --- components/http_foundation.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 5a0c24ef618..14843bab346 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -854,9 +854,10 @@ Alternatively, if you are serving a static file, you can use a The ``BinaryFileResponse`` will automatically handle ``Range`` and ``If-Range`` headers from the request. It also supports ``X-Sendfile`` -(see for `FrankenPHP`_, `nginx`_ and `Apache`_). To make use of it, you need to determine -whether or not the ``X-Sendfile-Type`` header should be trusted and call -:method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::trustXSendfileTypeHeader` +(see `FrankenPHP X-Sendfile and X-Accel-Redirect headers`_, +`nginx X-Accel-Redirect header`_ and `Apache mod_xsendfile module`_). To make use +of it, you need to determine whether or not the ``X-Sendfile-Type`` header should +be trusted and call :method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::trustXSendfileTypeHeader` if it should:: BinaryFileResponse::trustXSendfileTypeHeader(); @@ -1061,9 +1062,9 @@ Learn More /session /http_cache/* -.. _FrankenPHP: https://frankenphp.dev/docs/x-sendfile/ -.. _nginx: https://mattbrictson.com/blog/accelerated-rails-downloads -.. _Apache: https://tn123.org/mod_xsendfile/ +.. _`FrankenPHP X-Sendfile and X-Accel-Redirect headers`: https://frankenphp.dev/docs/x-sendfile/ +.. _`nginx X-Accel-Redirect header`: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers +.. _`Apache mod_xsendfile module`: https://github.com/nmaier/mod_xsendfile .. _`JSON Hijacking`: https://haacked.com/archive/2009/06/25/json-hijacking.aspx/ .. _`valid JSON top-level value`: https://www.json.org/json-en.html .. _OWASP guidelines: https://cheatsheetseries.owasp.org/cheatsheets/AJAX_Security_Cheat_Sheet.html#always-return-json-with-an-object-on-the-outside From a8a4523bcdfd889b2f9afee9342a655a879e090c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 15 Apr 2025 17:18:46 +0200 Subject: [PATCH 411/427] Fix a syntax issue in Coding Standards --- contributing/code/standards.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing/code/standards.rst b/contributing/code/standards.rst index 3a00343faf1..ebfde7dfab4 100644 --- a/contributing/code/standards.rst +++ b/contributing/code/standards.rst @@ -211,7 +211,7 @@ Naming Conventions * Use `camelCase`_ for PHP variables, function and method names, arguments (e.g. ``$acceptableContentTypes``, ``hasSession()``); -Use `snake_case`_ for configuration parameters, route names and Twig template +* Use `snake_case`_ for configuration parameters, route names and Twig template variables (e.g. ``framework.csrf_protection``, ``http_status_code``); * Use SCREAMING_SNAKE_CASE for constants (e.g. ``InputArgument::IS_ARRAY``); From 4f50290a46361fdf8907ecfa53beb8c6864330d8 Mon Sep 17 00:00:00 2001 From: Antoine M Date: Tue, 15 Apr 2025 11:33:07 +0200 Subject: [PATCH 412/427] feat: swap from event constant to event class --- event_dispatcher.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 7372d58b8d0..b854488de52 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -246,14 +246,13 @@ methods could be called before or after the methods defined in other listeners and subscribers. To learn more about event subscribers, read :doc:`/components/event_dispatcher`. The following example shows an event subscriber that defines several methods which -listen to the same ``kernel.exception`` event:: +listen to the same ``kernel.exception`` event which has an ``ExceptionEvent``:: // src/EventSubscriber/ExceptionSubscriber.php namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ExceptionEvent; - use Symfony\Component\HttpKernel\KernelEvents; class ExceptionSubscriber implements EventSubscriberInterface { @@ -261,7 +260,7 @@ listen to the same ``kernel.exception`` event:: { // return the subscribed events, their methods and priorities return [ - KernelEvents::EXCEPTION => [ + ExceptionEvent::class => [ ['processException', 10], ['logException', 0], ['notifyException', -10], From a6e0879c81c9009fcd376a144c0f97702b60213f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 15 Apr 2025 17:36:40 +0200 Subject: [PATCH 413/427] Minor tweak --- event_dispatcher.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index b854488de52..8e5c3d092e0 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -246,7 +246,8 @@ methods could be called before or after the methods defined in other listeners and subscribers. To learn more about event subscribers, read :doc:`/components/event_dispatcher`. The following example shows an event subscriber that defines several methods which -listen to the same ``kernel.exception`` event which has an ``ExceptionEvent``:: +listen to the same :ref:`kernel.exception event `_ +via its ``ExceptionEvent`` class:: // src/EventSubscriber/ExceptionSubscriber.php namespace App\EventSubscriber; From 90def249610950e1811cd70d5bc1a94caf09ad15 Mon Sep 17 00:00:00 2001 From: Ousmane NDIAYE Date: Tue, 15 Apr 2025 16:47:27 +0200 Subject: [PATCH 414/427] Update embedded.rst Comment added to specify the name of the fil to edit. (As previous examples) --- form/embedded.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/form/embedded.rst b/form/embedded.rst index dd163235f03..9e20164c3a4 100644 --- a/form/embedded.rst +++ b/form/embedded.rst @@ -87,6 +87,7 @@ inside the task form itself. To accomplish this, add a ``category`` field to the ``TaskType`` object whose type is an instance of the new ``CategoryType`` class:: + // src/Form/TaskType.php use App\Form\CategoryType; use Symfony\Component\Form\FormBuilderInterface; From 89ff8f3485003be9c8c2f774a7acb588f7d192aa Mon Sep 17 00:00:00 2001 From: Bastien Jaillot Date: Wed, 16 Apr 2025 12:20:24 +0200 Subject: [PATCH 415/427] Update routing.rst --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 79a513ba8dd..f34205de98e 100644 --- a/routing.rst +++ b/routing.rst @@ -2715,7 +2715,7 @@ same URL, but with the HTTPS scheme. If you want to force a group of routes to use HTTPS, you can define the default scheme when importing them. The following example forces HTTPS on all routes -defined as annotations: +defined as attributes: .. configuration-block:: From 32aec360f5fce14a1f7b680b8e5695a36cbad263 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 16 Apr 2025 17:43:23 +0200 Subject: [PATCH 416/427] [EventDispatcher] Fix a minor syntax issue in a reference --- event_dispatcher.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 8e5c3d092e0..d9b913ed49f 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -246,7 +246,7 @@ methods could be called before or after the methods defined in other listeners and subscribers. To learn more about event subscribers, read :doc:`/components/event_dispatcher`. The following example shows an event subscriber that defines several methods which -listen to the same :ref:`kernel.exception event `_ +listen to the same :ref:`kernel.exception event ` via its ``ExceptionEvent`` class:: // src/EventSubscriber/ExceptionSubscriber.php From 7fc2bc7c4c2268e5f27acbc7954497a859c96a3a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 16 Apr 2025 16:22:47 +0200 Subject: [PATCH 417/427] [Console] Minor tweak in the article introduction --- console.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/console.rst b/console.rst index baab4aff4a7..82bafd4d640 100644 --- a/console.rst +++ b/console.rst @@ -18,14 +18,14 @@ the ``list`` command to view all available commands in the application: ... Available commands: - about Display information about the current project - completion Dump the shell completion script - help Display help for a command - list List commands + about Display information about the current project + completion Dump the shell completion script + help Display help for a command + list List commands assets - assets:install Install bundle's web assets under a public directory + assets:install Install bundle's web assets under a public directory cache - cache:clear Clear the cache + cache:clear Clear the cache ... .. note:: From c4cf202b2614a726be6694161b6eec7aba253588 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 17 Apr 2025 08:34:15 +0200 Subject: [PATCH 418/427] fix configuration block indentation --- service_container.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_container.rst b/service_container.rst index 6ae601cf724..6086ae1d946 100644 --- a/service_container.rst +++ b/service_container.rst @@ -226,7 +226,7 @@ each time you ask for it. If some files or directories in your project should not become services, you can exclude them using the ``exclude`` option: - .. configuration-block:: + .. configuration-block:: .. code-block:: yaml From 316c8ac333d822e1b5d68aa8bdbc25f8923c453c Mon Sep 17 00:00:00 2001 From: Pierre Ambroise Date: Thu, 17 Apr 2025 16:39:24 +0200 Subject: [PATCH 419/427] Add when argument to AsAlias --- service_container/alias_private.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index f99f7cb5f3e..84632c1d89b 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -181,6 +181,27 @@ This means that when using the container directly, you can access the # ... app.mailer: '@App\Mail\PhpMailer' +The ``#[AsAlias]`` attribute also support per-environment configuration +via the ``when`` argument:: + + // src/Mail/PhpMailer.php + namespace App\Mail; + + // ... + use Symfony\Component\DependencyInjection\Attribute\AsAlias; + + #[AsAlias(id: 'app.mailer', when: 'dev')] + class PhpMailer + { + // ... + } + +You can pass either a string or an array of strings to the ``when`` argument. + +.. versionadded:: 7.3 + + The ``when`` argument on the ``#[AsAlias]`` attribute was introduced in Symfony 7.3. + .. tip:: When using ``#[AsAlias]`` attribute, you may omit passing ``id`` argument From 5482c8281ad9bf346362e06f7988e83dd4282c6a Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 17 Apr 2025 20:14:01 -0400 Subject: [PATCH 420/427] [Routing] add tip about using `symfony/clock` with `UriSigner` --- routing.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/routing.rst b/routing.rst index a9ada1fc44b..0e1a46a505b 100644 --- a/routing.rst +++ b/routing.rst @@ -2815,6 +2815,16 @@ argument of :method:`Symfony\\Component\\HttpFoundation\\UriSigner::sign`:: Starting with Symfony 7.3, signed URI hashes no longer include the ``/`` or ``+`` characters, as these may cause issues with certain clients. +.. tip:: + + If ``symfony/clock`` is installed, it is used for creating and verifying the + expiration. This allows you to :ref:`mock the current time in your tests + `. + +.. versionadded:: 7.3 + + ``symfony/clock`` support was added to ``UriSigner`` in Symfony 7.3. + Troubleshooting --------------- From aa3b1674ea0202c0d3966ee82f04836fe33479ec Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Fri, 18 Apr 2025 19:34:27 -0400 Subject: [PATCH 421/427] [Routing] document `UriSigner::verify()` --- routing.rst | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/routing.rst b/routing.rst index a9ada1fc44b..19c2ae1a5a6 100644 --- a/routing.rst +++ b/routing.rst @@ -2810,10 +2810,30 @@ argument of :method:`Symfony\\Component\\HttpFoundation\\UriSigner::sign`:: The feature to add an expiration date for a signed URI was introduced in Symfony 7.1. +If you need to know the reason why a signed URI is invalid, you can use the +``verify()`` method which throws exceptions on failure:: + + use Symfony\Component\HttpFoundation\Exception\ExpiredSignedUriException; + use Symfony\Component\HttpFoundation\Exception\UnsignedUriException; + use Symfony\Component\HttpFoundation\Exception\UnverifiedSignedUriException; + + // ... + + try { + $uriSigner->verify($uri); // $uri can be a string or Request object + + // the URI is valid + } catch (UnsignedUriException) { + // the URI isn't signed + } catch (UnverifiedSignedUriException) { + // the URI is signed but the signature is invalid + } catch (ExpiredSignedUriException) { + // the URI is signed but expired + } + .. versionadded:: 7.3 - Starting with Symfony 7.3, signed URI hashes no longer include the ``/`` or - ``+`` characters, as these may cause issues with certain clients. + The ``verify()`` method was introduced in Symfony 7.3. Troubleshooting --------------- From e7613b0e2af243005b9fb66c9d696f74005a645a Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Sat, 19 Apr 2025 19:03:15 +0200 Subject: [PATCH 422/427] [Validator] Add filenameCharset and filenameCountUnit options to File constraint --- reference/constraints/File.rst | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/reference/constraints/File.rst b/reference/constraints/File.rst index 495c19f9cbe..62efa6cc08e 100644 --- a/reference/constraints/File.rst +++ b/reference/constraints/File.rst @@ -274,6 +274,31 @@ You can find a list of existing mime types on the `IANA website`_. If set, the validator will check that the filename of the underlying file doesn't exceed a certain length. +``filenameCountUnit`` +~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``File::FILENAME_COUNT_BYTES`` + +The character count unit to use for the filename max length check. +By default :phpfunction:`strlen` is used, which counts the length of the string in bytes. + +Can be one of the following constants of the +:class:`Symfony\\Component\\Validator\\Constraints\\File` class: + +* ``FILENAME_COUNT_BYTES``: Uses :phpfunction:`strlen` counting the length of the + string in bytes. +* ``FILENAME_COUNT_CODEPOINTS``: Uses :phpfunction:`mb_strlen` counting the length + of the string in Unicode code points. Simple (multibyte) Unicode characters count + as 1 character, while for example ZWJ sequences of composed emojis count as + multiple characters. +* ``FILENAME_COUNT_GRAPHEMES``: Uses :phpfunction:`grapheme_strlen` counting the + length of the string in graphemes, i.e. even emojis and ZWJ sequences of composed + emojis count as 1 character. + +.. versionadded:: 7.3 + + The ``filenameCountUnit`` option was introduced in Symfony 7.3. + ``filenameTooLongMessage`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -290,6 +315,35 @@ Parameter Description ``{{ filename_max_length }}`` Maximum number of characters allowed ============================== ============================================================== +``filenameCharset`` +~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +The charset to be used when computing value's filename max length with the +:phpfunction:`mb_check_encoding` and :phpfunction:`mb_strlen` +PHP functions. + +``filenameCharsetMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This filename does not match the expected charset.`` + +The message that will be shown if the value is not using the given `filenameCharsetMessage`_. + +You can use the following parameters in this message: + +================= ============================================================ +Parameter Description +================= ============================================================ +``{{ charset }}`` The expected charset +``{{ name }}`` The current (invalid) value +================= ============================================================ + +.. versionadded:: 7.3 + + The ``filenameCharset`` and ``filenameCharsetMessage`` options were introduced in Symfony 7.3. + ``extensionsMessage`` ~~~~~~~~~~~~~~~~~~~~~ From 76c4720d47de37c43d0a87cc1c61fe8d1216605c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Apr 2025 17:17:11 +0200 Subject: [PATCH 423/427] Minor tweaks --- service_container/alias_private.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index 84632c1d89b..22bf649d861 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -181,8 +181,8 @@ This means that when using the container directly, you can access the # ... app.mailer: '@App\Mail\PhpMailer' -The ``#[AsAlias]`` attribute also support per-environment configuration -via the ``when`` argument:: +The ``#[AsAlias]`` attribute can also be limited to one or more specific +:ref:`config environments ` using the ``when`` argument:: // src/Mail/PhpMailer.php namespace App\Mail; @@ -196,11 +196,16 @@ via the ``when`` argument:: // ... } -You can pass either a string or an array of strings to the ``when`` argument. + // pass an array to apply it in multiple config environments + #[AsAlias(id: 'app.mailer', when: ['dev', 'test'])] + class PhpMailer + { + // ... + } .. versionadded:: 7.3 - The ``when`` argument on the ``#[AsAlias]`` attribute was introduced in Symfony 7.3. + The ``when`` argument of the ``#[AsAlias]`` attribute was introduced in Symfony 7.3. .. tip:: From 6350e2ea71430fa106bd7873a4c384153fab134e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Apr 2025 17:49:02 +0200 Subject: [PATCH 424/427] Minor tweaks --- routing.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/routing.rst b/routing.rst index 672f331291b..663e8518504 100644 --- a/routing.rst +++ b/routing.rst @@ -2837,13 +2837,14 @@ If you need to know the reason why a signed URI is invalid, you can use the .. tip:: - If ``symfony/clock`` is installed, it is used for creating and verifying the - expiration. This allows you to :ref:`mock the current time in your tests + If ``symfony/clock`` is installed, it will be used to create and verify + expirations. This allows you to :ref:`mock the current time in your tests `. .. versionadded:: 7.3 - ``symfony/clock`` support was added to ``UriSigner`` in Symfony 7.3. + Support for :doc:`Symfony Clock ` in ``UriSigner`` was + introduced in Symfony 7.3. Troubleshooting --------------- From a5308819ac679da412d48acbb3d45f245b23f1e3 Mon Sep 17 00:00:00 2001 From: aurac Date: Wed, 23 Apr 2025 19:38:45 +0200 Subject: [PATCH 425/427] fix(doctrine): default configuration --- reference/configuration/doctrine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index 8a1062a54ae..46877e9f84c 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -176,7 +176,7 @@ that the ORM resolves to: doctrine: orm: - auto_mapping: true + auto_mapping: false # the standard distribution overrides this to be true in debug, false otherwise auto_generate_proxy_classes: false proxy_namespace: Proxies From 3abba12e6fe84c031dcae54569f35e8225775b76 Mon Sep 17 00:00:00 2001 From: Hmache Abdellah <11814824+Hmache@users.noreply.github.com> Date: Sun, 20 Apr 2025 23:31:32 +0200 Subject: [PATCH 426/427] [uid] Fix Uuid::v8() usage example to show it requires a UUID string This update corrects the usage example of Uuid::v8() to prevent misuse and confusion --- components/uid.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/uid.rst b/components/uid.rst index b286329151d..2fa04251f90 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -140,7 +140,7 @@ of the UUID value is specific to each implementation and no format should be ass use Symfony\Component\Uid\Uuid; // $uuid is an instance of Symfony\Component\Uid\UuidV8 - $uuid = Uuid::v8(); + $uuid = Uuid::v8('d9e7a184-5d5b-11ea-a62a-3499710062d0'); .. versionadded:: 6.2 From 4464d375341f6d333fff2dd91e2b48aeb3589591 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 24 Apr 2025 08:57:36 +0200 Subject: [PATCH 427/427] Tweaks --- components/uid.rst | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 2fa04251f90..b031348f85a 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -32,13 +32,13 @@ to create each type of UUID: **UUID v1** (time-based) Generates the UUID using a timestamp and the MAC address of your device -(`read UUIDv1 spec `__). +(`read the UUIDv1 spec `__). Both are obtained automatically, so you don't have to pass any constructor argument:: use Symfony\Component\Uid\Uuid; - // $uuid is an instance of Symfony\Component\Uid\UuidV1 $uuid = Uuid::v1(); + // $uuid is an instance of Symfony\Component\Uid\UuidV1 .. tip:: @@ -48,7 +48,7 @@ Both are obtained automatically, so you don't have to pass any constructor argum **UUID v2** (DCE security) Similar to UUIDv1 but with a very high likelihood of ID collision -(`read UUIDv2 spec `__). +(`read the UUIDv2 spec `__). It's part of the authentication mechanism of DCE (Distributed Computing Environment) and the UUID includes the POSIX UIDs (user/group ID) of the user who generated it. This UUID variant is **not implemented** by the Uid component. @@ -56,7 +56,7 @@ This UUID variant is **not implemented** by the Uid component. **UUID v3** (name-based, MD5) Generates UUIDs from names that belong, and are unique within, some given namespace -(`read UUIDv3 spec `__). +(`read the UUIDv3 spec `__). This variant is useful to generate deterministic UUIDs from arbitrary strings. It works by populating the UUID contents with the``md5`` hash of concatenating the namespace and the name:: @@ -69,8 +69,8 @@ the namespace and the name:: // $namespace = Uuid::v4(); // $name can be any arbitrary string - // $uuid is an instance of Symfony\Component\Uid\UuidV3 $uuid = Uuid::v3($namespace, $name); + // $uuid is an instance of Symfony\Component\Uid\UuidV3 These are the default namespaces defined by the standard: @@ -81,20 +81,20 @@ These are the default namespaces defined by the standard: **UUID v4** (random) -Generates a random UUID (`read UUIDv4 spec `__). +Generates a random UUID (`read the UUIDv4 spec `__). Because of its randomness, it ensures uniqueness across distributed systems without the need for a central coordinating entity. It's privacy-friendly because it doesn't contain any information about where and when it was generated:: use Symfony\Component\Uid\Uuid; - // $uuid is an instance of Symfony\Component\Uid\UuidV4 $uuid = Uuid::v4(); + // $uuid is an instance of Symfony\Component\Uid\UuidV4 **UUID v5** (name-based, SHA-1) It's the same as UUIDv3 (explained above) but it uses ``sha1`` instead of -``md5`` to hash the given namespace and name (`read UUIDv5 spec `__). +``md5`` to hash the given namespace and name (`read the UUIDv5 spec `__). This makes it more secure and less prone to hash collisions. .. _uid-uuid-v6: @@ -103,12 +103,12 @@ This makes it more secure and less prone to hash collisions. It rearranges the time-based fields of the UUIDv1 to make it lexicographically sortable (like :ref:`ULIDs `). It's more efficient for database indexing -(`read UUIDv6 spec `__):: +(`read the UUIDv6 spec `__):: use Symfony\Component\Uid\Uuid; - // $uuid is an instance of Symfony\Component\Uid\UuidV6 $uuid = Uuid::v6(); + // $uuid is an instance of Symfony\Component\Uid\UuidV6 .. tip:: @@ -121,26 +121,28 @@ sortable (like :ref:`ULIDs `). It's more efficient for database indexing Generates time-ordered UUIDs based on a high-resolution Unix Epoch timestamp source (the number of milliseconds since midnight 1 Jan 1970 UTC, leap seconds excluded) -(`read UUIDv7 spec `__). +(`read the UUIDv7 spec `__). It's recommended to use this version over UUIDv1 and UUIDv6 because it provides better entropy (and a more strict chronological order of UUID generation):: use Symfony\Component\Uid\Uuid; - // $uuid is an instance of Symfony\Component\Uid\UuidV7 $uuid = Uuid::v7(); + // $uuid is an instance of Symfony\Component\Uid\UuidV7 **UUID v8** (custom) -Provides an RFC-compatible format for experimental or vendor-specific use cases -(`read UUIDv8 spec `__). -The only requirement is to set the variant and version bits of the UUID. The rest -of the UUID value is specific to each implementation and no format should be assumed:: +Provides an RFC-compatible format intended for experimental or vendor-specific use cases +(`read the UUIDv8 spec `__). +You must generate the UUID value yourself. The only requirement is to set the +variant and version bits of the UUID correctly. The rest of the UUID content is +implementation-specific, and no particular format should be assumed:: use Symfony\Component\Uid\Uuid; - // $uuid is an instance of Symfony\Component\Uid\UuidV8 + // pass your custom UUID value as the argument $uuid = Uuid::v8('d9e7a184-5d5b-11ea-a62a-3499710062d0'); + // $uuid is an instance of Symfony\Component\Uid\UuidV8 .. versionadded:: 6.2