@@ -766,31 +766,31 @@ Doctrine Query Language (DQL). DQL is similar to SQL except that you should
766766imagine that you're querying for one or more objects of an entity class (e.g. ``Product ``)
767767instead of querying for rows on a table (e.g. ``product ``).
768768
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
770770or using Doctrine's Query Builder.
771771
772772Querying for Objects with DQL
773773~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
774774
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 ::
778778
779779 $em = $this->getDoctrine()->getManager();
780780 $query = $em->createQuery(
781781 'SELECT p
782782 FROM AppBundle:Product p
783783 WHERE p.price > :price
784784 ORDER BY p.price ASC'
785- )->setParameter('price', ' 19.99' );
785+ )->setParameter('price', 19.99);
786786
787787 $products = $query->getResult();
788788
789789If 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 ``.
794794
795795.. tip ::
796796
@@ -844,11 +844,11 @@ Custom Repository Classes
844844~~~~~~~~~~~~~~~~~~~~~~~~~
845845
846846In 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 .
850850
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:
852852
853853.. configuration-block ::
854854
@@ -892,16 +892,22 @@ To do this, add the name of the repository class to your mapping definition:
892892 </entity >
893893 </doctrine-mapping >
894894
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:
897898
898899.. code-block :: bash
899900
900901 $ php bin/console doctrine:generate:entities AppBundle
901902
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.
905911
906912.. code-block :: php
907913
@@ -943,11 +949,13 @@ You can use this new method just like the default finder methods of the reposito
943949Entity Relationships/Associations
944950---------------------------------
945951
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.
951959
952960.. code-block :: bash
953961
@@ -961,8 +969,81 @@ a ``name`` field and the associated getter and setter functions.
961969Relationship Mapping Metadata
962970~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
963971
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.
9661047
9671048.. configuration-block ::
9681049
@@ -1024,126 +1105,67 @@ To relate the ``Category`` and ``Product`` entities, start by creating a
10241105 </entity >
10251106 </doctrine-mapping >
10261107
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.
10321113
10331114.. note ::
10341115
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.
10401123
10411124.. tip ::
10421125
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
10441127 with a valid namespace, not just entities defined in the same namespace. To
10451128 relate to an entity defined in a different class or bundle, enter a full
10461129 namespace as the targetEntity.
10471130
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:
11081133
11091134.. code-block :: bash
11101135
11111136 $ php bin/console doctrine:generate:entities AppBundle
11121137
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.
11271154
11281155.. image :: /images/book/doctrine_image_2.png
11291156 :align: center
11301157
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 ``
11331160property to figure out how the relationship is mapped.
11341161
11351162Before 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:
11371164
11381165.. code-block :: bash
11391166
11401167 $ php bin/console doctrine:schema:update --force
11411168
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 `_.
11471169
11481170 Saving Related Entities
11491171~~~~~~~~~~~~~~~~~~~~~~~
0 commit comments