@@ -598,15 +598,59 @@ the :ref:`doctrine-queries` section.
598
598
see the web debug toolbar, install the ``profiler `` :ref: `Symfony pack <symfony-packs >`
599
599
by running this command: ``composer require --dev symfony/profiler-pack ``.
600
600
601
- Automatically Fetching Objects (ParamConverter )
602
- -----------------------------------------------
601
+ Automatically Fetching Objects (EntityValueResolver )
602
+ ----------------------------------------------------
603
603
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 :
604
+ In many cases, you can use the `EntityValueResolver `_ to do the query for you
605
+ automatically! First, enable the feature :
606
606
607
- .. code-block :: terminal
607
+ .. configuration-block ::
608
+
609
+ .. code-block :: yaml
610
+
611
+ # config/packages/doctrine.yaml
612
+ doctrine :
613
+ orm :
614
+ controller_resolver :
615
+ enabled : true
616
+ auto_mapping : true
617
+ evict_cache : false
618
+
619
+ .. code-block :: xml
620
+
621
+ <!-- config/packages/doctrine.xml -->
622
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
623
+ <container xmlns =" http://symfony.com/schema/dic/services"
624
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
625
+ xmlns : doctrine =" http://symfony.com/schema/dic/doctrine"
626
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
627
+ https://symfony.com/schema/dic/services/services-1.0.xsd
628
+ http://symfony.com/schema/dic/doctrine
629
+ https://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd" >
608
630
609
- $ composer require sensio/framework-extra-bundle
631
+ <doctrine : config >
632
+ <!-- by convention the env var names are always uppercase -->
633
+ <doctrine : orm >
634
+ <doctrine : controller_resolver auto_mapping =" true" evict_cache =" false" />
635
+ </doctrine : orm >
636
+ </doctrine : config >
637
+
638
+ </container >
639
+
640
+ .. code-block :: php
641
+
642
+ // config/packages/doctrine.php
643
+ use Symfony\Config\DoctrineConfig;
644
+
645
+ return static function (DoctrineConfig $doctrine) {
646
+ $controllerResolver = $doctrine->orm()
647
+ ->entityManager('default')
648
+ // ...
649
+ ->controllerResolver();
650
+
651
+ $controllerResolver->autoMapping(true);
652
+ $controllerResolver->evictCache(true);
653
+ };
610
654
611
655
Now, simplify your controller::
612
656
@@ -621,7 +665,7 @@ Now, simplify your controller::
621
665
622
666
class ProductController extends AbstractController
623
667
{
624
- #[Route('/product/{id}', name: 'product_show' )]
668
+ #[Route('/product/{id}')]
625
669
public function show(Product $product): Response
626
670
{
627
671
// use the Product!
@@ -632,7 +676,212 @@ Now, simplify your controller::
632
676
That's it! The bundle uses the ``{id} `` from the route to query for the ``Product ``
633
677
by the ``id `` column. If it's not found, a 404 page is generated.
634
678
635
- There are many more options you can use. Read more about the `ParamConverter `_.
679
+ This behavior can be enabled on all your controllers, by setting the ``auto_mapping ``
680
+ parameter to ``true ``. Or individually on the desired controllers by using the
681
+ ``MapEntity `` attribute:
682
+
683
+ // src/Controller/ProductController.php
684
+ namespace App\C ontroller;
685
+
686
+ use App\E ntity\P roduct;
687
+ use App\R epository\P roductRepository;
688
+ use Symfony\B ridge\D octrine\A ttribute\M apEntity;
689
+ use Symfony\C omponent\H ttpFoundation\R esponse;
690
+ use Symfony\C omponent\R outing\A nnotation\R oute;
691
+ // ...
692
+
693
+ class ProductController extends AbstractController
694
+ {
695
+ #[Route('/product/{id}')]
696
+ public function show(
697
+ #[MapEntity]
698
+ Product $product
699
+ ): Response {
700
+ // use the Product!
701
+ // ...
702
+ }
703
+ }
704
+
705
+ Fetch Automatically
706
+ ~~~~~~~~~~~~~~~~~~~
707
+
708
+ If your route wildcards match properties on your entity, then the resolver
709
+ will automatically fetch them:
710
+
711
+ .. configuration-block ::
712
+
713
+ .. code-block :: php-attributes
714
+
715
+ /**
716
+ * Fetch via primary key because {id} is in the route.
717
+ */
718
+ #[Route('/product/{id}')]
719
+ public function showByPk(Post $post): Response
720
+ {
721
+ }
722
+
723
+ /**
724
+ * Perform a findOneBy() where the slug property matches {slug}.
725
+ */
726
+ #[Route('/product/{slug}')]
727
+ public function showBySlug(Post $post): Response
728
+ {
729
+ }
730
+
731
+ Automatic fetching works in these situations:
732
+
733
+ * If ``{id} `` is in your route, then this is used to fetch by
734
+ primary key via the ``find() `` method.
735
+
736
+ * The resolver will attempt to do a ``findOneBy() `` fetch by using
737
+ *all * of the wildcards in your route that are actually properties
738
+ on your entity (non-properties are ignored).
739
+
740
+ You can control this behavior by actually *adding * the ``MapEntity ``
741
+ attribute and using the `MapEntity options `_.
742
+
743
+ Fetch via an Expression
744
+ ~~~~~~~~~~~~~~~~~~~~~~~
745
+
746
+ If automatic fetching doesn't work, use an expression:
747
+
748
+ .. configuration-block ::
749
+
750
+ .. code-block :: php-attributes
751
+
752
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
753
+
754
+ #[Route('/product/{product_id}')]
755
+ public function show(
756
+ #[MapEntity(expr: 'repository.find(product_id)')]
757
+ Product $product
758
+ ): Response {
759
+ }
760
+
761
+ Use the special ``MapEntity `` attribute with an ``expr `` option to
762
+ fetch the object by calling a method on your repository. The
763
+ ``repository `` method will be your entity's Repository class and
764
+ any route wildcards - like ``{product_id} `` are available as variables.
765
+
766
+ This can also be used to help resolve multiple arguments:
767
+
768
+ .. configuration-block ::
769
+
770
+ .. code-block :: php-attributes
771
+
772
+ #[Route('/product/{id}/comments/{comment_id}')]
773
+ public function show(
774
+ Product $product
775
+ #[MapEntity(expr: 'repository.find(comment_id)')]
776
+ Comment $comment
777
+ ): Response {
778
+ }
779
+
780
+ In the example above, the ``$product `` argument is handled automatically,
781
+ but ``$comment `` is configured with the attribute since they cannot both follow
782
+ the default convention.
783
+
784
+ .. _`MapEntity options` :
785
+
786
+
787
+ MapEntity Options
788
+ ~~~~~~~~~~~~~~~~~
789
+
790
+ A number of ``options `` are available on the ``MapEntity `` annotation to
791
+ control behavior:
792
+
793
+ * ``id ``: If an ``id `` option is configured and matches a route parameter, then
794
+ the resolver will find by the primary key:
795
+
796
+ .. configuration-block ::
797
+
798
+ .. code-block :: php-attributes
799
+
800
+ #[Route('/product/{product_id}')]
801
+ public function show(
802
+ Product $product
803
+ #[MapEntity(id: 'product_id')]
804
+ Comment $comment
805
+ ): Response {
806
+ }
807
+
808
+ * ``mapping ``: Configures the properties and values to use with the ``findOneBy() ``
809
+ method: the key is the route placeholder name and the value is the Doctrine
810
+ property name:
811
+
812
+ .. configuration-block ::
813
+
814
+ .. code-block :: php-attributes
815
+
816
+ #[Route('/product/{category}/{slug}/comments/{comment_slug}')]
817
+ public function show(
818
+ #[MapEntity(mapping: ['date' => 'date', 'slug' => 'slug'])]
819
+ Product $product
820
+ #[MapEntity(mapping: ['comment_slug' => 'slug'])]
821
+ Comment $comment
822
+ ): Response {
823
+ }
824
+
825
+ * ``exclude `` Configures the properties that should be used in the ``findOneBy() ``
826
+ method by *excluding * one or more properties so that not *all * are used:
827
+
828
+ .. configuration-block ::
829
+
830
+ .. code-block :: php-attributes
831
+
832
+ #[Route('/product/{slug}/{date}')]
833
+ public function show(
834
+ #[MapEntity(exclude: ['date'])]
835
+ Product $product
836
+ \DateTime $date
837
+ ): Response {
838
+ }
839
+
840
+ * ``stripNull `` If true, then when ``findOneBy() `` is used, any values that
841
+ are ``null `` will not be used for the query.
842
+
843
+ * ``entityManager `` By default, the ``EntityValueResolver `` uses the *default *
844
+ entity manager, but you can configure this:
845
+
846
+ .. configuration-block ::
847
+
848
+ .. code-block :: php-attributes
849
+
850
+ #[Route('/product/{id}')]
851
+ public function show(
852
+ #[MapEntity(entityManager: ['foo'])]
853
+ Product $product
854
+ ): Response {
855
+ }
856
+
857
+ * ``evictCache `` If true, forces Doctrine to always fetch the entity from the
858
+ database instead of cache.
859
+
860
+ * ``disabled `` If true, the ``EntityValueResolver `` will not try to replace
861
+ the argument.
862
+
863
+ .. tip ::
864
+
865
+ When enabled globally, it's possible to disabled the behavior on a specific
866
+ controller, by using the ``MapEntity `` set to ``disabled ``.
867
+
868
+ public function show(
869
+ #[CurrentUser]
870
+ #[MapEntity(disabled: true)]
871
+ User $user
872
+ ): Response {
873
+ // User is not resolved by the EntityValueResolver
874
+ // ...
875
+ }
876
+
877
+ .. versionadded :: 6.2
878
+
879
+ Entity Value Resolver was introduced in Symfony 6.2.
880
+
881
+ .. versionadded :: 2.7.1
882
+
883
+ Autowiring of the ``EntityValueResolver `` was introduced in DoctrineBundle
884
+ 2.7.1.
636
885
637
886
Updating an Object
638
887
------------------
@@ -896,7 +1145,6 @@ Learn more
896
1145
.. _`DoctrineMigrationsBundle` : https://github.com/doctrine/DoctrineMigrationsBundle
897
1146
.. _`NativeQuery` : https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/native-sql.html
898
1147
.. _`SensioFrameworkExtraBundle` : https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html
899
- .. _`ParamConverter` : https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
900
1148
.. _`limit of 767 bytes for the index key prefix` : https://dev.mysql.com/doc/refman/5.6/en/innodb-limits.html
901
1149
.. _`Doctrine screencast series` : https://symfonycasts.com/screencast/symfony-doctrine
902
1150
.. _`API Platform` : https://api-platform.com/docs/core/validation/
0 commit comments