You are browsing a version that is no longer maintained.

Reference Mapping

This chapter explains how references between documents are mapped with Doctrine.

Collections

Examples of many-valued references in this manual make use of a Collection interface and a corresponding ArrayCollection implementation, which are defined in the Doctrine\Common\Collections namespace. These classes have no dependencies on ODM, and can therefore be used within your domain model and elsewhere without introducing coupling to the persistence layer.

ODM also provides a PersistentCollection implementation of Collection, which incorporates change-tracking functionality; however, this class is constructed internally during hydration. As a developer, you should develop with the Collection interface in mind so that your code can operate with any implementation.

Why are these classes used over PHP arrays? Native arrays cannot be transparently extended in PHP, which is necessary for many advanced features provided by the ODM. Although PHP does provide various interfaces that allow objects to operate like arrays (e.g. Traversable, Countable, ArrayAccess), and even a concrete implementation in ArrayObject, these objects cannot always be used everywhere that a native array is accepted. Doctrine's Collection interface and ArrayCollection implementation are conceptually very similar to ArrayObject, with some slight differences and improvements.

Reference One

Reference one document:

  • PHP
    1<?php /** @Document */ class Product { // ... /** * @ReferenceOne(targetDocument="Shipping") */ private $shipping; // ... } /** @Document */ class Shipping { // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
  • XML
    1<?xml version="1.0" encoding="UTF-8"?> <doctrine-mongo-mapping xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd"> <document name="Documents\Product"> <reference-one field="shipping" target-document="Documents\Shipping" /> </document> </doctrine-mongo-mapping>
    2
    3
    4
    5
    6
    7
    8
    9
  • YAML
    1User: type: document referenceOne: shipping: targetDocument: Documents\Shipping
    2
    3
    4
    5

Reference Many

Reference many documents:

  • PHP
    1<?php /** @Document */ class User { // ... /** * @ReferenceMany(targetDocument="Account") */ private $accounts = array(); // ... } /** @Document */ class Account { // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
  • XML
    1<?xml version="1.0" encoding="UTF-8"?> <doctrine-mongo-mapping xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd"> <document name="Documents\Product"> <reference-many field="accounts" target-document="Documents\Account" /> </document> </doctrine-mongo-mapping>
    2
    3
    4
    5
    6
    7
    8
    9
  • YAML
    1User: type: document referenceMany: accounts: targetDocument: Documents\Account
    2
    3
    4
    5

Mixing Document Types

If you want to store different types of documents in references, you can simply omit the targetDocument option:

  • PHP
    1<?php /** @Document */ class User { // .. /** @ReferenceMany */ private $favorites = array(); // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  • XML
    1<field fieldName="favorites" />
  • YAML
    1referenceMany: favorites: ~
    2

Now the $favorites property can store a reference to any type of document! The class name will be automatically stored in a field named _doctrine_class_name within the DBRef object.

The MongoDB shell tends to ignore fields other than $id and $ref when displaying DBRef objects. You can verify the presence of any $db and discriminator fields by querying and examining the document with a driver. See SERVER-10777
for additional discussion on this issue.

The name of the field within the DBRef object can be customized via the discriminatorField option:

  • PHP
    1<?php /** @Document */ class User { // .. /** * @ReferenceMany(discriminatorField="type") */ private $favorites = array(); // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • XML
    1<reference-many fieldName="favorites"> <discriminator-field name="type" /> </reference-many>
    2
    3
  • YAML
    1referenceMany: favorites: discriminatorField: type
    2
    3

You can also specify a discriminator map to avoid storing the fully qualified class name in each DBRef object:

  • PHP
    1<?php /** @Document */ class User { // .. /** * @ReferenceMany( * discriminatorMap={ * "album"="Album", * "song"="Song" * } * ) */ private $favorites = array(); // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
  • XML
    1<reference-many fieldName="favorites"> <discriminator-map> <discriminator-mapping value="album" class="Documents\Album" /> <discriminator-mapping value="song" class="Documents\Song" /> </discriminator-map> </reference-many>
    2
    3
    4
    5
    6
  • YAML
    1referenceMany: favorites: discriminatorMap: album: Documents\Album song: Documents\Song
    2
    3
    4
    5

If you have references without a discriminator value that should be considered a certain class, you can optionally specify a default discriminator value:

  • PHP
    1<?php /** @Document */ class User { // .. /** * @ReferenceMany( * discriminatorMap={ * "album"="Album", * "song"="Song" * }, * defaultDiscriminatorValue="album" * ) */ private $favorites = array(); // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
  • XML
    1<reference-many fieldName="favorites"> <discriminator-map> <discriminator-mapping value="album" class="Documents\Album" /> <discriminator-mapping value="song" class="Documents\Song" /> </discriminator-map> <default-discriminator-value value="album" /> </reference-many>
    2
    3
    4
    5
    6
    7
  • YAML
    1referenceMany: favorites: discriminatorMap: album: Documents\Album song: Documents\Song defaultDiscriminatorValue: album
    2
    3
    4
    5
    6

Simple References

By default all references are stored as a DBRef object with the traditional $ref, $id, and $db fields (in that order). For references to documents of a single collection, storing the collection and database names for each reference may be redundant. You can use simple references to store the referenced document's identifier (e.g. MongoId) instead of a DBRef.

Example:

  • PHP
    1<?php /** * @ReferenceOne(targetDocument="Profile", simple=true) */ private $profile;
    2
    3
    4
    5
    6
  • XML
    1<reference-one target-document="Documents\Profile", simple="true" />
  • YAML
    1referenceOne: profile: simple: true
    2
    3

Now, the profile field will only store the MongoId of the referenced Profile document.

Simple references reduce the amount of storage used, both for the document itself and any indexes on the reference field; however, simple references cannot be used with discriminators, since there is no DBRef object in which to store a discriminator value.

Cascading Operations

By default, Doctrine will not cascade any UnitOfWork operations to referenced documents. You must explicitly enable this functionality:

  • PHP
    1<?php /** * @ReferenceOne(targetDocument="Profile", cascade={"persist"}) */ private $profile;
    2
    3
    4
    5
    6
  • XML
    1<reference-one target-document="Documents\Profile"> <cascade> <persist/> </cascade> </reference-one>
    2
    3
    4
    5
  • YAML
    1referenceOne: profile: cascade: [persist]
    2
    3

The valid values are:

  • all - cascade 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.