diff --git a/docs/en/reference/annotations-reference.rst b/docs/en/reference/annotations-reference.rst index 1955fffd6c..a6ff3fca09 100644 --- a/docs/en/reference/annotations-reference.rst +++ b/docs/en/reference/annotations-reference.rst @@ -1191,8 +1191,11 @@ Optional attributes: - targetDocument - A |FQCN| of the target document. - - simple - Create simple references and only store the referenced document's - identifier (e.g. ``MongoId``) instead of a `DBRef`_. Note that simple + simple - deprecated (use ``storeAs: id``) +- + storeAs - Indicates how to store the reference. ``id`` uses ``MongoId``, + ``dbRef`` uses a `DBRef`_ without ``$db`` value and ``dbRefWithDb`` stores + a full `DBRef`_ (``$ref``, ``$id``, and ``$db``). Note that ``id`` references are not compatible with the discriminators. - cascade - Cascade Option @@ -1258,8 +1261,11 @@ Optional attributes: - targetDocument - A |FQCN| of the target document. - - simple - Create simple references and only store the referenced document's - identifier (e.g. ``MongoId``) instead of a `DBRef`_. Note that simple + simple - deprecated (use ``storeAs: id``) +- + storeAs - Indicates how to store the reference. ``id`` uses ``MongoId``, + ``dbRef`` uses a `DBRef`_ without ``$db`` value and ``dbRefWithDb`` stores + a full `DBRef`_ (``$ref``, ``$id``, and ``$db``). Note that ``id`` references are not compatible with the discriminators. - cascade - Cascade Option diff --git a/docs/en/reference/complex-references.rst b/docs/en/reference/complex-references.rst index ffe96ac52e..263e5a9e36 100644 --- a/docs/en/reference/complex-references.rst +++ b/docs/en/reference/complex-references.rst @@ -7,7 +7,7 @@ the inverse side of a relationship. You can create an `immutable`_ reference to one or many documents and specify how that reference is to be loaded. The reference is immutable in that it is defined only in the mapping, unlike a typical reference where a `MongoDBRef`_ or -identifier (for :ref:`simple_references`) is stored on the document itself. +identifier (see :ref:`storing_references`) is stored on the document itself. The following options may be used for :ref:`one ` and :ref:`many ` reference mappings: diff --git a/docs/en/reference/priming-references.rst b/docs/en/reference/priming-references.rst index 9aa324bc35..391b179d5b 100644 --- a/docs/en/reference/priming-references.rst +++ b/docs/en/reference/priming-references.rst @@ -83,7 +83,7 @@ queries (one per discriminated class name). .. note:: - Priming is also compatible with :ref:`simple references ` + Priming is also compatible with :ref:`simple references ` and discriminated references. When priming discriminated references, ODM will issue one query per distinct class among the referenced document(s). diff --git a/docs/en/reference/reference-mapping.rst b/docs/en/reference/reference-mapping.rst index ef99d1088a..b9a4e4b93f 100644 --- a/docs/en/reference/reference-mapping.rst +++ b/docs/en/reference/reference-mapping.rst @@ -309,14 +309,14 @@ a certain class, you can optionally specify a default discriminator value: song: Documents\Song defaultDiscriminatorValue: album -.. _simple_references: +.. _storing_references: -Simple References ------------------ +Storing 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 +``$ref``, ``$id``, and (optionally) ``$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`_. @@ -329,19 +329,19 @@ Example: + .. code-block:: yaml referenceOne: profile: - simple: true + storeAs: id Now, the ``profile`` field will only store the ``MongoId`` of the referenced Profile document. @@ -351,6 +351,28 @@ 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. +In addition to saving references as `DBRef`_ with ``$ref``, ``$id``, and ``$db`` +fields and as ``MongoId``, it is possible to save references as `DBRef`_ without +the ``$db`` field. This solves problems when the database name changes (and also +reduces the amount of storage used). + +The ``storeAs`` option has three possible values: + +- **dbRefWithDb**: Uses a `DBRef`_ with ``$ref``, ``$id``, and ``$db`` fields (this is the default) +- **dbRef**: Uses a `DBRef`_ with ``$ref`` and ``$id`` +- **id**: Uses a ``MongoId`` + +.. note:: + + The ``storeAs=id`` option used to be called a "simple reference". The old syntax is + still recognized (so using ``simple=true`` will imply ``storeAs=id``). + +.. note:: + + For backwards compatibility ``storeAs=dbRefWithDb`` is the default, but + ``storeAs=dbRef`` is the recommended setting. + + Cascading Operations -------------------- @@ -391,6 +413,6 @@ The valid values are: - **remove** - cascade remove operation to referenced documents. - **persist** - cascade persist operation to referenced documents. -.. _`DBRef`: http://docs.mongodb.org/manual/reference/database-references/#dbref +.. _`DBRef`: http://docs.mongodb.org/manual/reference/database-references/#dbrefs .. |FQCN| raw:: html FQCN diff --git a/doctrine-mongo-mapping.xsd b/doctrine-mongo-mapping.xsd index a11b09fc1e..ca02297196 100644 --- a/doctrine-mongo-mapping.xsd +++ b/doctrine-mongo-mapping.xsd @@ -113,6 +113,14 @@ + + + + + + + + @@ -125,7 +133,8 @@ - + + @@ -145,7 +154,8 @@ - + + diff --git a/lib/Doctrine/ODM/MongoDB/DocumentManager.php b/lib/Doctrine/ODM/MongoDB/DocumentManager.php index 07a74560ed..c13a34626c 100644 --- a/lib/Doctrine/ODM/MongoDB/DocumentManager.php +++ b/lib/Doctrine/ODM/MongoDB/DocumentManager.php @@ -679,7 +679,7 @@ public function createDBRef($document, array $referenceMapping = null) ); } - if ( ! empty($referenceMapping['simple'])) { + if ($referenceMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { if ($class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) { throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']); } @@ -689,9 +689,12 @@ public function createDBRef($document, array $referenceMapping = null) $dbRef = array( '$ref' => $class->getCollection(), '$id' => $class->getDatabaseIdentifierValue($id), - '$db' => $this->getDocumentDatabase($class->name)->getName(), ); + if ($referenceMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB) { + $dbRef['$db'] = $this->getDocumentDatabase($class->name)->getName(); + } + /* If the class has a discriminator (field and value), use it. A child * class that is not defined in the discriminator map may only have a * discriminator field and no value, so default to the full class name. diff --git a/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php b/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php index 8abe5dbb94..3a0899eb07 100644 --- a/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php +++ b/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php @@ -250,7 +250,7 @@ private function generateHydratorClass(ClassMetadata $class, $hydratorClassName, /** @ReferenceOne */ if (isset(\$data['%1\$s'])) { \$reference = \$data['%1\$s']; - if (isset(\$this->class->fieldMappings['%2\$s']['simple']) && \$this->class->fieldMappings['%2\$s']['simple']) { + if (isset(\$this->class->fieldMappings['%2\$s']['storeAs']) && \$this->class->fieldMappings['%2\$s']['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { \$className = \$this->class->fieldMappings['%2\$s']['targetDocument']; \$mongoId = \$reference; } else { @@ -291,7 +291,7 @@ private function generateHydratorClass(ClassMetadata $class, $hydratorClassName, \$className = \$mapping['targetDocument']; \$targetClass = \$this->dm->getClassMetadata(\$mapping['targetDocument']); \$mappedByMapping = \$targetClass->fieldMappings[\$mapping['mappedBy']]; - \$mappedByFieldName = isset(\$mappedByMapping['simple']) && \$mappedByMapping['simple'] ? \$mapping['mappedBy'] : \$mapping['mappedBy'].'.\$id'; + \$mappedByFieldName = isset(\$mappedByMapping['storeAs']) && \$mappedByMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID ? \$mapping['mappedBy'] : \$mapping['mappedBy'].'.\$id'; \$criteria = array_merge( array(\$mappedByFieldName => \$data['_id']), isset(\$this->class->fieldMappings['%2\$s']['criteria']) ? \$this->class->fieldMappings['%2\$s']['criteria'] : array() @@ -366,6 +366,7 @@ private function generateHydratorClass(ClassMetadata $class, $hydratorClassName, use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; use Doctrine\ODM\MongoDB\Hydrator\HydratorInterface; use Doctrine\ODM\MongoDB\UnitOfWork; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; /** * THIS CLASS WAS GENERATED BY THE DOCTRINE ODM. DO NOT EDIT THIS FILE. diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceMany.php b/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceMany.php index 98a87839ae..8359f40224 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceMany.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceMany.php @@ -19,6 +19,7 @@ namespace Doctrine\ODM\MongoDB\Mapping\Annotations; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Utility\CollectionHelper; /** @@ -30,7 +31,8 @@ final class ReferenceMany extends AbstractField { public $type = 'many'; public $reference = true; - public $simple = false; + public $simple = false; // @deprecated + public $storeAs = ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB; public $targetDocument; public $discriminatorField; public $discriminatorMap; diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceOne.php b/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceOne.php index 2f4430888c..b7cc956197 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceOne.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/Annotations/ReferenceOne.php @@ -19,6 +19,8 @@ namespace Doctrine\ODM\MongoDB\Mapping\Annotations; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; + /** * Specifies a one-to-one relationship to a different document * @@ -28,7 +30,8 @@ final class ReferenceOne extends AbstractField { public $type = 'one'; public $reference = true; - public $simple = false; + public $simple = false; // @deprecated + public $storeAs = ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB; public $targetDocument; public $discriminatorField; public $discriminatorMap; diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php index 71269e3720..3c3fbddc0d 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php @@ -97,6 +97,13 @@ class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMet const MANY = 'many'; const ONE = 'one'; + /** + * The types of storeAs references + */ + const REFERENCE_STORE_AS_ID = 'id'; + const REFERENCE_STORE_AS_DB_REF = 'dbRef'; + const REFERENCE_STORE_AS_DB_REF_WITH_DB = 'dbRefWithDb'; + /* The inheritance mapping types */ /** * NONE means the class does not participate in an inheritance hierarchy @@ -1181,7 +1188,20 @@ public function mapField(array $mapping) $mapping['nullable'] = false; } - if (isset($mapping['reference']) && ! empty($mapping['simple']) && ! isset($mapping['targetDocument'])) { + // Synchronize the "simple" and "storeAs" mapping information for backwards compatibility + if (isset($mapping['simple']) && ($mapping['simple'] === true || $mapping['simple'] === 'true')) { + $mapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_ID; + } + // Remove the "simple" mapping and use "storeAs" in all further logic + if (isset($mapping['simple'])) { + unset($mapping['simple']); + } + + if (isset($mapping['reference']) + && isset($mapping['storeAs']) + && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID + && ! isset($mapping['targetDocument']) + ) { throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']); } diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php index 6e017fa015..d8cff5eaec 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php @@ -282,7 +282,8 @@ private function addReferenceMapping(ClassMetadataInfo $class, $reference, $type 'orphanRemoval' => isset($attributes['orphan-removal']) ? ('true' === (string) $attributes['orphan-removal']) : false, 'type' => $type, 'reference' => true, - 'simple' => isset($attributes['simple']) ? ('true' === (string) $attributes['simple']) : false, + 'simple' => isset($attributes['simple']) ? ('true' === (string) $attributes['simple']) : false, // deprecated + 'storeAs' => isset($attributes['store-as']) ? (string) $attributes['store-as'] : ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'targetDocument' => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null, 'name' => (string) $attributes['field'], 'strategy' => isset($attributes['strategy']) ? (string) $attributes['strategy'] : $defaultStrategy, diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php index 8792e854fb..eadc82e965 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php @@ -264,7 +264,8 @@ private function addMappingFromReference(ClassMetadataInfo $class, $fieldName, $ 'orphanRemoval' => isset($reference['orphanRemoval']) ? $reference['orphanRemoval'] : false, 'type' => $type, 'reference' => true, - 'simple' => isset($reference['simple']) ? (boolean) $reference['simple'] : false, + 'simple' => isset($reference['simple']) ? (boolean) $reference['simple'] : false, // deprecated + 'storeAs' => isset($reference['storeAs']) ? (string) $reference['storeAs'] : ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'targetDocument' => isset($reference['targetDocument']) ? $reference['targetDocument'] : null, 'fieldName' => $fieldName, 'strategy' => isset($reference['strategy']) ? (string) $reference['strategy'] : $defaultStrategy, diff --git a/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php b/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php index af4230ef81..b09e49ab7c 100644 --- a/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php +++ b/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php @@ -24,6 +24,7 @@ use Doctrine\MongoDB\CursorInterface; use Doctrine\ODM\MongoDB\Cursor; use Doctrine\ODM\MongoDB\DocumentManager; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Utility\CollectionHelper; use Doctrine\ODM\MongoDB\Hydrator\HydratorFactory; use Doctrine\ODM\MongoDB\LockException; @@ -666,7 +667,7 @@ private function loadReferenceManyCollectionOwningSide(PersistentCollectionInter $sorted = isset($mapping['sort']) && $mapping['sort']; foreach ($collection->getMongoData() as $key => $reference) { - if (isset($mapping['simple']) && $mapping['simple']) { + if (isset($mapping['storeAs']) && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { $className = $mapping['targetDocument']; $mongoId = $reference; } else { @@ -752,7 +753,7 @@ public function createReferenceManyInverseSideQuery(PersistentCollectionInterfac $ownerClass = $this->dm->getClassMetadata(get_class($owner)); $targetClass = $this->dm->getClassMetadata($mapping['targetDocument']); $mappedByMapping = isset($targetClass->fieldMappings[$mapping['mappedBy']]) ? $targetClass->fieldMappings[$mapping['mappedBy']] : array(); - $mappedByFieldName = isset($mappedByMapping['simple']) && $mappedByMapping['simple'] ? $mapping['mappedBy'] : $mapping['mappedBy'] . '.$id'; + $mappedByFieldName = isset($mappedByMapping['storeAs']) && $mappedByMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID ? $mapping['mappedBy'] : $mapping['mappedBy'] . '.$id'; $criteria = $this->cm->merge( array($mappedByFieldName => $ownerClass->getIdentifierObject($owner)), $this->dm->getFilterCollection()->getFilterCriteria($targetClass), @@ -994,7 +995,7 @@ private function prepareQueryElement($fieldName, $value = null, $class = null, $ // No further preparation unless we're dealing with a simple reference // We can't have expressions in empty() with PHP < 5.5, so store it in a variable $arrayValue = (array) $value; - if (empty($mapping['reference']) || empty($mapping['simple']) || empty($arrayValue)) { + if (empty($mapping['reference']) || $mapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID || empty($arrayValue)) { return array($fieldName, $value); } @@ -1106,7 +1107,7 @@ private function prepareQueryElement($fieldName, $value = null, $class = null, $ $objectPropertyIsId = $targetClass->isIdentifier($objectProperty); // Prepare DBRef identifiers or the mapped field's property path - $fieldName = ($objectPropertyIsId && ! empty($mapping['reference']) && empty($mapping['simple'])) + $fieldName = ($objectPropertyIsId && ! empty($mapping['reference']) && $mapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) ? $e[0] . '.$id' : $e[0] . '.' . $objectPropertyPrefix . $targetMapping['name']; diff --git a/lib/Doctrine/ODM/MongoDB/Query/Expr.php b/lib/Doctrine/ODM/MongoDB/Query/Expr.php index d4ec5d9dd3..2ac2d59ff3 100644 --- a/lib/Doctrine/ODM/MongoDB/Query/Expr.php +++ b/lib/Doctrine/ODM/MongoDB/Query/Expr.php @@ -21,6 +21,7 @@ use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Mapping\MappingException; /** @@ -73,12 +74,17 @@ public function references($document) if ($this->currentField) { $mapping = $this->getReferenceMapping(); $dbRef = $this->dm->createDBRef($document, $mapping); + $storeAs = array_key_exists('storeAs', $mapping) ? $mapping['storeAs'] : null; - if (isset($mapping['simple']) && $mapping['simple']) { + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { $this->query[$mapping['name']] = $dbRef; } else { $keys = array('ref' => true, 'id' => true, 'db' => true); + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { + unset($keys['db']); + } + if (isset($mapping['targetDocument'])) { unset($keys['ref'], $keys['db']); } @@ -106,12 +112,17 @@ public function includesReferenceTo($document) if ($this->currentField) { $mapping = $this->getReferenceMapping(); $dbRef = $this->dm->createDBRef($document, $mapping); + $storeAs = array_key_exists('storeAs', $mapping) ? $mapping['storeAs'] : null; - if (isset($mapping['simple']) && $mapping['simple']) { + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { $this->query[$mapping['name']] = $dbRef; } else { $keys = array('ref' => true, 'id' => true, 'db' => true); + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { + unset($keys['db']); + } + if (isset($mapping['targetDocument'])) { unset($keys['ref'], $keys['db']); } diff --git a/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php b/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php index d2bddc5c6b..66be4bda48 100644 --- a/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php +++ b/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php @@ -20,9 +20,11 @@ namespace Doctrine\ODM\MongoDB\Query; use Doctrine\ODM\MongoDB\DocumentManager; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; +use Doctrine\ODM\MongoDB\PersistentCollection; use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface; use Doctrine\ODM\MongoDB\Proxy\Proxy; -use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; use Doctrine\ODM\MongoDB\UnitOfWork; /** @@ -124,7 +126,7 @@ public function primeReferences(ClassMetadata $class, $documents, $fieldName, ar /* Simple reference require a target document class so we can construct * the priming query. */ - if ( ! empty($mapping['simple']) && empty($mapping['targetDocument'])) { + if ($mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID && empty($mapping['targetDocument'])) { throw new \LogicException(sprintf('Field "%s" is a simple reference without a target document class in class "%s"', $fieldName, $class->name)); } @@ -253,13 +255,13 @@ private function addManyReferences(PersistentCollectionInterface $persistentColl { $mapping = $persistentCollection->getMapping(); - if ( ! empty($mapping['simple'])) { + if ($mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { $className = $mapping['targetDocument']; $class = $this->dm->getClassMetadata($className); } foreach ($persistentCollection->getMongoData() as $reference) { - if ( ! empty($mapping['simple'])) { + if ($mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { $id = $reference; } else { $id = $reference['$id']; diff --git a/lib/Doctrine/ODM/MongoDB/SchemaManager.php b/lib/Doctrine/ODM/MongoDB/SchemaManager.php index df4b65b2d2..29577d4c85 100644 --- a/lib/Doctrine/ODM/MongoDB/SchemaManager.php +++ b/lib/Doctrine/ODM/MongoDB/SchemaManager.php @@ -21,6 +21,7 @@ use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; class SchemaManager { @@ -192,7 +193,9 @@ private function doGetDocumentIndexes($documentName, array &$visited) $newKeys = array(); foreach ($index['keys'] as $key => $v) { if ($key == $fieldMapping['name']) { - $key = $fieldMapping['simple'] ? $key : $key . '.$id'; + $key = $fieldMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID + ? $key + : $key . '.$id'; } $newKeys[$key] = $v; } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php b/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php index a2dbb8a946..bef16f1e26 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php @@ -206,6 +206,28 @@ public function testDisriminatedSimpleReferenceFails() $this->dm->createDBRef($r, $class->associationMappings['ref']); } + public function testDifferentStoreAsDbReferences() + { + $r = new \Documents\User(); + $this->dm->persist($r); + $d = new ReferenceStoreAsDocument(); + $class = $this->dm->getClassMetadata(get_class($d)); + + $dbRef = $this->dm->createDBRef($r, $class->associationMappings['ref1']); + $this->assertInstanceOf('MongoId', $dbRef); + + $dbRef = $this->dm->createDBRef($r, $class->associationMappings['ref2']); + $this->assertCount(2, $dbRef); + $this->assertArrayHasKey('$ref', $dbRef); + $this->assertArrayHasKey('$id', $dbRef); + + $dbRef = $this->dm->createDBRef($r, $class->associationMappings['ref3']); + $this->assertCount(3, $dbRef); + $this->assertArrayHasKey('$ref', $dbRef); + $this->assertArrayHasKey('$id', $dbRef); + $this->assertArrayHasKey('$db', $dbRef); + } + private function getMockClassMetadataFactory() { return $this->getMockBuilder('Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory') @@ -230,3 +252,19 @@ class WrongSimpleRefDocument /** @ODM\ReferenceOne(targetDocument="Documents\Tournament\Participant", simple=true) */ public $ref; } + +/** @ODM\Document */ +class ReferenceStoreAsDocument +{ + /** @ODM\Id */ + public $id; + + /** @ODM\ReferenceOne(targetDocument="Documents\User", storeAs="id") */ + public $ref1; + + /** @ODM\ReferenceOne(targetDocument="Documents\User", storeAs="dbRef") */ + public $ref2; + + /** @ODM\ReferenceOne(targetDocument="Documents\User", storeAs="dbRefWithDb") */ + public $ref3; +} diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php index f57d2d36bd..6df6871f34 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php @@ -368,10 +368,13 @@ class DocumentPersisterTestDocument */ public $association; - /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument", simple=true) */ + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument", storeAs="id") */ public $simpleRef; - /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument") */ + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument", storeAs="dbRef") */ + public $semiComplexRef; + + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument", storeAs="dbRefWithDb") */ public $complexRef; } @@ -433,9 +436,12 @@ class DocumentPersisterTestHashIdDocument /** @ODM\Id(strategy="none", options={"type"="hash"}) */ public $id; - /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument", simple=true) */ + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument", storeAs="id") */ public $simpleRef; - /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument") */ + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument", storeAs="dbRef") */ + public $semiComplexRef; + + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument", storeAs="dbRefWithDb") */ public $complexRef; } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php index 195734a465..58aa025fa1 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php @@ -12,6 +12,7 @@ use Documents\GuestServer; use Documents\Phonenumber; use Documents\Project; +use Documents\ReferenceUser; use Documents\SimpleReferenceUser; use Documents\User; use Documents\Ecommerce\ConfigurableProduct; @@ -165,6 +166,83 @@ public function testPrimeReferencesWithSimpleReferences() } } + public function testPrimeReferencesWithDifferentStoreAsReferences() + { + $referenceUser = new ReferenceUser(); + $this->dm->persist($referenceUser); + + $user1 = new User(); + $this->dm->persist($user1); + $referenceUser->setUser($user1); + + $user2 = new User(); + $this->dm->persist($user2); + $referenceUser->addUser($user2); + + $parentUser1 = new User(); + $this->dm->persist($parentUser1); + $referenceUser->setParentUser($parentUser1); + + $parentUser2 = new User(); + $this->dm->persist($parentUser2); + $referenceUser->addParentUser($parentUser2); + + $otherUser1 = new User(); + $this->dm->persist($otherUser1); + $referenceUser->setOtherUser($otherUser1); + + $otherUser2 = new User(); + $this->dm->persist($otherUser2); + $referenceUser->addOtherUser($otherUser2); + + $this->dm->flush(); + $this->dm->clear(); + + $qb = $this->dm->createQueryBuilder('Documents\ReferenceUser') + ->field('user')->prime(true) + ->field('users')->prime(true) + ->field('parentUser')->prime(true) + ->field('parentUsers')->prime(true) + ->field('otherUser')->prime(true) + ->field('otherUsers')->prime(true); + + /** @var ReferenceUser $referenceUser */ + foreach ($qb->getQuery() as $referenceUser) { + // storeAs=id reference + $this->assertInstanceOf('Doctrine\ODM\MongoDB\Proxy\Proxy', $referenceUser->getUser()); + $this->assertTrue($referenceUser->getUser()->__isInitialized()); + + $this->assertCount(1, $referenceUser->getUsers()); + + foreach ($referenceUser->getUsers() as $user) { + $this->assertNotInstanceOf('Doctrine\ODM\MongoDB\Proxy\Proxy', $user); + $this->assertInstanceOf('Documents\User', $user); + } + + // storeAs=dbRef reference + $this->assertInstanceOf('Doctrine\ODM\MongoDB\Proxy\Proxy', $referenceUser->getParentUser()); + $this->assertTrue($referenceUser->getParentUser()->__isInitialized()); + + $this->assertCount(1, $referenceUser->getParentUsers()); + + foreach ($referenceUser->getParentUsers() as $user) { + $this->assertNotInstanceOf('Doctrine\ODM\MongoDB\Proxy\Proxy', $user); + $this->assertInstanceOf('Documents\User', $user); + } + + // storeAs=dbRefWithDb reference + $this->assertInstanceOf('Doctrine\ODM\MongoDB\Proxy\Proxy', $referenceUser->getOtherUser()); + $this->assertTrue($referenceUser->getOtherUser()->__isInitialized()); + + $this->assertCount(1, $referenceUser->getOtherUsers()); + + foreach ($referenceUser->getOtherUsers() as $user) { + $this->assertNotInstanceOf('Doctrine\ODM\MongoDB\Proxy\Proxy', $user); + $this->assertInstanceOf('Documents\User', $user); + } + } + } + public function testPrimeReferencesWithDiscriminatedReferenceMany() { $group = new Group(); diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/ClassMetadataInfoTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/ClassMetadataInfoTest.php index 18bd78f769..05122a8f41 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/ClassMetadataInfoTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/ClassMetadataInfoTest.php @@ -234,6 +234,38 @@ public function testSimpleReferenceRequiresTargetDocument() 'simple' => true, )); } + + /** + * @expectedException \Doctrine\ODM\MongoDB\Mapping\MappingException + * @expectedExceptionMessage Target document must be specified for simple reference: stdClass::assoc + */ + public function testSimpleAsStringReferenceRequiresTargetDocument() + { + $cm = new ClassMetadataInfo('stdClass'); + + $cm->mapField(array( + 'fieldName' => 'assoc', + 'reference' => true, + 'type' => 'one', + 'simple' => 'true', + )); + } + + /** + * @expectedException \Doctrine\ODM\MongoDB\Mapping\MappingException + * @expectedExceptionMessage Target document must be specified for simple reference: stdClass::assoc + */ + public function testStoreAsIdReferenceRequiresTargetDocument() + { + $cm = new ClassMetadataInfo('stdClass'); + + $cm->mapField(array( + 'fieldName' => 'assoc', + 'reference' => true, + 'type' => 'one', + 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_ID, + )); + } /** * @expectedException \Doctrine\ODM\MongoDB\Mapping\MappingException diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php index 694db8e2ae..a1ad13b4e7 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php @@ -141,7 +141,7 @@ public function testDriver() 'name' => 'profile', 'type' => 'one', 'reference' => true, - 'simple' => true, + 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_ID, 'targetDocument' => 'Documents\Profile', 'cascade' => array('remove', 'persist', 'refresh', 'merge', 'detach'), 'isCascadeDetach' => true, @@ -167,7 +167,7 @@ public function testDriver() 'name' => 'account', 'type' => 'one', 'reference' => true, - 'simple' => false, + 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'targetDocument' => 'Documents\Account', 'cascade' => array('remove', 'persist', 'refresh', 'merge', 'detach'), 'isCascadeDetach' => true, @@ -193,7 +193,7 @@ public function testDriver() 'name' => 'groups', 'type' => 'many', 'reference' => true, - 'simple' => false, + 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'targetDocument' => 'Documents\Group', 'cascade' => array('remove', 'persist', 'refresh', 'merge', 'detach'), 'isCascadeDetach' => true, diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/XmlDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/XmlDriverTest.php index 51db3c798e..7453e77dee 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/XmlDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/XmlDriverTest.php @@ -2,6 +2,7 @@ namespace Doctrine\ODM\MongoDB\Tests\Mapping\Driver; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Mapping\Driver\XmlDriver; use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; @@ -46,11 +47,11 @@ public function testDriverShouldParseNonStringAttributes() $this->assertSame(false, $classMetadata->slaveOkay); $profileMapping = $classMetadata->fieldMappings['profile']; - $this->assertSame(true, $profileMapping['simple']); + $this->assertSame(ClassMetadataInfo::REFERENCE_STORE_AS_ID, $profileMapping['storeAs']); $this->assertSame(true, $profileMapping['orphanRemoval']); $profileMapping = $classMetadata->fieldMappings['groups']; - $this->assertSame(false, $profileMapping['simple']); + $this->assertSame(ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, $profileMapping['storeAs']); $this->assertSame(false, $profileMapping['orphanRemoval']); $this->assertSame(0, $profileMapping['limit']); $this->assertSame(2, $profileMapping['skip']); diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php index ccc5d70c60..c351682e25 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php @@ -25,7 +25,7 @@ public function testAlternateRelationshipMappingSyntaxShouldSetDefaults() $mappingDriver->loadMetadataForClass($className, $class); foreach (array('address', 'phonenumbers') as $referencedField) { - foreach (array('inversedBy', 'limit', 'mappedBy', 'repositoryMethod', 'simple', 'skip', 'strategy', 'targetDocument') as $key) { + foreach (array('inversedBy', 'limit', 'mappedBy', 'repositoryMethod', 'storeAs', 'skip', 'strategy', 'targetDocument') as $key) { $this->assertArrayHasKey($key, $class->fieldMappings[$referencedField]); } } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php index 5bd9b13e80..5c7d0a6b82 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php @@ -32,6 +32,18 @@ public function testReferencesGoesThroughDiscriminatorMap() ->getQuery()->debug(); $this->assertEquals([ 'featureSimple' => new \MongoId($f->id) ], $q2['query']); + + $q3 = $this->dm->createQueryBuilder(ParentClass::class) + ->field('featurePartial')->references($f) + ->getQuery()->debug(); + + $this->assertEquals( + [ + 'featurePartial.$id' => new \MongoId($f->id), + 'featurePartial.$ref' => 'Feature', + ], + $q3['query'] + ); } /** @@ -77,7 +89,23 @@ public function testIncludesReferenceToGoesThroughDiscriminatorMap() ->field('featureSimpleMany')->includesReferenceTo($f) ->getQuery()->debug(); - $this->assertEquals([ 'featureSimpleMany' => [ '$elemMatch' => new \MongoId($f->id) ] ], $q2['query']); + $this->assertEquals([ 'featureSimpleMany' => new \MongoId($f->id) ], $q2['query']); + + $q3 = $this->dm->createQueryBuilder(ParentClass::class) + ->field('featurePartialMany')->includesReferenceTo($f) + ->getQuery()->debug(); + + $this->assertEquals( + [ + 'featurePartialMany' => [ + '$elemMatch' => [ + '$id' => new \MongoId($f->id), + '$ref' => 'Feature', + ] + ] + ], + $q3['query'] + ); } /** @@ -113,7 +141,7 @@ public function testIncludesReferenceToThrowsSpecializedExceptionForConflictingM * @ODM\Document * @ODM\InheritanceType("SINGLE_COLLECTION") * @ODM\DiscriminatorField(fieldName="type") - * @ODM\DiscriminatorMap({"ca"="ChildA", "cb"="ChildB"}) + * @ODM\DiscriminatorMap({"ca"="ChildA", "cb"="ChildB", "cc"="ChildC"}) */ class ParentClass { @@ -156,3 +184,15 @@ class ChildB extends ParentClass /** @ODM\ReferenceMany(targetDocument="Documents\Feature", simple=true) */ public $conflictMany; } + +/** + * @ODM\Document + */ +class ChildC extends ParentClass +{ + /** @ODM\ReferenceOne(storeAs="dbRef") */ + public $featurePartial; + + /** @ODM\ReferenceMany(storeAs="dbRef") */ + public $featurePartialMany; +} diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php index a76b2e2ee7..1afdbedfb2 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php @@ -2,6 +2,7 @@ namespace Doctrine\ODM\MongoDB\Tests\Query; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Query\Expr; class ExprTest extends \Doctrine\ODM\MongoDB\Tests\BaseTest @@ -262,4 +263,45 @@ public function testReferencesUsesAllKeys() $this->assertEquals($expected, $expr->getQuery(), '->references() uses all keys if no targetDocument is set'); } -} \ No newline at end of file + + public function testReferencesUsesSomeKeys() + { + $dm = $this->getMockBuilder('Doctrine\\ODM\\MongoDB\\DocumentManager') + ->disableOriginalConstructor() + ->getMock(); + $uw = $this->getMockBuilder('Doctrine\ODM\MongoDB\UnitOfWork') + ->disableOriginalConstructor() + ->getMock(); + $documentPersister = $this->getMockBuilder('Doctrine\ODM\MongoDB\Persisters\DocumentPersister') + ->disableOriginalConstructor() + ->getMock(); + $class = $this->getMockBuilder('Doctrine\\ODM\\MongoDB\\Mapping\\ClassMetadata') + ->disableOriginalConstructor() + ->getMock(); + + $expected = array('foo.$ref' => 'coll', 'foo.$id' => '1234'); + + $dm->expects($this->once()) + ->method('createDBRef') + ->will($this->returnValue(array('$ref' => 'coll', '$id' => '1234'))); + $dm->expects($this->once()) + ->method('getUnitOfWork') + ->will($this->returnValue($uw)); + $uw->expects($this->once()) + ->method('getDocumentPersister') + ->will($this->returnValue($documentPersister)); + $documentPersister->expects($this->once()) + ->method('prepareQueryOrNewObj') + ->with($expected) + ->will($this->returnValue($expected)); + $class->expects($this->once()) + ->method('getFieldMapping') + ->will($this->returnValue(array('storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF))); + + $expr = new Expr($dm); + $expr->setClassMetadata($class); + $expr->field('foo')->references(new \stdClass()); + + $this->assertEquals($expected, $expr->getQuery(), '->references() uses some keys if storeAs=dbRef is set'); + } +} diff --git a/tests/Doctrine/ODM/MongoDB/Tests/QueryTest.php b/tests/Doctrine/ODM/MongoDB/Tests/QueryTest.php index 3d5d77cdde..b958ecfc32 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/QueryTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/QueryTest.php @@ -73,7 +73,7 @@ public function testReferences() $this->assertSame($kris, $query->getSingleResult()); } - public function testReferencesSimple() + public function testReferencesStoreAsId() { $kris = new Person('Kris'); $jon = new Person('Jon'); @@ -99,6 +99,33 @@ public function testReferencesSimple() $this->assertSame($kris, $query->getSingleResult()); } + public function testReferencesStoreAsDbRef() + { + $kris = new Person('Kris'); + $jon = new Person('Jon'); + + $this->dm->persist($kris); + $this->dm->persist($jon); + $this->dm->flush(); + + $kris->bestFriendPartial = $jon; + $this->dm->flush(); + + $qb = $this->dm->createQueryBuilder(__NAMESPACE__.'\Person'); + $qb->field('bestFriendPartial')->references($jon); + + $queryArray = $qb->getQueryArray(); + $this->assertEquals(array( + 'bestFriendPartial.$ref' => 'people', + 'bestFriendPartial.$id' => new \MongoId($jon->id), + ), $queryArray); + + $query = $qb->getQuery(); + + $this->assertEquals(1, $query->count()); + $this->assertSame($kris, $query->getSingleResult()); + } + public function testIncludesReferenceTo() { $kris = new Person('Kris'); @@ -131,7 +158,7 @@ public function testIncludesReferenceTo() $this->assertSame($jon, $query->getSingleResult()); } - public function testIncludesReferenceToSimple() + public function testIncludesReferenceToWithStoreAsId() { $kris = new Person('Kris'); $jon = new Person('Jon'); @@ -160,6 +187,37 @@ public function testIncludesReferenceToSimple() $this->assertSame($jon, $query->getSingleResult()); } + public function testIncludesReferenceToWithStoreAsDbRef() + { + $kris = new Person('Kris'); + $jon = new Person('Jon'); + + $this->dm->persist($kris); + $this->dm->persist($jon); + $this->dm->flush(); + + $jon->friendsPartial[] = $kris; + $this->dm->flush(); + + $qb = $this->dm->createQueryBuilder(__NAMESPACE__.'\Person'); + $qb->field('friendsPartial')->includesReferenceTo($kris); + + $queryArray = $qb->getQueryArray(); + $this->assertEquals(array( + 'friendsPartial' => array( + '$elemMatch' => array( + '$ref' => 'people', + '$id' => new \MongoId($kris->id) + ), + ), + ), $queryArray); + + $query = $qb->getQuery(); + + $this->assertEquals(1, $query->count()); + $this->assertSame($jon, $query->getSingleResult()); + } + public function testQueryIdIn() { $user = new \Documents\User(); @@ -306,15 +364,21 @@ class Person /** @ODM\ReferenceOne */ public $bestFriend; - /** @ODM\ReferenceOne(simple=true, targetDocument="Doctrine\ODM\MongoDB\Tests\Person") */ + /** @ODM\ReferenceOne(storeAs="id", targetDocument="Doctrine\ODM\MongoDB\Tests\Person") */ public $bestFriendSimple; + /** @ODM\ReferenceOne(storeAs="dbRef") */ + public $bestFriendPartial; + /** @ODM\ReferenceMany */ public $friends = array(); - /** @ODM\ReferenceMany(simple=true, targetDocument="Doctrine\ODM\MongoDB\Tests\Person") */ + /** @ODM\ReferenceMany(storeAs="id", targetDocument="Doctrine\ODM\MongoDB\Tests\Person") */ public $friendsSimple = array(); + /** @ODM\ReferenceMany(storeAs="dbRef") */ + public $friendsPartial = array(); + public function __construct($firstName) { $this->firstName = $firstName; diff --git a/tests/Documents/ReferenceUser.php b/tests/Documents/ReferenceUser.php new file mode 100644 index 0000000000..51542bd6bd --- /dev/null +++ b/tests/Documents/ReferenceUser.php @@ -0,0 +1,171 @@ +user = $user; + } + + /** + * @return User + */ + public function getUser() + { + return $this->user; + } + + /** + * @param User $user + */ + public function addUser(User $user) + { + $this->users[] = $user; + } + + /** + * @return User[] + */ + public function getUsers() + { + return $this->users; + } + + /** + * @param User $parentUser + */ + public function setParentUser(User $parentUser) + { + $this->parentUser = $parentUser; + } + + /** + * @return User + */ + public function getParentUser() + { + return $this->parentUser; + } + + /** + * @param User $parentUser + */ + public function addParentUser(User $parentUser) + { + $this->parentUsers[] = $parentUser; + } + + /** + * @return User[] + */ + public function getParentUsers() + { + return $this->parentUsers; + } + + /** + * @param User $otherUser + */ + public function setOtherUser(User $otherUser) + { + $this->otherUser = $otherUser; + } + + /** + * @return User + */ + public function getOtherUser() + { + return $this->otherUser; + } + + /** + * @param User $otherUser + */ + public function addOtherUser(User $otherUser) + { + $this->otherUsers[] = $otherUser; + } + + /** + * @return User[] + */ + public function getOtherUsers() + { + return $this->otherUsers; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } +}