@@ -721,31 +721,31 @@ Doctrine Query Language (DQL). DQL is similar to SQL except that you should
721
721
imagine that you're querying for one or more objects of an entity class (e.g. ``Product ``)
722
722
instead of querying for rows on a table (e.g. ``product ``).
723
723
724
- When querying in Doctrine, you have two options: writing pure Doctrine queries
724
+ When querying in Doctrine, you have two main options: writing pure DQL queries
725
725
or using Doctrine's Query Builder.
726
726
727
727
Querying for Objects with DQL
728
728
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
729
729
730
- Imagine that you want to query for products, but only return products that
731
- cost more than `` 19.99 ``, ordered from cheapest to most expensive. You can use
732
- Doctrine's native SQL-like language called DQL to make a query for this::
730
+ Imagine that you want to query for products that cost more than `` 19.99 ``,
731
+ ordered from least to most expensive. You can use DQL, Doctrine's native
732
+ SQL-like language, to construct a query for this scenario ::
733
733
734
734
$em = $this->getDoctrine()->getManager();
735
735
$query = $em->createQuery(
736
736
'SELECT p
737
737
FROM AppBundle:Product p
738
738
WHERE p.price > :price
739
739
ORDER BY p.price ASC'
740
- )->setParameter('price', ' 19.99' );
740
+ )->setParameter('price', 19.99);
741
741
742
742
$products = $query->getResult();
743
743
744
744
If you're comfortable with SQL, then DQL should feel very natural. The biggest
745
- difference is that you need to think in terms of "objects" instead of rows
746
- in a database. For this reason, you select *from * the `` AppBundle:Product ``
747
- * object * (an optional shortcut for `` AppBundle\Entity\Product ``) and then
748
- alias it as ``p ``.
745
+ difference is that you need to think in terms of selecting PHP objects,
746
+ instead of rows in a database. For this reason, you select *from * the
747
+ `` AppBundle:Product `` * entity * (an optional shortcut for the
748
+ `` AppBundle\Entity\Product `` class) and then alias it as ``p ``.
749
749
750
750
.. tip ::
751
751
@@ -799,11 +799,11 @@ Custom Repository Classes
799
799
~~~~~~~~~~~~~~~~~~~~~~~~~
800
800
801
801
In the previous sections, you began constructing and using more complex queries
802
- from inside a controller. In order to isolate, test and reuse these queries,
803
- it's a good practice to create a custom repository class for your entity and
804
- add methods with your query logic there .
802
+ from inside a controller. In order to isolate, reuse and test these queries,
803
+ it's a good practice to create a custom repository class for your entity.
804
+ Methods containing your query logic can then be stored in this class .
805
805
806
- To do this, add the name of the repository class to your mapping definition:
806
+ To do this, add the repository class name to your entity's mapping definition:
807
807
808
808
.. configuration-block ::
809
809
@@ -847,16 +847,22 @@ To do this, add the name of the repository class to your mapping definition:
847
847
</entity >
848
848
</doctrine-mapping >
849
849
850
- Doctrine can generate the repository class for you by running the same command
851
- used earlier to generate the missing getter and setter methods:
850
+ Doctrine can generate empty repository classes for all the entities in your
851
+ application via the same command used earlier to generate the missing getter
852
+ and setter methods:
852
853
853
854
.. code-block :: bash
854
855
855
856
$ php app/console doctrine:generate:entities AppBundle
856
857
857
- Next, add a new method - ``findAllOrderedByName() `` - to the newly generated
858
- repository class. This method will query for all the ``Product `` entities,
859
- ordered alphabetically.
858
+ .. tip ::
859
+
860
+ If you opt to create the repository classes yourself, they must extend
861
+ ``Doctrine\ORM\EntityRepository ``.
862
+
863
+ Next, add a new method - ``findAllOrderedByName() `` - to the newly-generated
864
+ ``ProductRepository `` class. This method will query for all the ``Product ``
865
+ entities, ordered alphabetically by name.
860
866
861
867
.. code-block :: php
862
868
@@ -898,11 +904,13 @@ You can use this new method just like the default finder methods of the reposito
898
904
Entity Relationships/Associations
899
905
---------------------------------
900
906
901
- Suppose that the products in your application all belong to exactly one "category".
902
- In this case, you'll need a ``Category `` object and a way to relate a ``Product ``
903
- object to a ``Category `` object. Start by creating the ``Category `` entity.
904
- Since you know that you'll eventually need to persist the class through Doctrine,
905
- you can let Doctrine create the class for you.
907
+ Suppose that each product in your application belongs to exactly one category.
908
+ In this case, you'll need a ``Category `` class, and a way to relate a
909
+ ``Product `` object to a ``Category `` object.
910
+
911
+ Start by creating the ``Category `` entity. Since you know that you'll eventually
912
+ need to persist category objects through Doctrine, you can let Doctrine create
913
+ the class for you.
906
914
907
915
.. code-block :: bash
908
916
@@ -916,8 +924,81 @@ a ``name`` field and the associated getter and setter functions.
916
924
Relationship Mapping Metadata
917
925
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
918
926
919
- To relate the ``Category `` and ``Product `` entities, start by creating a
920
- ``products `` property on the ``Category `` class:
927
+ In this example, each category can be associated with *many * products, while
928
+ each product can be associated with only *one * category. This relationship
929
+ can be summarized as: *many * products to *one * category (or equivalently,
930
+ *one * category to *many * products).
931
+
932
+ From the perspective of the ``Product `` entity, this is a many-to-one relationship.
933
+ From the perspective of the ``Category `` entity, this is a one-to-many relationship.
934
+ This is important, because the relative nature of the relationship determines
935
+ which mapping metadata to use. It also determines which class *must * hold
936
+ a reference to the other class.
937
+
938
+ To relate the ``Product `` and ``Category `` entities, simply create a ``category ``
939
+ property on the ``Product `` class, annotated as follows:
940
+
941
+ .. configuration-block ::
942
+
943
+ .. code-block :: php-annotations
944
+
945
+ // src/AppBundle/Entity/Product.php
946
+
947
+ // ...
948
+ class Product
949
+ {
950
+ // ...
951
+
952
+ /**
953
+ * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
954
+ * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
955
+ */
956
+ private $category;
957
+ }
958
+
959
+ .. code-block :: yaml
960
+
961
+ # src/AppBundle/Resources/config/doctrine/Product.orm.yml
962
+ AppBundle\Entity\Product :
963
+ type : entity
964
+ # ...
965
+ manyToOne :
966
+ category :
967
+ targetEntity : Category
968
+ inversedBy : products
969
+ joinColumn :
970
+ name : category_id
971
+ referencedColumnName : id
972
+
973
+ .. code-block :: xml
974
+
975
+ <!-- src/AppBundle/Resources/config/doctrine/Product.orm.xml -->
976
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
977
+ <doctrine-mapping xmlns =" http://doctrine-project.org/schemas/orm/doctrine-mapping"
978
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
979
+ xsi : schemaLocation =" http://doctrine-project.org/schemas/orm/doctrine-mapping
980
+ http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd" >
981
+
982
+ <entity name =" AppBundle\Entity\Product" >
983
+ <!-- ... -->
984
+ <many-to-one
985
+ field =" category"
986
+ target-entity =" Category"
987
+ inversed-by =" products"
988
+ join-column =" category" >
989
+
990
+ <join-column name =" category_id" referenced-column-name =" id" />
991
+ </many-to-one >
992
+ </entity >
993
+ </doctrine-mapping >
994
+
995
+ This many-to-one mapping is critical. It tells Doctrine to use the ``category_id ``
996
+ column on the ``product `` table to relate each record in that table with
997
+ a record in the ``category `` table.
998
+
999
+ Next, since a single ``Category `` object will relate to many ``Product ``
1000
+ objects, a ``products `` property can be added to the ``Category `` class
1001
+ to hold those associated objects.
921
1002
922
1003
.. configuration-block ::
923
1004
@@ -979,126 +1060,67 @@ To relate the ``Category`` and ``Product`` entities, start by creating a
979
1060
</entity >
980
1061
</doctrine-mapping >
981
1062
982
- First, since a `` Category `` object will relate to many `` Product `` objects,
983
- a `` products `` array property is added to hold those `` Product `` objects.
984
- Again, this isn't done because Doctrine needs it, but instead because it
985
- makes sense in the application for each ``Category `` to hold an array of
986
- ``Product `` objects.
1063
+ While the many-to-one mapping shown earlier was mandatory, this one-to-many
1064
+ mapping is optional. It is included here to help demonstrate Doctrine's range
1065
+ of relationship management capabailties. Plus, in the context of this application,
1066
+ it will likely be convenient for each ``Category `` object to automatically
1067
+ own a collection of its related ``Product `` objects.
987
1068
988
1069
.. note ::
989
1070
990
- The code in the ``__construct() `` method is important because Doctrine
991
- requires the ``$products `` property to be an ``ArrayCollection `` object.
992
- This object looks and acts almost *exactly * like an array, but has some
993
- added flexibility. If this makes you uncomfortable, don't worry. Just
994
- imagine that it's an ``array `` and you'll be in good shape.
1071
+ The code in the constructor is important. Rather than being instantiated
1072
+ as a traditional ``array ``, the ``$products `` property must be of a type
1073
+ that implements Doctrine's ``Collection `` interface. In this case, an
1074
+ ``ArrayCollection `` object is used. This object looks and acts almost
1075
+ *exactly * like an array, but has some added flexibility. If this makes
1076
+ you uncomfortable, don't worry. Just imagine that it's an ``array ``
1077
+ and you'll be in good shape.
995
1078
996
1079
.. tip ::
997
1080
998
- The targetEntity value in the decorator used above can reference any entity
1081
+ The targetEntity value in the metadata used above can reference any entity
999
1082
with a valid namespace, not just entities defined in the same namespace. To
1000
1083
relate to an entity defined in a different class or bundle, enter a full
1001
1084
namespace as the targetEntity.
1002
1085
1003
- Next, since each ``Product `` class can relate to exactly one ``Category ``
1004
- object, you'll want to add a ``$category `` property to the ``Product `` class:
1005
-
1006
- .. configuration-block ::
1007
-
1008
- .. code-block :: php-annotations
1009
-
1010
- // src/AppBundle/Entity/Product.php
1011
-
1012
- // ...
1013
- class Product
1014
- {
1015
- // ...
1016
-
1017
- /**
1018
- * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
1019
- * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
1020
- */
1021
- private $category;
1022
- }
1023
-
1024
- .. code-block :: yaml
1025
-
1026
- # src/AppBundle/Resources/config/doctrine/Product.orm.yml
1027
- AppBundle\Entity\Product :
1028
- type : entity
1029
- # ...
1030
- manyToOne :
1031
- category :
1032
- targetEntity : Category
1033
- inversedBy : products
1034
- joinColumn :
1035
- name : category_id
1036
- referencedColumnName : id
1037
-
1038
- .. code-block :: xml
1039
-
1040
- <!-- src/AppBundle/Resources/config/doctrine/Product.orm.xml -->
1041
- <?xml version =" 1.0" encoding =" UTF-8" ?>
1042
- <doctrine-mapping xmlns =" http://doctrine-project.org/schemas/orm/doctrine-mapping"
1043
- xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
1044
- xsi : schemaLocation =" http://doctrine-project.org/schemas/orm/doctrine-mapping
1045
- http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd" >
1046
-
1047
- <entity name =" AppBundle\Entity\Product" >
1048
- <!-- ... -->
1049
- <many-to-one
1050
- field =" category"
1051
- target-entity =" Category"
1052
- inversed-by =" products"
1053
- join-column =" category" >
1054
-
1055
- <join-column name =" category_id" referenced-column-name =" id" />
1056
- </many-to-one >
1057
- </entity >
1058
- </doctrine-mapping >
1059
-
1060
- Finally, now that you've added a new property to both the ``Category `` and
1061
- ``Product `` classes, tell Doctrine to generate the missing getter and setter
1062
- methods for you:
1086
+ Now that you've added new properties to both the ``Product `` and ``Category ``
1087
+ classes, tell Doctrine to generate the missing getter and setter methods for you:
1063
1088
1064
1089
.. code-block :: bash
1065
1090
1066
1091
$ php app/console doctrine:generate:entities AppBundle
1067
1092
1068
- Ignore the Doctrine metadata for a moment. You now have two classes - ``Category ``
1069
- and ``Product `` with a natural one-to-many relationship. The ``Category ``
1070
- class holds an array of ``Product `` objects and the ``Product `` object can
1071
- hold one ``Category `` object. In other words - you've built your classes
1072
- in a way that makes sense for your needs. The fact that the data needs to
1073
- be persisted to a database is always secondary.
1074
-
1075
- Now, look at the metadata above the ``$category `` property on the ``Product ``
1076
- class. The information here tells Doctrine that the related class is ``Category ``
1077
- and that it should store the ``id `` of the category record on a ``category_id ``
1078
- field that lives on the ``product `` table. In other words, the related ``Category ``
1079
- object will be stored on the ``$category `` property, but behind the scenes,
1080
- Doctrine will persist this relationship by storing the category's id value
1081
- on a ``category_id `` column of the ``product `` table.
1093
+ Ignore the Doctrine metadata for a moment. You now have two classes - ``Product ``
1094
+ and ``Category ``, with a natural many-to-one relationship. The ``Product ``
1095
+ class holds a *single * ``Category `` object, and the ``Category `` class holds
1096
+ a *collection * of ``Product `` objects. In other words, you've built your classes
1097
+ in a way that makes sense for your application. The fact that the data needs
1098
+ to be persisted to a database is always secondary.
1099
+
1100
+ Now, review the metadata above the ``Product `` entity's ``$category `` property.
1101
+ It tells Doctrine that the related class is ``Category ``, and that the ``id ``
1102
+ of the related category record should be stored in a ``category_id `` field
1103
+ on the ``product `` table.
1104
+
1105
+ In other words, the related ``Category `` object will be stored in the
1106
+ ``$category `` property, but behind the scenes, Doctrine will persist this
1107
+ relationship by storing the category's id in the ``category_id `` column
1108
+ of the ``product `` table.
1082
1109
1083
1110
.. image :: /images/book/doctrine_image_2.png
1084
1111
:align: center
1085
1112
1086
- The metadata above the ``$products `` property of the `` Category `` object
1087
- is less important, and simply tells Doctrine to look at the ``Product.category ``
1113
+ The metadata above the ``Category `` entity's `` $products `` property is less
1114
+ complicated. It simply tells Doctrine to look at the ``Product.category ``
1088
1115
property to figure out how the relationship is mapped.
1089
1116
1090
1117
Before you continue, be sure to tell Doctrine to add the new ``category ``
1091
- table, and ``product.category_id `` column, and new foreign key:
1118
+ table, the new ``product.category_id `` column, and the new foreign key:
1092
1119
1093
1120
.. code-block :: bash
1094
1121
1095
1122
$ php app/console doctrine:schema:update --force
1096
1123
1097
- .. note ::
1098
-
1099
- This command should only be used during development. For a more robust
1100
- method of systematically updating your production database, read about
1101
- `migrations `_.
1102
1124
1103
1125
Saving Related Entities
1104
1126
~~~~~~~~~~~~~~~~~~~~~~~
0 commit comments