From 6156dcfa45f40c5422427a706529d9a1723c0050 Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 1 Jun 2025 07:13:58 +0200 Subject: [PATCH 01/21] [Form] Add input=date_point to DateTimeType, DateType and TimeType --- reference/forms/types/datetime.rst | 1 + reference/forms/types/options/date_input.rst.inc | 1 + reference/forms/types/time.rst | 1 + 3 files changed, 3 insertions(+) diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index 5fda8e9a14f..786abbc3af9 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -110,6 +110,7 @@ on your underlying object. Valid values are: * ``string`` (e.g. ``2011-06-05 12:15:00``) * ``datetime`` (a ``DateTime`` object) * ``datetime_immutable`` (a ``DateTimeImmutable`` object) +* ``date_point`` (a ``DatePoint`` object) * ``array`` (e.g. ``[2011, 06, 05, 12, 15, 0]``) * ``timestamp`` (e.g. ``1307276100``) diff --git a/reference/forms/types/options/date_input.rst.inc b/reference/forms/types/options/date_input.rst.inc index dafd7c483ad..06b17228bc0 100644 --- a/reference/forms/types/options/date_input.rst.inc +++ b/reference/forms/types/options/date_input.rst.inc @@ -9,6 +9,7 @@ on your underlying object. Valid values are: * ``string`` (e.g. ``2011-06-05``) * ``datetime`` (a ``DateTime`` object) * ``datetime_immutable`` (a ``DateTimeImmutable`` object) +* ``date_point`` (a ``DatePoint`` object) * ``array`` (e.g. ``['year' => 2011, 'month' => 06, 'day' => 05]``) * ``timestamp`` (e.g. ``1307232000``) diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index a3378f948cd..11377ba594f 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -99,6 +99,7 @@ on your underlying object. Valid values are: * ``string`` (e.g. ``12:17:26``) * ``datetime`` (a ``DateTime`` object) * ``datetime_immutable`` (a ``DateTimeImmutable`` object) +* ``date_point`` (a ``DatePoint`` object) * ``array`` (e.g. ``['hour' => 12, 'minute' => 17, 'second' => 26]``) * ``timestamp`` (e.g. ``1307232000``) From 2276ec1ad77b668d1db559b030cb4f2f9aacbd52 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 2 Jun 2025 08:25:06 +0200 Subject: [PATCH 02/21] Minor tweaks --- reference/forms/types/datetime.rst | 6 +++++- reference/forms/types/options/date_input.rst.inc | 6 +++++- reference/forms/types/time.rst | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index 786abbc3af9..035bdee7c7e 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -110,10 +110,14 @@ on your underlying object. Valid values are: * ``string`` (e.g. ``2011-06-05 12:15:00``) * ``datetime`` (a ``DateTime`` object) * ``datetime_immutable`` (a ``DateTimeImmutable`` object) -* ``date_point`` (a ``DatePoint`` object) +* ``date_point`` (a :ref:`DatePoint ` object) * ``array`` (e.g. ``[2011, 06, 05, 12, 15, 0]``) * ``timestamp`` (e.g. ``1307276100``) +.. versionadded:: 7.4 + + Support for ``date_point`` values was introduced in Symfony 7.4. + The value that comes back from the form will also be normalized back into this format. diff --git a/reference/forms/types/options/date_input.rst.inc b/reference/forms/types/options/date_input.rst.inc index 06b17228bc0..b4dc263cac1 100644 --- a/reference/forms/types/options/date_input.rst.inc +++ b/reference/forms/types/options/date_input.rst.inc @@ -9,10 +9,14 @@ on your underlying object. Valid values are: * ``string`` (e.g. ``2011-06-05``) * ``datetime`` (a ``DateTime`` object) * ``datetime_immutable`` (a ``DateTimeImmutable`` object) -* ``date_point`` (a ``DatePoint`` object) +* ``date_point`` (a :ref:`DatePoint ` object) * ``array`` (e.g. ``['year' => 2011, 'month' => 06, 'day' => 05]``) * ``timestamp`` (e.g. ``1307232000``) +.. versionadded:: 7.4 + + Support for ``date_point`` values was introduced in Symfony 7.4. + The value that comes back from the form will also be normalized back into this format. diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 11377ba594f..968907efd5b 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -99,10 +99,14 @@ on your underlying object. Valid values are: * ``string`` (e.g. ``12:17:26``) * ``datetime`` (a ``DateTime`` object) * ``datetime_immutable`` (a ``DateTimeImmutable`` object) -* ``date_point`` (a ``DatePoint`` object) +* ``date_point`` (a :ref:`DatePoint ` object) * ``array`` (e.g. ``['hour' => 12, 'minute' => 17, 'second' => 26]``) * ``timestamp`` (e.g. ``1307232000``) +.. versionadded:: 7.4 + + Support for ``date_point`` values was introduced in Symfony 7.4. + The value that comes back from the form will also be normalized back into this format. From d7fd599cc6d3f1aa055249b94903ca98a4d8cb25 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 3 Jun 2025 13:02:05 +0200 Subject: [PATCH 03/21] [WebLink] Add class to parse Link headers from HTTP responses --- web_link.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/web_link.rst b/web_link.rst index 79fd51b8d02..3fe2e349f50 100644 --- a/web_link.rst +++ b/web_link.rst @@ -195,6 +195,30 @@ You can also add links to the HTTP response directly from controllers and servic } } +Parsing Link Headers +-------------------- + +Some third-party APIs provide resources such as pagination URLs using the +``Link`` HTTP header. The WebLink component provides the +:class:`Symfony\\Component\\WebLink\\HttpHeaderParser` utility class to parse +those headers and transform them into :class:`Symfony\\Component\\WebLink\\Link` +instances:: + + use Symfony\Component\WebLink\HttpHeaderParser; + + $parser = new HttpHeaderParser(); + // get the value of the Link header from the Request + $linkHeader = '; rel="prerender",; rel="dns-prefetch"; pr="0.7",; rel="preload"; as="script"'; + + $links = $parser->parse($linkHeader)->getLinks(); + $links[0]->getRels(); // ['prerender'] + $links[1]->getAttributes(); // ['pr' => '0.7'] + $links[2]->getHref(); // '/baz.js' + +.. versionadded:: 7.4 + + The ``HttpHeaderParser`` class was introduced in Symfony 7.4. + .. _`WebLink`: https://github.com/symfony/web-link .. _`HTTP/2 Server Push`: https://tools.ietf.org/html/rfc7540#section-8.2 .. _`Resource Hints`: https://www.w3.org/TR/resource-hints/ From 412a94bbaabbb100e8c7501debaf31af7f59ec2e Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Sat, 7 Jun 2025 10:31:08 +0200 Subject: [PATCH 04/21] [PhpUnitBridge] Add strtotime() to ClockMock --- components/phpunit_bridge.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 5ce4c003a11..999e9626b40 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -566,9 +566,13 @@ Clock Mocking The :class:`Symfony\\Bridge\\PhpUnit\\ClockMock` class provided by this bridge allows you to mock the PHP's built-in time functions ``time()``, ``microtime()``, -``sleep()``, ``usleep()``, ``gmdate()``, and ``hrtime()``. Additionally the -function ``date()`` is mocked so it uses the mocked time if no timestamp is -specified. +``sleep()``, ``usleep()``, ``gmdate()``, ``hrtime()``, and ``strtotime()``. +Additionally the function ``date()`` is mocked so it uses the mocked time if no +timestamp is specified. + +.. versionadded:: 7.4 + + Support for mocking the ``strtotime()`` function was introduced in Symfony 7.4. Other functions with an optional timestamp parameter that defaults to ``time()`` will still use the system time instead of the mocked time. This means that you From 6e4ba05869fa2a8da110ba327e3cb7d3007fefb8 Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Sun, 8 Jun 2025 01:16:36 -0300 Subject: [PATCH 05/21] [Mailer] Add new assertEmailAddressNotContains method --- testing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing.rst b/testing.rst index 9356f2013a7..4af0cb19ec0 100644 --- a/testing.rst +++ b/testing.rst @@ -1082,8 +1082,8 @@ Mailer Assertions ``assertEmailHeaderSame(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``/``assertEmailHeaderNotSame(RawMessage $email, string $headerName, string $expectedValue, string $message = '')`` Asserts that the given email does (not) have the expected header set to the expected value. -``assertEmailAddressContains(RawMessage $email, string $headerName, string $expectedValue, string $message = '')`` - Asserts that the given address header equals the expected e-mail +``assertEmailAddressContains(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``/``assertEmailAddressNotContains(RawMessage $email, string $headerName, string $expectedValue, string $message = '')`` + Asserts that the given address header does (not) equal the expected e-mail address. This assertion normalizes addresses like ``Jane Smith `` into ``jane@example.com``. ``assertEmailSubjectContains(RawMessage $email, string $expectedValue, string $message = '')``/``assertEmailSubjectNotContains(RawMessage $email, string $expectedValue, string $message = '')`` From c259c28d33bcb6a4977259353b23bd2f6864d4c3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 18 Jun 2025 17:25:16 +0200 Subject: [PATCH 06/21] Add the missing versionadded directive --- testing.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testing.rst b/testing.rst index 4af0cb19ec0..fc2a22324ff 100644 --- a/testing.rst +++ b/testing.rst @@ -1090,6 +1090,10 @@ Mailer Assertions Asserts that the subject of the given email does (not) contain the expected subject. +.. versionadded:: 7.4 + + The ``assertEmailAddressNotContains()`` assertion was introduced in Symfony 7.4. + Notifier Assertions ................... From 8059765da0eaef018e2616e2ba0a6cce8fca2339 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 20 Jun 2025 16:14:38 +0200 Subject: [PATCH 07/21] ObjectMapper component is not experimental in 7.4 branch --- object_mapper.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/object_mapper.rst b/object_mapper.rst index 625466ffefc..74cbb5756e7 100644 --- a/object_mapper.rst +++ b/object_mapper.rst @@ -3,8 +3,7 @@ Object Mapper .. versionadded:: 7.3 - The ObjectMapper component was introduced in Symfony 7.3 as an - :doc:`experimental feature `. + The ObjectMapper component was introduced in Symfony 7.3. This component transforms one object into another, simplifying tasks such as converting DTOs (Data Transfer Objects) into entities or vice versa. It can also From b6b6d9952f65a9a49603b8412fe4ace479e870a1 Mon Sep 17 00:00:00 2001 From: Yopai <6121503+Yopai@users.noreply.github.com> Date: Sat, 21 Jun 2025 20:19:29 +0200 Subject: [PATCH 08/21] Update setup.rst : fix version number for 7.4 --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index a1fe9669a6e..cff4858a40a 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.3.x-dev" --webapp + $ symfony new my_project_directory --version="7.4.x-dev" --webapp # run this if you are building a microservice, console application or API - $ symfony new my_project_directory --version="7.3.x-dev" + $ symfony new my_project_directory --version="7.4.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.3.x-dev" my_project_directory + $ composer create-project symfony/skeleton:"7.4.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.3.x-dev" my_project_directory + $ composer create-project symfony/skeleton:"7.4.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 ad966a7b82c6ae4303ce3d4b2a1350d1f71faf0e Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sun, 22 Jun 2025 12:38:08 +0200 Subject: [PATCH 09/21] [Routing] Document _query parameter for URL generation Fix #21055 --- routing.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/routing.rst b/routing.rst index ffc7d168395..46215fe1881 100644 --- a/routing.rst +++ b/routing.rst @@ -1151,6 +1151,17 @@ special parameters created by Symfony: This is used for such things as setting the ``Content-Type`` of the response (e.g. a ``json`` format translates into a ``Content-Type`` of ``application/json``). +``_query`` + Used to add query parameters to the generated URL. + + .. versionadded:: 7.4 + + The ``_query`` parameter was introduced in Symfony 7.4. + + .. deprecated:: 7.4 + + Passing a value other than an array as the ``_query`` parameter was deprecated in Symfony 7.4. + ``_fragment`` Used to set the fragment identifier, which is the optional last part of a URL that starts with a ``#`` character and is used to identify a portion of a document. From 8a6a9f24bd125d24977b88f5637f7b6ee0186b1e Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sun, 22 Jun 2025 13:07:27 +0200 Subject: [PATCH 10/21] [Scheduler] Document unique schedule name Fix #21024 --- scheduler.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scheduler.rst b/scheduler.rst index 983ede09357..fc4656f811e 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -133,9 +133,14 @@ on a particular schedule:: .. tip:: - By default, the schedule name is ``default`` and the transport name follows + The schedule name must be unique and by default, it is ``default``. The transport name follows the syntax: ``scheduler_nameofyourschedule`` (e.g. ``scheduler_default``). +.. versionadded:: 7.4 + + Throwing an exception for duplicate schedule names instead of replacing the existing schedule + was introduced with Symfony 7.4. + .. tip:: `Memoizing`_ your schedule is a good practice to prevent unnecessary reconstruction From 88c022db18e6a95d8215ed8084825ba58f873089 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 20 Jun 2025 15:09:28 +0200 Subject: [PATCH 11/21] docs(FrameworkBundle): allow to unverbose all the methods in BrowserKitAssertionsTrait --- testing.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/testing.rst b/testing.rst index fc2a22324ff..0fe90dad93d 100644 --- a/testing.rst +++ b/testing.rst @@ -963,11 +963,11 @@ However, Symfony provides useful shortcut methods for the most common cases: Response Assertions ................... -``assertResponseIsSuccessful(string $message = '', bool $verbose = true)`` +``assertResponseIsSuccessful(string $message = '', ?bool $verbose = null)`` Asserts that the response was successful (HTTP status is 2xx). -``assertResponseStatusCodeSame(int $expectedCode, string $message = '', bool $verbose = true)`` +``assertResponseStatusCodeSame(int $expectedCode, string $message = '', ?bool $verbose = null)`` Asserts a specific HTTP status code. -``assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', bool $verbose = true)`` +``assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', ?bool $verbose = null)`` Asserts the response is a redirect response (optionally, you can check the target location and status code). The excepted location can be either an absolute or a relative path. @@ -985,13 +985,22 @@ Response Assertions Asserts the response format returned by the :method:`Symfony\\Component\\HttpFoundation\\Response::getFormat` method is the same as the expected value. -``assertResponseIsUnprocessable(string $message = '', bool $verbose = true)`` +``assertResponseIsUnprocessable(string $message = '', bool ?$verbose = null)`` Asserts the response is unprocessable (HTTP status is 422) .. versionadded:: 7.1 The ``$verbose`` parameters were introduced in Symfony 7.1. +.. versionadded:: 7.4 + + The ``$defaultVerboseMode = true;`` attribute was introduced in + :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\BrowserKitAssertionsTrait` + in Symfony 7.4. This attribute allows you to define the default verbosity + for all applicable assertions within the trait, overriding the initial `null` + value of the `$verbose` parameter. + + Request Assertions .................. From fdf8824289df7eb57874348ef7c1355bad98c0f4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 25 Jun 2025 09:43:20 +0200 Subject: [PATCH 12/21] Reword and tweaks --- testing.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/testing.rst b/testing.rst index 0fe90dad93d..e5e57522d69 100644 --- a/testing.rst +++ b/testing.rst @@ -988,18 +988,21 @@ Response Assertions ``assertResponseIsUnprocessable(string $message = '', bool ?$verbose = null)`` Asserts the response is unprocessable (HTTP status is 422) +By default, these assert methods provide detailed error messages when they fail. +You can control the verbosity level using the optional ``verbose`` argument in +each assert method. To set this verbosity level globally, use the +``setBrowserKitAssertionsAsVerbose()`` method from the +:class:`Symfony\\Bundle\\FrameworkBundle\\Test\\BrowserKitAssertionsTrait`:: + + BrowserKitAssertionsTrait::setBrowserKitAssertionsAsVerbose(false); + .. versionadded:: 7.1 The ``$verbose`` parameters were introduced in Symfony 7.1. .. versionadded:: 7.4 - The ``$defaultVerboseMode = true;`` attribute was introduced in - :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\BrowserKitAssertionsTrait` - in Symfony 7.4. This attribute allows you to define the default verbosity - for all applicable assertions within the trait, overriding the initial `null` - value of the `$verbose` parameter. - + The ``setBrowserKitAssertionsAsVerbose()`` method ws introduced in Symfony 7.4. Request Assertions .................. From c7ce246b8f3e43e3e46c493e37f6e8bc1dcd30af Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 25 Jun 2025 11:19:17 +0200 Subject: [PATCH 13/21] fix typo --- testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing.rst b/testing.rst index e5e57522d69..1afc15befbb 100644 --- a/testing.rst +++ b/testing.rst @@ -1002,7 +1002,7 @@ each assert method. To set this verbosity level globally, use the .. versionadded:: 7.4 - The ``setBrowserKitAssertionsAsVerbose()`` method ws introduced in Symfony 7.4. + The ``setBrowserKitAssertionsAsVerbose()`` method was introduced in Symfony 7.4. Request Assertions .................. From 7f37b3c77c6c888401697be1aa306002582663fb Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 26 Jun 2025 10:38:40 +0200 Subject: [PATCH 14/21] docs(SecurityBundle): register alias for argument for password hasher --- security.rst | 4 +-- security/passwords.rst | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/security.rst b/security.rst index 9d2df6165d0..ede0bc39825 100644 --- a/security.rst +++ b/security.rst @@ -461,8 +461,8 @@ You can also manually hash a password by running: $ php bin/console security:hash-password -Read more about all available hashers and password migration in -:doc:`security/passwords`. +Read more about all available hashers (including specific hashers) and password +migration in :doc:`security/passwords`. .. _firewalls-authentication: .. _a-authentication-firewalls: diff --git a/security/passwords.rst b/security/passwords.rst index 7f05bc3acb9..bba983a94e3 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -226,6 +226,61 @@ After configuring the correct algorithm, you can use the throw new \Exception('Bad credentials, cannot delete this user.'); } +Injecting a Specific Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases, you might define a password hasher in your configuration that is +not linked to a user entity but is instead identified by a unique key. +For example, you might have a separate hasher for things like password recovery +codes. + +With the following configuration: + +.. code-block:: yaml + + # config/packages/security.yaml + security: + password_hashers: + recovery_code: 'auto' + + firewalls: + main: + # ... + +It is possible to inject the recovery_code password hasher into any service. +To do this, you can't rely on standard autowiring, as Symfony wouldn't know +which specific hasher to provide. + +Instead, you can use the ``#[Target]`` attribute to request the hasher by its +configuration key:: + + // src/Controller/HomepageController.php + namespace App\Controller; + + use Symfony\Component\DependencyInjection\Attribute\Target; + use Symfony\Component\PasswordHasher\PasswordHasherInterface; + + class HomepageController extends AbstractController + { + public function __construct( + #[Target('recovery_code')] + private readonly PasswordHasherInterface $passwordHasher, + ) { + } + + #[Route('/')] + public function index(): Response + { + $plaintextToken = 'some-secret-token'; + + // Note: use hash(), not hashPassword(), as we are not using a UserInterface object + $hashedToken = $this->passwordHasher->hash($plaintextToken); + } + } + +When injecting a specific hasher by its name, you should type-hint the generic +:class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface`. + Reset Password -------------- From ee6841b81adf0d9cf25b15b16a08cddad89bf685 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 27 Jun 2025 08:21:51 +0200 Subject: [PATCH 15/21] Minor tweaks --- security/passwords.rst | 77 ++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/security/passwords.rst b/security/passwords.rst index bba983a94e3..5de5d4b7b24 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -226,13 +226,42 @@ After configuring the correct algorithm, you can use the throw new \Exception('Bad credentials, cannot delete this user.'); } +Reset Password +-------------- + +Using `MakerBundle`_ and `SymfonyCastsResetPasswordBundle`_, you can create +a secure out of the box solution to handle forgotten passwords. First, +install the SymfonyCastsResetPasswordBundle: + +.. code-block:: terminal + + $ composer require symfonycasts/reset-password-bundle + +Then, use the ``make:reset-password`` command. This asks you a few +questions about your app and generates all the files you need! After, +you'll see a success message and a list of any other steps you need to do. + +.. code-block:: terminal + + $ php bin/console make:reset-password + +.. tip:: + + Starting in `MakerBundle`_: v1.57.0 - You can pass either ``--with-uuid`` or + ``--with-ulid`` to ``make:reset-password``. Leveraging Symfony's :doc:`Uid Component `, + the entities will be generated with the ``id`` type as :ref:`Uuid ` + or :ref:`Ulid ` instead of ``int``. + +You can customize the reset password bundle's behavior by updating the +``reset_password.yaml`` file. For more information on the configuration, +check out the `SymfonyCastsResetPasswordBundle`_ guide. + Injecting a Specific Password Hasher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In some cases, you might define a password hasher in your configuration that is -not linked to a user entity but is instead identified by a unique key. -For example, you might have a separate hasher for things like password recovery -codes. +In some cases, you may define a password hasher in your configuration that is +not tied to a user class. For example, you might use a separate hasher for +password recovery codes or API tokens. With the following configuration: @@ -247,12 +276,12 @@ With the following configuration: main: # ... -It is possible to inject the recovery_code password hasher into any service. -To do this, you can't rely on standard autowiring, as Symfony wouldn't know -which specific hasher to provide. +You can inject the ``recovery_code`` password hasher into any service. However, +you can't rely on standard autowiring, as Symfony doesn't know which specific +hasher to provide. -Instead, you can use the ``#[Target]`` attribute to request the hasher by its -configuration key:: +Instead, use the ``#[Target]`` attribute to explicitly request the hasher by +its configuration key:: // src/Controller/HomepageController.php namespace App\Controller; @@ -281,35 +310,9 @@ configuration key:: When injecting a specific hasher by its name, you should type-hint the generic :class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface`. -Reset Password --------------- - -Using `MakerBundle`_ and `SymfonyCastsResetPasswordBundle`_, you can create -a secure out of the box solution to handle forgotten passwords. First, -install the SymfonyCastsResetPasswordBundle: - -.. code-block:: terminal - - $ composer require symfonycasts/reset-password-bundle - -Then, use the ``make:reset-password`` command. This asks you a few -questions about your app and generates all the files you need! After, -you'll see a success message and a list of any other steps you need to do. +.. versionadded:: 7.4 -.. code-block:: terminal - - $ php bin/console make:reset-password - -.. tip:: - - Starting in `MakerBundle`_: v1.57.0 - You can pass either ``--with-uuid`` or - ``--with-ulid`` to ``make:reset-password``. Leveraging Symfony's :doc:`Uid Component `, - the entities will be generated with the ``id`` type as :ref:`Uuid ` - or :ref:`Ulid ` instead of ``int``. - -You can customize the reset password bundle's behavior by updating the -``reset_password.yaml`` file. For more information on the configuration, -check out the `SymfonyCastsResetPasswordBundle`_ guide. + The feature to inject specific password hashers was introduced in Symfony 7.4. .. _security-password-migration: From 1cf79561eb134f698d54aa05f60bef132f8a7ed6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 27 Jun 2025 08:38:05 +0200 Subject: [PATCH 16/21] Tweak and added some example --- routing.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/routing.rst b/routing.rst index 46215fe1881..4eea1e23d29 100644 --- a/routing.rst +++ b/routing.rst @@ -1151,6 +1151,13 @@ special parameters created by Symfony: This is used for such things as setting the ``Content-Type`` of the response (e.g. a ``json`` format translates into a ``Content-Type`` of ``application/json``). +``_fragment`` + Used to set the fragment identifier, which is the optional last part of a URL that + starts with a ``#`` character and is used to identify a portion of a document. + +``_locale`` + Used to set the :ref:`locale ` on the request. + ``_query`` Used to add query parameters to the generated URL. @@ -1160,14 +1167,8 @@ special parameters created by Symfony: .. deprecated:: 7.4 - Passing a value other than an array as the ``_query`` parameter was deprecated in Symfony 7.4. - -``_fragment`` - Used to set the fragment identifier, which is the optional last part of a URL that - starts with a ``#`` character and is used to identify a portion of a document. - -``_locale`` - Used to set the :ref:`locale ` on the request. + Passing a value other than an array as the ``_query`` parameter was + deprecated in Symfony 7.4. You can include these attributes (except ``_fragment``) both in individual routes and in route imports. Symfony defines some special attributes with the same name @@ -1187,6 +1188,7 @@ and in route imports. Symfony defines some special attributes with the same name path: '/articles/{_locale}/search.{_format}', locale: 'en', format: 'html', + query: ['page' => 1], requirements: [ '_locale' => 'en|fr', '_format' => 'html|xml', @@ -1205,6 +1207,8 @@ and in route imports. Symfony defines some special attributes with the same name controller: App\Controller\ArticleController::search locale: en format: html + query: + page: 1 requirements: _locale: en|fr _format: html|xml @@ -1242,6 +1246,7 @@ and in route imports. Symfony defines some special attributes with the same name ->controller([ArticleController::class, 'search']) ->locale('en') ->format('html') + ->query(['page' => 1]) ->requirements([ '_locale' => 'en|fr', '_format' => 'html|xml', From 9d67f32feec97a62aa971de1a1cb7d630300946c Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Thu, 26 Jun 2025 10:03:01 -0300 Subject: [PATCH 17/21] [BrowserKit] Add `isFirstPage()` and `isLastPage()` methods to History --- components/browser_kit.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/browser_kit.rst b/components/browser_kit.rst index 8cf0772298c..7feb29096fb 100644 --- a/components/browser_kit.rst +++ b/components/browser_kit.rst @@ -329,6 +329,20 @@ history:: // go forward to documentation page $crawler = $client->forward(); + // check if the history position is on the first page + if (!$client->getHistory()->isFirstPage()) { + $crawler = $client->back(); + } + + // check if the history position is on the last page + if (!$client->getHistory()->isLastPage()) { + $crawler = $client->forward(); + } + +.. versionadded:: 7.4 + + The ``isFirstPage`` and ``isLastPage`` methods were introduced in Symfony 7.4. + You can delete the client's history with the ``restart()`` method. This will also delete all the cookies:: From bc2c9c33b8a07e9cd4b8870ed16f382e91a24ab1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Sun, 29 Jun 2025 22:14:52 +0200 Subject: [PATCH 18/21] minor --- components/browser_kit.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/browser_kit.rst b/components/browser_kit.rst index 7feb29096fb..ddbbd0f704d 100644 --- a/components/browser_kit.rst +++ b/components/browser_kit.rst @@ -333,7 +333,7 @@ history:: if (!$client->getHistory()->isFirstPage()) { $crawler = $client->back(); } - + // check if the history position is on the last page if (!$client->getHistory()->isLastPage()) { $crawler = $client->forward(); @@ -341,7 +341,7 @@ history:: .. versionadded:: 7.4 - The ``isFirstPage`` and ``isLastPage`` methods were introduced in Symfony 7.4. + The ``isFirstPage()`` and ``isLastPage()`` methods were introduced in Symfony 7.4. You can delete the client's history with the ``restart()`` method. This will also delete all the cookies:: From a3c42994c95c5b5a1cb764b4b6e91bb98a49c57b Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Sun, 29 Jun 2025 14:51:48 +0200 Subject: [PATCH 19/21] [Uid] Add microsecond precision to UUIDv7 and optimize on x64 --- components/uid.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/uid.rst b/components/uid.rst index b4083765436..46c710a0fd5 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -120,7 +120,7 @@ sortable (like :ref:`ULIDs `). It's more efficient for database indexing **UUID v7** (UNIX timestamp) 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) +source (the number of microseconds since midnight 1 Jan 1970 UTC, leap seconds excluded) (`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):: @@ -130,6 +130,10 @@ better entropy (and a more strict chronological order of UUID generation):: $uuid = Uuid::v7(); // $uuid is an instance of Symfony\Component\Uid\UuidV7 +.. versionadded:: 7.4 + + In Symfony 7.4, the precision was increased from milliseconds to microseconds. + **UUID v8** (custom) Provides an RFC-compatible format intended for experimental or vendor-specific use cases From f5ca9c5c4d4ae035b855b593451f2817c05c8e40 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 1 Jul 2025 10:34:19 +0200 Subject: [PATCH 20/21] Document the ability to set aliases and hidden status via command name - Add documentation for command aliases using pipe syntax in console.rst - Document how to make commands hidden using the `|` prefix in hide_commands.rst - Show examples for the #[AsCommand] attribute - Include version annotations for Symfony 7.4 - Ensure lines are within 80 character limit --- console.rst | 27 +++++++++++++++++++++++++++ console/hide_commands.rst | 24 ++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/console.rst b/console.rst index a3d6701f47c..0ec6f28b02a 100644 --- a/console.rst +++ b/console.rst @@ -206,6 +206,33 @@ After configuring and registering the command, you can run it in the terminal: As you might expect, this command will do nothing as you didn't write any logic yet. Add your own logic inside the ``__invoke()`` method. +Command Aliases +~~~~~~~~~~~~~~~ + +You can define alternative names (aliases) for a command directly in its name +using a pipe (``|``) separator. The first name in the list becomes the actual +command name; the others are aliases that can also be used to run the command:: + + // src/Command/CreateUserCommand.php + namespace App\Command; + + use Symfony\Component\Console\Attribute\AsCommand; + use Symfony\Component\Console\Command\Command; + + #[AsCommand( + name: 'app:create-user|app:add-user|app:new-user', + description: 'Creates a new user.', + )] + class CreateUserCommand extends Command + { + // ... + } + +.. versionadded:: 7.4 + + The ability to define aliases through the command name was introduced in + Symfony 7.4. + Console Output -------------- diff --git a/console/hide_commands.rst b/console/hide_commands.rst index 4ab9d3a6dad..17bcf37a8f9 100644 --- a/console/hide_commands.rst +++ b/console/hide_commands.rst @@ -22,8 +22,28 @@ the ``hidden`` property of the ``AsCommand`` attribute:: // ... } -Hidden commands behave the same as normal commands but they are no longer displayed -in command listings, so end-users are not aware of their existence. +You can also define a command as hidden using the pipe (``|``) syntax in the +command name:: + + // src/Command/LegacyCommand.php + namespace App\Command; + + use Symfony\Component\Console\Attribute\AsCommand; + use Symfony\Component\Console\Command\Command; + + #[AsCommand(name: '|app:legacy')] + class LegacyCommand extends Command + { + // ... + } + +.. versionadded:: 7.4 + + The ability to define a command as hidden using the pipe syntax in the + command name was introduced in Symfony 7.4. + +Hidden commands behave the same as normal commands but they are no longer +displayed in command listings, so end-users are not aware of their existence. .. note:: From fbf50800fb5798d7bb4827a8d92a3577a8701c96 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 1 Jul 2025 13:12:49 +0200 Subject: [PATCH 21/21] [Console] Update the hidden command doc when using the pipe syntax --- console.rst | 2 ++ console/hide_commands.rst | 11 ++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/console.rst b/console.rst index 0ec6f28b02a..0aeece2dc09 100644 --- a/console.rst +++ b/console.rst @@ -206,6 +206,8 @@ After configuring and registering the command, you can run it in the terminal: As you might expect, this command will do nothing as you didn't write any logic yet. Add your own logic inside the ``__invoke()`` method. +.. _command-aliases: + Command Aliases ~~~~~~~~~~~~~~~ diff --git a/console/hide_commands.rst b/console/hide_commands.rst index 17bcf37a8f9..aad4b6d45a4 100644 --- a/console/hide_commands.rst +++ b/console/hide_commands.rst @@ -22,8 +22,9 @@ the ``hidden`` property of the ``AsCommand`` attribute:: // ... } -You can also define a command as hidden using the pipe (``|``) syntax in the -command name:: +You can also define a command as hidden using the pipe (``|``) syntax of +:ref:`command aliases `. To do this, use the command name as one +of the aliases and leave the main command name (the part before the ``|``) empty:: // src/Command/LegacyCommand.php namespace App\Command; @@ -39,11 +40,7 @@ command name:: .. versionadded:: 7.4 - The ability to define a command as hidden using the pipe syntax in the - command name was introduced in Symfony 7.4. - -Hidden commands behave the same as normal commands but they are no longer -displayed in command listings, so end-users are not aware of their existence. + Support for hidding commands using the pipe syntax was introduced in Symfony 7.4. .. note::