Skip to content

Commit 4a07f5a

Browse files
committed
Merge branch '6.2' into 6.3
* 6.2: Fix typo, change parameter $accesToken to $token Fix lint issues [#17393] Finish entity value resolver docs [FrameworkBundle] Rename option `catch_all_throwables` to `handle_all_throwables` in documentation Add documentation about the Doctrine Entity Value Resolver
2 parents b59499e + 66422d5 commit 4a07f5a

File tree

5 files changed

+197
-23
lines changed

5 files changed

+197
-23
lines changed

.doctor-rst.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ whitelist:
8888
- '.. versionadded:: 1.11' # Messenger (Middleware / DoctrineBundle)
8989
- '.. versionadded:: 1.18' # Flex in setup/upgrade_minor.rst
9090
- '.. versionadded:: 1.0.0' # Encore
91+
- '.. versionadded:: 2.7.1' # Doctrine
9192
- '0 => 123' # assertion for var_dumper - components/var_dumper.rst
9293
- '1 => "foo"' # assertion for var_dumper - components/var_dumper.rst
9394
- '123,' # assertion for var_dumper - components/var_dumper.rst

best_practices.rst

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,17 @@ Instead, you must use dependency injection to fetch services by
246246
:ref:`type-hinting action method arguments <controller-accessing-services>` or
247247
constructor arguments.
248248

249-
Use ParamConverters If They Are Convenient
250-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
249+
Use Entity Value Resolvers If They Are Convenient
250+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251251

252-
If you're using :doc:`Doctrine </doctrine>`, then you can *optionally* use the
253-
`ParamConverter`_ to automatically query for an entity and pass it as an argument
254-
to your controller. It will also show a 404 page if no entity can be found.
252+
If you're using :doc:`Doctrine </doctrine>`, then you can *optionally* use
253+
the :ref:`EntityValueResolver <doctrine-entity-value-resolver>` to
254+
automatically query for an entity and pass it as an argument to your
255+
controller. It will also show a 404 page if no entity can be found.
255256

256257
If the logic to get an entity from a route variable is more complex, instead of
257-
configuring the ParamConverter, it's better to make the Doctrine query inside
258-
the controller (e.g. by calling to a :doc:`Doctrine repository method </doctrine>`).
258+
configuring the EntityValueResolver, it's better to make the Doctrine query
259+
inside the controller (e.g. by calling to a :doc:`Doctrine repository method </doctrine>`).
259260

260261
Templates
261262
---------
@@ -450,7 +451,6 @@ you must set up a redirection.
450451
.. _`Symfony Demo`: https://github.com/symfony/demo
451452
.. _`download Symfony`: https://symfony.com/download
452453
.. _`Composer`: https://getcomposer.org/
453-
.. _`ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
454454
.. _`feature toggles`: https://en.wikipedia.org/wiki/Feature_toggle
455455
.. _`smoke testing`: https://en.wikipedia.org/wiki/Smoke_testing_(software)
456456
.. _`Webpack`: https://webpack.js.org/

doctrine.rst

Lines changed: 184 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -598,17 +598,21 @@ the :ref:`doctrine-queries` section.
598598
see the web debug toolbar, install the ``profiler`` :ref:`Symfony pack <symfony-packs>`
599599
by running this command: ``composer require --dev symfony/profiler-pack``.
600600

601-
Automatically Fetching Objects (ParamConverter)
602-
-----------------------------------------------
601+
.. _doctrine-entity-value-resolver:
603602

604-
In many cases, you can use the `SensioFrameworkExtraBundle`_ to do the query
605-
for you automatically! First, install the bundle in case you don't have it:
603+
Automatically Fetching Objects (EntityValueResolver)
604+
----------------------------------------------------
606605

607-
.. code-block:: terminal
606+
.. versionadded:: 6.2
607+
608+
Entity Value Resolver was introduced in Symfony 6.2.
608609

609-
$ composer require sensio/framework-extra-bundle
610+
.. versionadded:: 2.7.1
610611

611-
Now, simplify your controller::
612+
Autowiring of the ``EntityValueResolver`` was introduced in DoctrineBundle 2.7.1.
613+
614+
In many cases, you can use the ``EntityValueResolver`` to do the query for you
615+
automatically! You can simplify the controller to::
612616

613617
// src/Controller/ProductController.php
614618
namespace App\Controller;
@@ -621,7 +625,7 @@ Now, simplify your controller::
621625

622626
class ProductController extends AbstractController
623627
{
624-
#[Route('/product/{id}', name: 'product_show')]
628+
#[Route('/product/{id}')]
625629
public function show(Product $product): Response
626630
{
627631
// use the Product!
@@ -632,7 +636,178 @@ Now, simplify your controller::
632636
That's it! The bundle uses the ``{id}`` from the route to query for the ``Product``
633637
by the ``id`` column. If it's not found, a 404 page is generated.
634638

635-
There are many more options you can use. Read more about the `ParamConverter`_.
639+
This behavior is enabled by default on all your controllers. You can
640+
disable it by setting the ``doctrine.orm.controller_resolver.auto_mapping``
641+
config option to ``false``.
642+
643+
When disabled, you can enable it individually on the desired controllers by
644+
using the ``MapEntity`` attribute::
645+
646+
// src/Controller/ProductController.php
647+
namespace App\Controller;
648+
649+
use App\Entity\Product;
650+
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
651+
use Symfony\Component\HttpFoundation\Response;
652+
use Symfony\Component\Routing\Annotation\Route;
653+
// ...
654+
655+
class ProductController extends AbstractController
656+
{
657+
#[Route('/product/{id}')]
658+
public function show(
659+
#[MapEntity]
660+
Product $product
661+
): Response {
662+
// use the Product!
663+
// ...
664+
}
665+
}
666+
667+
.. tip::
668+
669+
When enabled globally, it's possible to disabled the behavior on a specific
670+
controller, by using the ``MapEntity`` set to ``disabled``.
671+
672+
public function show(
673+
#[CurrentUser]
674+
#[MapEntity(disabled: true)]
675+
User $user
676+
): Response {
677+
// User is not resolved by the EntityValueResolver
678+
// ...
679+
}
680+
681+
Fetch Automatically
682+
~~~~~~~~~~~~~~~~~~~
683+
684+
If your route wildcards match properties on your entity, then the resolver
685+
will automatically fetch them::
686+
687+
/**
688+
* Fetch via primary key because {id} is in the route.
689+
*/
690+
#[Route('/product/{id}')]
691+
public function showByPk(Post $post): Response
692+
{
693+
}
694+
695+
/**
696+
* Perform a findOneBy() where the slug property matches {slug}.
697+
*/
698+
#[Route('/product/{slug}')]
699+
public function showBySlug(Post $post): Response
700+
{
701+
}
702+
703+
Automatic fetching works in these situations:
704+
705+
* If ``{id}`` is in your route, then this is used to fetch by
706+
primary key via the ``find()`` method.
707+
708+
* The resolver will attempt to do a ``findOneBy()`` fetch by using
709+
*all* of the wildcards in your route that are actually properties
710+
on your entity (non-properties are ignored).
711+
712+
You can control this behavior by actually *adding* the ``MapEntity``
713+
attribute and using the `MapEntity options`_.
714+
715+
Fetch via an Expression
716+
~~~~~~~~~~~~~~~~~~~~~~~
717+
718+
If automatic fetching doesn't work, you can write an expression using the
719+
:doc:`ExpressionLanguage component </components/expression_language>`::
720+
721+
#[Route('/product/{product_id}')]
722+
public function show(
723+
#[MapEntity(expr: 'repository.find(product_id)')]
724+
Product $product
725+
): Response {
726+
}
727+
728+
In the expression, the ``repository`` variable will be your entity's
729+
Repository class and any route wildcards - like ``{product_id}`` are
730+
available as variables.
731+
732+
This can also be used to help resolve multiple arguments::
733+
734+
#[Route('/product/{id}/comments/{comment_id}')]
735+
public function show(
736+
Product $product
737+
#[MapEntity(expr: 'repository.find(comment_id)')]
738+
Comment $comment
739+
): Response {
740+
}
741+
742+
In the example above, the ``$product`` argument is handled automatically,
743+
but ``$comment`` is configured with the attribute since they cannot both follow
744+
the default convention.
745+
746+
MapEntity Options
747+
~~~~~~~~~~~~~~~~~
748+
749+
A number of options are available on the ``MapEntity`` annotation to
750+
control behavior:
751+
752+
``id``
753+
If an ``id`` option is configured and matches a route parameter, then
754+
the resolver will find by the primary key::
755+
756+
#[Route('/product/{product_id}')]
757+
public function show(
758+
Product $product
759+
#[MapEntity(id: 'product_id')]
760+
Comment $comment
761+
): Response {
762+
}
763+
764+
``mapping``
765+
Configures the properties and values to use with the ``findOneBy()``
766+
method: the key is the route placeholder name and the value is the Doctrine
767+
property name::
768+
769+
#[Route('/product/{category}/{slug}/comments/{comment_slug}')]
770+
public function show(
771+
#[MapEntity(mapping: ['date' => 'date', 'slug' => 'slug'])]
772+
Product $product
773+
#[MapEntity(mapping: ['comment_slug' => 'slug'])]
774+
Comment $comment
775+
): Response {
776+
}
777+
778+
``exclude``
779+
Configures the properties that should be used in the ``findOneBy()``
780+
method by *excluding* one or more properties so that not *all* are used:
781+
782+
#[Route('/product/{slug}/{date}')]
783+
public function show(
784+
#[MapEntity(exclude: ['date'])]
785+
Product $product
786+
\DateTime $date
787+
): Response {
788+
}
789+
790+
``stripNull``
791+
If true, then when ``findOneBy()`` is used, any values that are
792+
``null`` will not be used for the query.
793+
794+
``entityManager``
795+
By default, the ``EntityValueResolver`` uses the *default*
796+
entity manager, but you can configure this::
797+
798+
#[Route('/product/{id}')]
799+
public function show(
800+
#[MapEntity(entityManager: ['foo'])]
801+
Product $product
802+
): Response {
803+
}
804+
805+
``evictCache``
806+
If true, forces Doctrine to always fetch the entity from the database
807+
instead of cache.
808+
809+
``disabled``
810+
If true, the ``EntityValueResolver`` will not try to replace the argument.
636811

637812
Updating an Object
638813
------------------
@@ -895,8 +1070,6 @@ Learn more
8951070
.. _`Transactions and Concurrency`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/transactions-and-concurrency.html
8961071
.. _`DoctrineMigrationsBundle`: https://github.com/doctrine/DoctrineMigrationsBundle
8971072
.. _`NativeQuery`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/native-sql.html
898-
.. _`SensioFrameworkExtraBundle`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html
899-
.. _`ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
9001073
.. _`limit of 767 bytes for the index key prefix`: https://dev.mysql.com/doc/refman/5.6/en/innodb-limits.html
9011074
.. _`Doctrine screencast series`: https://symfonycasts.com/screencast/symfony-doctrine
9021075
.. _`API Platform`: https://api-platform.com/docs/core/validation/

reference/configuration/framework.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ will invalidate all signed URIs and Remember Me cookies. That's why, after
5353
changing this value, you should regenerate the application cache and log
5454
out all the application users.
5555

56-
catch_all_throwables
57-
~~~~~~~~~~~~~~~~~~~~
56+
handle_all_throwables
57+
~~~~~~~~~~~~~~~~~~~~~
5858

5959
**type**: ``boolean`` **default**: ``false``
6060

@@ -65,7 +65,7 @@ Starting from Symfony 7.0, the default value of this option will be ``true``.
6565

6666
.. versionadded:: 6.2
6767

68-
The ``catch_all_throwables`` option was introduced in Symfony 6.2.
68+
The ``handle_all_throwables`` option was introduced in Symfony 6.2.
6969

7070
.. _configuration-framework-http_cache:
7171

security/access_token.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ This handler must implement
9494
public function getUserBadgeFrom(string $accessToken): UserBadge
9595
{
9696
// e.g. query the "access token" database to search for this token
97-
$accessToken = $this->repository->findOneByValue($token);
97+
$accessToken = $this->repository->findOneByValue($accessToken);
9898
if (null === $accessToken || !$accessToken->isValid()) {
9999
throw new BadCredentialsException('Invalid credentials.');
100100
}

0 commit comments

Comments
 (0)