Reference Mapping
=================
This chapter explains how references between documents are mapped
with Doctrine.
Collections
-----------
In all the examples of many-valued references in this manual we
will make use of a ``Collection`` interface and a corresponding
default implementation ``ArrayCollection`` that are defined in the
``Doctrine\Common\Collections`` namespace. Why do we need that?
Doesn't that couple my domain model to Doctrine? Unfortunately, PHP
arrays, while being great for many things, do not make up for good
collections of business objects, especially not in the context of
an ODM. The reason is that plain PHP arrays can not be
transparently extended / instrumented in PHP code, which is
necessary for a lot of advanced ODM features. The classes /
interfaces that come closest to an OO collection are ArrayAccess
and ArrayObject but until instances of these types can be used in
all places where a plain array can be used (something that may
happen in PHP6) their usability is fairly limited. You "can"
type-hint on ``ArrayAccess`` instead of ``Collection``, since the
Collection interface extends ``ArrayAccess``, but this will
severely limit you in the way you can work with the collection,
because the ``ArrayAccess`` API is (intentionally) very primitive
and more importantly because you can not pass this collection to
all the useful PHP array functions, which makes it very hard to
work with.
**CAUTION** The Collection interface and ArrayCollection class,
like everything else in the Doctrine namespace, are neither part of
the ODM, it is a plain PHP class that has no outside dependencies
apart from dependencies on PHP itself (and the SPL). Therefore
using this class in your domain classes and elsewhere does not
introduce a coupling to the persistence layer. The Collection
class, like everything else in the Common namespace, is not part of
the persistence layer. You could even copy that class over to your
project if you want to remove Doctrine from your project and all
your domain classes will work the same as before.
Reference One
-------------
Reference one document:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
User:
type: document
referenceOne:
shipping:
targetDocument: Documents\Shipping
Reference Many
--------------
Reference many documents:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
User:
type: document
referenceMany:
accounts:
targetDocument: Documents\Account
Mixing Document Types
---------------------
If you want to store different types of documents in references you
can simply omit the ``targetDocument`` option:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
referenceMany:
favorites: ~
Now the ``$favorites`` property can store a reference to any type
of document! The class name will be automatically added for you in
a field named ``_doctrine_class_name``.
You can also specify a discriminator map to avoid storing the fully
qualified class name with each reference:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
referenceMany:
favorites:
discriminatorMap:
album: Documents\Album
song: Documents\Song
If you want to store the discriminator value in a field other than
``_doctrine_class_name`` you can use the ``discriminatorField``
option:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
referenceMany:
favorites:
discriminatorField: type
Simple References
-----------------
By default all references are stored as a ``DBRef`` with the traditional ``$id``,
``$db`` and ``$ref`` fields but if you want you can configure your references
to be simple and only store a ``MongoId``.
Example:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
referenceOne:
profile:
simple: true
Now when you create a new reference to a Profile only a ``MongoId`` instance
will be stored in the ``profile`` field.
Benefits:
- Smaller amount of storage used.
- Performance and simple indexing.
Cascading Operations
--------------------
By default Doctrine will not cascade any ``UnitOfWork`` operations
to referenced documents so if wish to have this functionality you
must explicitly enable it:
.. configuration-block::
.. code-block:: php
.. code-block:: yaml
referenceOne:
profile:
cascade: [persist]
The valid values are:
- **all** - cascade on all operations by default.
- **detach** - cascade detach operation to referenced documents.
- **merge** - cascade merge operation to referenced documents.
- **refresh** - cascade refresh operation to referenced documents.
- **remove** - cascade remove operation to referenced documents.
- **persist** - cascade persist operation to referenced documents.