diff --git a/book/doctrine.rst b/book/doctrine.rst
index 6287f49ecdb..e03064a446d 100644
--- a/book/doctrine.rst
+++ b/book/doctrine.rst
@@ -721,15 +721,15 @@ Doctrine Query Language (DQL). DQL is similar to SQL except that you should
imagine that you're querying for one or more objects of an entity class (e.g. ``Product``)
instead of querying for rows on a table (e.g. ``product``).
-When querying in Doctrine, you have two options: writing pure Doctrine queries
+When querying in Doctrine, you have two main options: writing pure DQL queries
or using Doctrine's Query Builder.
Querying for Objects with DQL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Imagine that you want to query for products, but only return products that
-cost more than ``19.99``, ordered from cheapest to most expensive. You can use
-Doctrine's native SQL-like language called DQL to make a query for this::
+Imagine that you want to query for products that cost more than ``19.99``,
+ordered from least to most expensive. You can use DQL, Doctrine's native
+SQL-like language, to construct a query for this scenario::
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
@@ -737,15 +737,15 @@ Doctrine's native SQL-like language called DQL to make a query for this::
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
- )->setParameter('price', '19.99');
+ )->setParameter('price', 19.99);
$products = $query->getResult();
If you're comfortable with SQL, then DQL should feel very natural. The biggest
-difference is that you need to think in terms of "objects" instead of rows
-in a database. For this reason, you select *from* the ``AppBundle:Product``
-*object* (an optional shortcut for ``AppBundle\Entity\Product``) and then
-alias it as ``p``.
+difference is that you need to think in terms of selecting PHP objects,
+instead of rows in a database. For this reason, you select *from* the
+``AppBundle:Product`` *entity* (an optional shortcut for the
+``AppBundle\Entity\Product`` class) and then alias it as ``p``.
.. tip::
@@ -799,11 +799,11 @@ Custom Repository Classes
~~~~~~~~~~~~~~~~~~~~~~~~~
In the previous sections, you began constructing and using more complex queries
-from inside a controller. In order to isolate, test and reuse these queries,
-it's a good practice to create a custom repository class for your entity and
-add methods with your query logic there.
+from inside a controller. In order to isolate, reuse and test these queries,
+it's a good practice to create a custom repository class for your entity.
+Methods containing your query logic can then be stored in this class.
-To do this, add the name of the repository class to your mapping definition:
+To do this, add the repository class name to your entity's mapping definition:
.. configuration-block::
@@ -847,16 +847,22 @@ To do this, add the name of the repository class to your mapping definition:
-Doctrine can generate the repository class for you by running the same command
-used earlier to generate the missing getter and setter methods:
+Doctrine can generate empty repository classes for all the entities in your
+application via the same command used earlier to generate the missing getter
+and setter methods:
.. code-block:: bash
$ php app/console doctrine:generate:entities AppBundle
-Next, add a new method - ``findAllOrderedByName()`` - to the newly generated
-repository class. This method will query for all the ``Product`` entities,
-ordered alphabetically.
+.. tip::
+
+ If you opt to create the repository classes yourself, they must extend
+ ``Doctrine\ORM\EntityRepository``.
+
+Next, add a new method - ``findAllOrderedByName()`` - to the newly-generated
+``ProductRepository`` class. This method will query for all the ``Product``
+entities, ordered alphabetically by name.
.. code-block:: php
@@ -898,11 +904,13 @@ You can use this new method just like the default finder methods of the reposito
Entity Relationships/Associations
---------------------------------
-Suppose that the products in your application all belong to exactly one "category".
-In this case, you'll need a ``Category`` object and a way to relate a ``Product``
-object to a ``Category`` object. Start by creating the ``Category`` entity.
-Since you know that you'll eventually need to persist the class through Doctrine,
-you can let Doctrine create the class for you.
+Suppose that each product in your application belongs to exactly one category.
+In this case, you'll need a ``Category`` class, and a way to relate a
+``Product`` object to a ``Category`` object.
+
+Start by creating the ``Category`` entity. Since you know that you'll eventually
+need to persist category objects through Doctrine, you can let Doctrine create
+the class for you.
.. code-block:: bash
@@ -916,8 +924,81 @@ a ``name`` field and the associated getter and setter functions.
Relationship Mapping Metadata
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To relate the ``Category`` and ``Product`` entities, start by creating a
-``products`` property on the ``Category`` class:
+In this example, each category can be associated with *many* products, while
+each product can be associated with only *one* category. This relationship
+can be summarized as: *many* products to *one* category (or equivalently,
+*one* category to *many* products).
+
+From the perspective of the ``Product`` entity, this is a many-to-one relationship.
+From the perspective of the ``Category`` entity, this is a one-to-many relationship.
+This is important, because the relative nature of the relationship determines
+which mapping metadata to use. It also determines which class *must* hold
+a reference to the other class.
+
+To relate the ``Product`` and ``Category`` entities, simply create a ``category``
+property on the ``Product`` class, annotated as follows:
+
+.. configuration-block::
+
+ .. code-block:: php-annotations
+
+ // src/AppBundle/Entity/Product.php
+
+ // ...
+ class Product
+ {
+ // ...
+
+ /**
+ * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
+ * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
+ */
+ private $category;
+ }
+
+ .. code-block:: yaml
+
+ # src/AppBundle/Resources/config/doctrine/Product.orm.yml
+ AppBundle\Entity\Product:
+ type: entity
+ # ...
+ manyToOne:
+ category:
+ targetEntity: Category
+ inversedBy: products
+ joinColumn:
+ name: category_id
+ referencedColumnName: id
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+This many-to-one mapping is critical. It tells Doctrine to use the ``category_id``
+column on the ``product`` table to relate each record in that table with
+a record in the ``category`` table.
+
+Next, since a single ``Category`` object will relate to many ``Product``
+objects, a ``products`` property can be added to the ``Category`` class
+to hold those associated objects.
.. configuration-block::
@@ -979,126 +1060,67 @@ To relate the ``Category`` and ``Product`` entities, start by creating a
-First, since a ``Category`` object will relate to many ``Product`` objects,
-a ``products`` array property is added to hold those ``Product`` objects.
-Again, this isn't done because Doctrine needs it, but instead because it
-makes sense in the application for each ``Category`` to hold an array of
-``Product`` objects.
+While the many-to-one mapping shown earlier was mandatory, this one-to-many
+mapping is optional. It is included here to help demonstrate Doctrine's range
+of relationship management capabailties. Plus, in the context of this application,
+it will likely be convenient for each ``Category`` object to automatically
+own a collection of its related ``Product`` objects.
.. note::
- The code in the ``__construct()`` method is important because Doctrine
- requires the ``$products`` property to be an ``ArrayCollection`` object.
- This object looks and acts almost *exactly* like an array, but has some
- added flexibility. If this makes you uncomfortable, don't worry. Just
- imagine that it's an ``array`` and you'll be in good shape.
+ The code in the constructor is important. Rather than being instantiated
+ as a traditional ``array``, the ``$products`` property must be of a type
+ that implements Doctrine's ``Collection`` interface. In this case, an
+ ``ArrayCollection`` object is used. This object looks and acts almost
+ *exactly* like an array, but has some added flexibility. If this makes
+ you uncomfortable, don't worry. Just imagine that it's an ``array``
+ and you'll be in good shape.
.. tip::
- The targetEntity value in the decorator used above can reference any entity
+ The targetEntity value in the metadata used above can reference any entity
with a valid namespace, not just entities defined in the same namespace. To
relate to an entity defined in a different class or bundle, enter a full
namespace as the targetEntity.
-Next, since each ``Product`` class can relate to exactly one ``Category``
-object, you'll want to add a ``$category`` property to the ``Product`` class:
-
-.. configuration-block::
-
- .. code-block:: php-annotations
-
- // src/AppBundle/Entity/Product.php
-
- // ...
- class Product
- {
- // ...
-
- /**
- * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
- * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
- */
- private $category;
- }
-
- .. code-block:: yaml
-
- # src/AppBundle/Resources/config/doctrine/Product.orm.yml
- AppBundle\Entity\Product:
- type: entity
- # ...
- manyToOne:
- category:
- targetEntity: Category
- inversedBy: products
- joinColumn:
- name: category_id
- referencedColumnName: id
-
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Finally, now that you've added a new property to both the ``Category`` and
-``Product`` classes, tell Doctrine to generate the missing getter and setter
-methods for you:
+Now that you've added new properties to both the ``Product`` and ``Category``
+classes, tell Doctrine to generate the missing getter and setter methods for you:
.. code-block:: bash
$ php app/console doctrine:generate:entities AppBundle
-Ignore the Doctrine metadata for a moment. You now have two classes - ``Category``
-and ``Product`` with a natural one-to-many relationship. The ``Category``
-class holds an array of ``Product`` objects and the ``Product`` object can
-hold one ``Category`` object. In other words - you've built your classes
-in a way that makes sense for your needs. The fact that the data needs to
-be persisted to a database is always secondary.
-
-Now, look at the metadata above the ``$category`` property on the ``Product``
-class. The information here tells Doctrine that the related class is ``Category``
-and that it should store the ``id`` of the category record on a ``category_id``
-field that lives on the ``product`` table. In other words, the related ``Category``
-object will be stored on the ``$category`` property, but behind the scenes,
-Doctrine will persist this relationship by storing the category's id value
-on a ``category_id`` column of the ``product`` table.
+Ignore the Doctrine metadata for a moment. You now have two classes - ``Product``
+and ``Category``, with a natural many-to-one relationship. The ``Product``
+class holds a *single* ``Category`` object, and the ``Category`` class holds
+a *collection* of ``Product`` objects. In other words, you've built your classes
+in a way that makes sense for your application. The fact that the data needs
+to be persisted to a database is always secondary.
+
+Now, review the metadata above the ``Product`` entity's ``$category`` property.
+It tells Doctrine that the related class is ``Category``, and that the ``id``
+of the related category record should be stored in a ``category_id`` field
+on the ``product`` table.
+
+In other words, the related ``Category`` object will be stored in the
+``$category`` property, but behind the scenes, Doctrine will persist this
+relationship by storing the category's id in the ``category_id`` column
+of the ``product`` table.
.. image:: /images/book/doctrine_image_2.png
:align: center
-The metadata above the ``$products`` property of the ``Category`` object
-is less important, and simply tells Doctrine to look at the ``Product.category``
+The metadata above the ``Category`` entity's ``$products`` property is less
+complicated. It simply tells Doctrine to look at the ``Product.category``
property to figure out how the relationship is mapped.
Before you continue, be sure to tell Doctrine to add the new ``category``
-table, and ``product.category_id`` column, and new foreign key:
+table, the new ``product.category_id`` column, and the new foreign key:
.. code-block:: bash
$ php app/console doctrine:schema:update --force
-.. note::
-
- This command should only be used during development. For a more robust
- method of systematically updating your production database, read about
- `migrations`_.
Saving Related Entities
~~~~~~~~~~~~~~~~~~~~~~~