@@ -721,31 +721,31 @@ Doctrine Query Language (DQL). DQL is similar to SQL except that you should
721721imagine that you're querying for one or more objects of an entity class (e.g. ``Product ``)
722722instead of querying for rows on a table (e.g. ``product ``).
723723
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
725725or using Doctrine's Query Builder.
726726
727727Querying for Objects with DQL
728728~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
729729
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 ::
733733
734734 $em = $this->getDoctrine()->getManager();
735735 $query = $em->createQuery(
736736 'SELECT p
737737 FROM AppBundle:Product p
738738 WHERE p.price > :price
739739 ORDER BY p.price ASC'
740- )->setParameter('price', ' 19.99' );
740+ )->setParameter('price', 19.99);
741741
742742 $products = $query->getResult();
743743
744744If 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 ``.
749749
750750.. tip ::
751751
@@ -799,11 +799,11 @@ Custom Repository Classes
799799~~~~~~~~~~~~~~~~~~~~~~~~~
800800
801801In 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 .
805805
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:
807807
808808.. configuration-block ::
809809
@@ -847,16 +847,22 @@ To do this, add the name of the repository class to your mapping definition:
847847 </entity >
848848 </doctrine-mapping >
849849
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:
852853
853854.. code-block :: bash
854855
855856 $ php app/console doctrine:generate:entities AppBundle
856857
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.
860866
861867.. code-block :: php
862868
@@ -898,11 +904,13 @@ You can use this new method just like the default finder methods of the reposito
898904Entity Relationships/Associations
899905---------------------------------
900906
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.
906914
907915.. code-block :: bash
908916
@@ -916,8 +924,81 @@ a ``name`` field and the associated getter and setter functions.
916924Relationship Mapping Metadata
917925~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
918926
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.
9211002
9221003.. configuration-block ::
9231004
@@ -979,126 +1060,67 @@ To relate the ``Category`` and ``Product`` entities, start by creating a
9791060 </entity >
9801061 </doctrine-mapping >
9811062
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.
9871068
9881069.. note ::
9891070
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.
9951078
9961079.. tip ::
9971080
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
9991082 with a valid namespace, not just entities defined in the same namespace. To
10001083 relate to an entity defined in a different class or bundle, enter a full
10011084 namespace as the targetEntity.
10021085
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:
10631088
10641089.. code-block :: bash
10651090
10661091 $ php app/console doctrine:generate:entities AppBundle
10671092
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.
10821109
10831110.. image :: /images/book/doctrine_image_2.png
10841111 :align: center
10851112
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 ``
10881115property to figure out how the relationship is mapped.
10891116
10901117Before 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:
10921119
10931120.. code-block :: bash
10941121
10951122 $ php app/console doctrine:schema:update --force
10961123
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 `_.
11021124
11031125 Saving Related Entities
11041126~~~~~~~~~~~~~~~~~~~~~~~
0 commit comments