@@ -766,31 +766,31 @@ Doctrine Query Language (DQL). DQL is similar to SQL except that you should
766
766
imagine that you're querying for one or more objects of an entity class (e.g. ``Product ``)
767
767
instead of querying for rows on a table (e.g. ``product ``).
768
768
769
- When querying in Doctrine, you have two options: writing pure Doctrine queries
769
+ When querying in Doctrine, you have two main options: writing pure DQL queries
770
770
or using Doctrine's Query Builder.
771
771
772
772
Querying for Objects with DQL
773
773
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
774
774
775
- Imagine that you want to query for products, but only return products that
776
- cost more than `` 19.99 ``, ordered from cheapest to most expensive. You can use
777
- Doctrine's native SQL-like language called DQL to make a query for this::
775
+ Imagine that you want to query for products that cost more than `` 19.99 ``,
776
+ ordered from least to most expensive. You can use DQL, Doctrine's native
777
+ SQL-like language, to construct a query for this scenario ::
778
778
779
779
$em = $this->getDoctrine()->getManager();
780
780
$query = $em->createQuery(
781
781
'SELECT p
782
782
FROM AppBundle:Product p
783
783
WHERE p.price > :price
784
784
ORDER BY p.price ASC'
785
- )->setParameter('price', ' 19.99' );
785
+ )->setParameter('price', 19.99);
786
786
787
787
$products = $query->getResult();
788
788
789
789
If you're comfortable with SQL, then DQL should feel very natural. The biggest
790
- difference is that you need to think in terms of "objects" instead of rows
791
- in a database. For this reason, you select *from * the `` AppBundle:Product ``
792
- * object * (an optional shortcut for `` AppBundle\Entity\Product ``) and then
793
- alias it as ``p ``.
790
+ difference is that you need to think in terms of selecting PHP objects,
791
+ instead of rows in a database. For this reason, you select *from * the
792
+ `` AppBundle:Product `` * entity * (an optional shortcut for the
793
+ `` AppBundle\Entity\Product `` class) and then alias it as ``p ``.
794
794
795
795
.. tip ::
796
796
@@ -844,11 +844,11 @@ Custom Repository Classes
844
844
~~~~~~~~~~~~~~~~~~~~~~~~~
845
845
846
846
In the previous sections, you began constructing and using more complex queries
847
- from inside a controller. In order to isolate, test and reuse these queries,
848
- it's a good practice to create a custom repository class for your entity and
849
- add methods with your query logic there .
847
+ from inside a controller. In order to isolate, reuse and test these queries,
848
+ it's a good practice to create a custom repository class for your entity.
849
+ Methods containing your query logic can then be stored in this class .
850
850
851
- To do this, add the name of the repository class to your mapping definition:
851
+ To do this, add the repository class name to your entity's mapping definition:
852
852
853
853
.. configuration-block ::
854
854
@@ -892,16 +892,22 @@ To do this, add the name of the repository class to your mapping definition:
892
892
</entity >
893
893
</doctrine-mapping >
894
894
895
- Doctrine can generate the repository class for you by running the same command
896
- used earlier to generate the missing getter and setter methods:
895
+ Doctrine can generate empty repository classes for all the entities in your
896
+ application via the same command used earlier to generate the missing getter
897
+ and setter methods:
897
898
898
899
.. code-block :: bash
899
900
900
901
$ php bin/console doctrine:generate:entities AppBundle
901
902
902
- Next, add a new method - ``findAllOrderedByName() `` - to the newly generated
903
- repository class. This method will query for all the ``Product `` entities,
904
- ordered alphabetically.
903
+ .. tip ::
904
+
905
+ If you opt to create the repository classes yourself, they must extend
906
+ ``Doctrine\ORM\EntityRepository ``.
907
+
908
+ Next, add a new method - ``findAllOrderedByName() `` - to the newly-generated
909
+ ``ProductRepository `` class. This method will query for all the ``Product ``
910
+ entities, ordered alphabetically by name.
905
911
906
912
.. code-block :: php
907
913
@@ -943,11 +949,13 @@ You can use this new method just like the default finder methods of the reposito
943
949
Entity Relationships/Associations
944
950
---------------------------------
945
951
946
- Suppose that the products in your application all belong to exactly one "category".
947
- In this case, you'll need a ``Category `` object and a way to relate a ``Product ``
948
- object to a ``Category `` object. Start by creating the ``Category `` entity.
949
- Since you know that you'll eventually need to persist the class through Doctrine,
950
- you can let Doctrine create the class for you.
952
+ Suppose that each product in your application belongs to exactly one category.
953
+ In this case, you'll need a ``Category `` class, and a way to relate a
954
+ ``Product `` object to a ``Category `` object.
955
+
956
+ Start by creating the ``Category `` entity. Since you know that you'll eventually
957
+ need to persist category objects through Doctrine, you can let Doctrine create
958
+ the class for you.
951
959
952
960
.. code-block :: bash
953
961
@@ -961,8 +969,81 @@ a ``name`` field and the associated getter and setter functions.
961
969
Relationship Mapping Metadata
962
970
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
963
971
964
- To relate the ``Category `` and ``Product `` entities, start by creating a
965
- ``products `` property on the ``Category `` class:
972
+ In this example, each category can be associated with *many * products, while
973
+ each product can be associated with only *one * category. This relationship
974
+ can be summarized as: *many * products to *one * category (or equivalently,
975
+ *one * category to *many * products).
976
+
977
+ From the perspective of the ``Product `` entity, this is a many-to-one relationship.
978
+ From the perspective of the ``Category `` entity, this is a one-to-many relationship.
979
+ This is important, because the relative nature of the relationship determines
980
+ which mapping metadata to use. It also determines which class *must * hold
981
+ a reference to the other class.
982
+
983
+ To relate the ``Product `` and ``Category `` entities, simply create a ``category ``
984
+ property on the ``Product `` class, annotated as follows:
985
+
986
+ .. configuration-block ::
987
+
988
+ .. code-block :: php-annotations
989
+
990
+ // src/AppBundle/Entity/Product.php
991
+
992
+ // ...
993
+ class Product
994
+ {
995
+ // ...
996
+
997
+ /**
998
+ * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
999
+ * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
1000
+ */
1001
+ private $category;
1002
+ }
1003
+
1004
+ .. code-block :: yaml
1005
+
1006
+ # src/AppBundle/Resources/config/doctrine/Product.orm.yml
1007
+ AppBundle\Entity\Product :
1008
+ type : entity
1009
+ # ...
1010
+ manyToOne :
1011
+ category :
1012
+ targetEntity : Category
1013
+ inversedBy : products
1014
+ joinColumn :
1015
+ name : category_id
1016
+ referencedColumnName : id
1017
+
1018
+ .. code-block :: xml
1019
+
1020
+ <!-- src/AppBundle/Resources/config/doctrine/Product.orm.xml -->
1021
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
1022
+ <doctrine-mapping xmlns =" http://doctrine-project.org/schemas/orm/doctrine-mapping"
1023
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
1024
+ xsi : schemaLocation =" http://doctrine-project.org/schemas/orm/doctrine-mapping
1025
+ http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd" >
1026
+
1027
+ <entity name =" AppBundle\Entity\Product" >
1028
+ <!-- ... -->
1029
+ <many-to-one
1030
+ field =" category"
1031
+ target-entity =" Category"
1032
+ inversed-by =" products"
1033
+ join-column =" category" >
1034
+
1035
+ <join-column name =" category_id" referenced-column-name =" id" />
1036
+ </many-to-one >
1037
+ </entity >
1038
+ </doctrine-mapping >
1039
+
1040
+ This many-to-one mapping is critical. It tells Doctrine to use the ``category_id ``
1041
+ column on the ``product `` table to relate each record in that table with
1042
+ a record in the ``category `` table.
1043
+
1044
+ Next, since a single ``Category `` object will relate to many ``Product ``
1045
+ objects, a ``products `` property can be added to the ``Category `` class
1046
+ to hold those associated objects.
966
1047
967
1048
.. configuration-block ::
968
1049
@@ -1024,126 +1105,67 @@ To relate the ``Category`` and ``Product`` entities, start by creating a
1024
1105
</entity >
1025
1106
</doctrine-mapping >
1026
1107
1027
- First, since a `` Category `` object will relate to many `` Product `` objects,
1028
- a `` products `` array property is added to hold those `` Product `` objects.
1029
- Again, this isn't done because Doctrine needs it, but instead because it
1030
- makes sense in the application for each ``Category `` to hold an array of
1031
- ``Product `` objects.
1108
+ While the many-to-one mapping shown earlier was mandatory, this one-to-many
1109
+ mapping is optional. It is included here to help demonstrate Doctrine's range
1110
+ of relationship management capabailties. Plus, in the context of this application,
1111
+ it will likely be convenient for each ``Category `` object to automatically
1112
+ own a collection of its related ``Product `` objects.
1032
1113
1033
1114
.. note ::
1034
1115
1035
- The code in the ``__construct() `` method is important because Doctrine
1036
- requires the ``$products `` property to be an ``ArrayCollection `` object.
1037
- This object looks and acts almost *exactly * like an array, but has some
1038
- added flexibility. If this makes you uncomfortable, don't worry. Just
1039
- imagine that it's an ``array `` and you'll be in good shape.
1116
+ The code in the constructor is important. Rather than being instantiated
1117
+ as a traditional ``array ``, the ``$products `` property must be of a type
1118
+ that implements Doctrine's ``Collection `` interface. In this case, an
1119
+ ``ArrayCollection `` object is used. This object looks and acts almost
1120
+ *exactly * like an array, but has some added flexibility. If this makes
1121
+ you uncomfortable, don't worry. Just imagine that it's an ``array ``
1122
+ and you'll be in good shape.
1040
1123
1041
1124
.. tip ::
1042
1125
1043
- The targetEntity value in the decorator used above can reference any entity
1126
+ The targetEntity value in the metadata used above can reference any entity
1044
1127
with a valid namespace, not just entities defined in the same namespace. To
1045
1128
relate to an entity defined in a different class or bundle, enter a full
1046
1129
namespace as the targetEntity.
1047
1130
1048
- Next, since each ``Product `` class can relate to exactly one ``Category ``
1049
- object, you'll want to add a ``$category `` property to the ``Product `` class:
1050
-
1051
- .. configuration-block ::
1052
-
1053
- .. code-block :: php-annotations
1054
-
1055
- // src/AppBundle/Entity/Product.php
1056
-
1057
- // ...
1058
- class Product
1059
- {
1060
- // ...
1061
-
1062
- /**
1063
- * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
1064
- * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
1065
- */
1066
- private $category;
1067
- }
1068
-
1069
- .. code-block :: yaml
1070
-
1071
- # src/AppBundle/Resources/config/doctrine/Product.orm.yml
1072
- AppBundle\Entity\Product :
1073
- type : entity
1074
- # ...
1075
- manyToOne :
1076
- category :
1077
- targetEntity : Category
1078
- inversedBy : products
1079
- joinColumn :
1080
- name : category_id
1081
- referencedColumnName : id
1082
-
1083
- .. code-block :: xml
1084
-
1085
- <!-- src/AppBundle/Resources/config/doctrine/Product.orm.xml -->
1086
- <?xml version =" 1.0" encoding =" UTF-8" ?>
1087
- <doctrine-mapping xmlns =" http://doctrine-project.org/schemas/orm/doctrine-mapping"
1088
- xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
1089
- xsi : schemaLocation =" http://doctrine-project.org/schemas/orm/doctrine-mapping
1090
- http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd" >
1091
-
1092
- <entity name =" AppBundle\Entity\Product" >
1093
- <!-- ... -->
1094
- <many-to-one
1095
- field =" category"
1096
- target-entity =" Category"
1097
- inversed-by =" products"
1098
- join-column =" category" >
1099
-
1100
- <join-column name =" category_id" referenced-column-name =" id" />
1101
- </many-to-one >
1102
- </entity >
1103
- </doctrine-mapping >
1104
-
1105
- Finally, now that you've added a new property to both the ``Category `` and
1106
- ``Product `` classes, tell Doctrine to generate the missing getter and setter
1107
- methods for you:
1131
+ Now that you've added new properties to both the ``Product `` and ``Category ``
1132
+ classes, tell Doctrine to generate the missing getter and setter methods for you:
1108
1133
1109
1134
.. code-block :: bash
1110
1135
1111
1136
$ php bin/console doctrine:generate:entities AppBundle
1112
1137
1113
- Ignore the Doctrine metadata for a moment. You now have two classes - ``Category ``
1114
- and ``Product `` with a natural one-to-many relationship. The ``Category ``
1115
- class holds an array of ``Product `` objects and the ``Product `` object can
1116
- hold one ``Category `` object. In other words - you've built your classes
1117
- in a way that makes sense for your needs. The fact that the data needs to
1118
- be persisted to a database is always secondary.
1119
-
1120
- Now, look at the metadata above the ``$category `` property on the ``Product ``
1121
- class. The information here tells Doctrine that the related class is ``Category ``
1122
- and that it should store the ``id `` of the category record on a ``category_id ``
1123
- field that lives on the ``product `` table. In other words, the related ``Category ``
1124
- object will be stored on the ``$category `` property, but behind the scenes,
1125
- Doctrine will persist this relationship by storing the category's id value
1126
- on a ``category_id `` column of the ``product `` table.
1138
+ Ignore the Doctrine metadata for a moment. You now have two classes - ``Product ``
1139
+ and ``Category ``, with a natural many-to-one relationship. The ``Product ``
1140
+ class holds a *single * ``Category `` object, and the ``Category `` class holds
1141
+ a *collection * of ``Product `` objects. In other words, you've built your classes
1142
+ in a way that makes sense for your application. The fact that the data needs
1143
+ to be persisted to a database is always secondary.
1144
+
1145
+ Now, review the metadata above the ``Product `` entity's ``$category `` property.
1146
+ It tells Doctrine that the related class is ``Category ``, and that the ``id ``
1147
+ of the related category record should be stored in a ``category_id `` field
1148
+ on the ``product `` table.
1149
+
1150
+ In other words, the related ``Category `` object will be stored in the
1151
+ ``$category `` property, but behind the scenes, Doctrine will persist this
1152
+ relationship by storing the category's id in the ``category_id `` column
1153
+ of the ``product `` table.
1127
1154
1128
1155
.. image :: /images/book/doctrine_image_2.png
1129
1156
:align: center
1130
1157
1131
- The metadata above the ``$products `` property of the `` Category `` object
1132
- is less important, and simply tells Doctrine to look at the ``Product.category ``
1158
+ The metadata above the ``Category `` entity's `` $products `` property is less
1159
+ complicated. It simply tells Doctrine to look at the ``Product.category ``
1133
1160
property to figure out how the relationship is mapped.
1134
1161
1135
1162
Before you continue, be sure to tell Doctrine to add the new ``category ``
1136
- table, and ``product.category_id `` column, and new foreign key:
1163
+ table, the new ``product.category_id `` column, and the new foreign key:
1137
1164
1138
1165
.. code-block :: bash
1139
1166
1140
1167
$ php bin/console doctrine:schema:update --force
1141
1168
1142
- .. note ::
1143
-
1144
- This command should only be used during development. For a more robust
1145
- method of systematically updating your production database, read about
1146
- `migrations `_.
1147
1169
1148
1170
Saving Related Entities
1149
1171
~~~~~~~~~~~~~~~~~~~~~~~
0 commit comments