diff --git a/docs/en/reference/annotations-reference.rst b/docs/en/reference/annotations-reference.rst index 1fcf4b3f69..9db3efae6d 100644 --- a/docs/en/reference/annotations-reference.rst +++ b/docs/en/reference/annotations-reference.rst @@ -1218,24 +1218,26 @@ documents. Optional attributes: - - targetDocument - A |FQCN| of the target document. + targetDocument - A |FQCN| of the target document. A ``targetDocument`` is + required when using ``storeAs: id``. - 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. + storeAs - Indicates how to store the reference. ``id`` stores the identifier, + ``ref`` an embedded object containing the ``id`` field and (optionally) a + discriminator. ``dbRef`` and ``dbRefWithDb`` store a `DBRef`_ object and + are deprecated in favor of ``ref``. Note that ``id`` references are not + compatible with the discriminators. - cascade - Cascade Option - discriminatorField - The field name to store the discriminator value within - the `DBRef`_ object. + the reference object. - discriminatorMap - Map of discriminator values to class names. - defaultDiscriminatorValue - A default value for discriminatorField if no value - has been set in the embedded document. + has been set in the referenced document. - inversedBy - The field name of the inverse side. Only allowed on owning side. - @@ -1292,24 +1294,26 @@ Defines an instance variable holds a related document instance. Optional attributes: - - targetDocument - A |FQCN| of the target document. + targetDocument - A |FQCN| of the target document. A ``targetDocument`` is + required when using ``storeAs: id``. - 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. + storeAs - Indicates how to store the reference. ``id`` stores the identifier, + ``ref`` an embedded object containing the ``id`` field and (optionally) a + discriminator. ``dbRef`` and ``dbRefWithDb`` store a `DBRef`_ object and + are deprecated in favor of ``ref``. Note that ``id`` references are not + compatible with the discriminators. - cascade - Cascade Option - discriminatorField - The field name to store the discriminator value within - the `DBRef`_ object. + the reference object. - discriminatorMap - Map of discriminator values to class names. - defaultDiscriminatorValue - A default value for discriminatorField if no value - has been set in the embedded document. + has been set in the referenced document. - inversedBy - The field name of the inverse side. Only allowed on owning side. - diff --git a/docs/en/reference/reference-mapping.rst b/docs/en/reference/reference-mapping.rst index dadfb93cd0..285309aca2 100644 --- a/docs/en/reference/reference-mapping.rst +++ b/docs/en/reference/reference-mapping.rst @@ -356,11 +356,12 @@ 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: +The ``storeAs`` option has the following 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`` +- **ref**: Uses a custom embedded object with an ``id`` field +- **id**: Uses the identifier of the referenced object .. note:: diff --git a/doctrine-mongo-mapping.xsd b/doctrine-mongo-mapping.xsd index 1abd97dffc..a4b109c764 100644 --- a/doctrine-mongo-mapping.xsd +++ b/doctrine-mongo-mapping.xsd @@ -124,6 +124,7 @@ + diff --git a/lib/Doctrine/ODM/MongoDB/Aggregation/Stage/Lookup.php b/lib/Doctrine/ODM/MongoDB/Aggregation/Stage/Lookup.php index d603315933..552a3cf406 100644 --- a/lib/Doctrine/ODM/MongoDB/Aggregation/Stage/Lookup.php +++ b/lib/Doctrine/ODM/MongoDB/Aggregation/Stage/Lookup.php @@ -96,26 +96,38 @@ private function fromReference($fieldName) parent::from($targetMapping->getCollection()); if ($referenceMapping['isOwningSide']) { - if ($referenceMapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - throw MappingException::cannotLookupNonIdReference($this->class->name, $fieldName); + switch ($referenceMapping['storeAs']) { + case ClassMetadataInfo::REFERENCE_STORE_AS_ID: + case ClassMetadataInfo::REFERENCE_STORE_AS_REF: + $referencedFieldName = ClassMetadataInfo::getReferenceFieldName($referenceMapping['storeAs'], $referenceMapping['name']); + break; + + default: + throw MappingException::cannotLookupNonIdReference($this->class->name, $fieldName); } $this ->foreignField('_id') - ->localField($referenceMapping['name']); + ->localField($referencedFieldName); } else { if (isset($referenceMapping['repositoryMethod'])) { throw MappingException::repositoryMethodLookupNotAllowed($this->class->name, $fieldName); } $mappedByMapping = $targetMapping->getFieldMapping($referenceMapping['mappedBy']); - if ($mappedByMapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - throw MappingException::cannotLookupNonIdReference($this->class->name, $fieldName); + switch ($mappedByMapping['storeAs']) { + case ClassMetadataInfo::REFERENCE_STORE_AS_ID: + case ClassMetadataInfo::REFERENCE_STORE_AS_REF: + $referencedFieldName = ClassMetadataInfo::getReferenceFieldName($mappedByMapping['storeAs'], $mappedByMapping['name']); + break; + + default: + throw MappingException::cannotLookupNonIdReference($this->class->name, $fieldName); } $this ->localField('_id') - ->foreignField($mappedByMapping['name']); + ->foreignField($referencedFieldName); } return $this; diff --git a/lib/Doctrine/ODM/MongoDB/DocumentManager.php b/lib/Doctrine/ODM/MongoDB/DocumentManager.php index b1f5f417cb..da07e1a64b 100644 --- a/lib/Doctrine/ODM/MongoDB/DocumentManager.php +++ b/lib/Doctrine/ODM/MongoDB/DocumentManager.php @@ -668,15 +668,15 @@ public function getConfiguration() } /** - * Returns a DBRef array for the supplied document. + * Returns a reference to the supplied document. * - * @param mixed $document A document object + * @param object $document A document object * @param array $referenceMapping Mapping for the field that references the document * * @throws \InvalidArgumentException - * @return array A DBRef array + * @return mixed The reference for the document in question, according to the desired mapping */ - public function createDBRef($document, array $referenceMapping = null) + public function createReference($document, array $referenceMapping) { if ( ! is_object($document)) { throw new \InvalidArgumentException('Cannot create a DBRef, the document is not an object'); @@ -691,20 +691,38 @@ public function createDBRef($document, array $referenceMapping = null) ); } - if ($referenceMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - if ($class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) { - throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']); - } - return $class->getDatabaseIdentifierValue($id); - } - - $dbRef = array( - '$ref' => $class->getCollection(), - '$id' => $class->getDatabaseIdentifierValue($id), - ); - - if ($referenceMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB) { - $dbRef['$db'] = $this->getDocumentDatabase($class->name)->getName(); + $storeAs = isset($referenceMapping['storeAs']) ? $referenceMapping['storeAs'] : null; + switch ($storeAs) { + case ClassMetadataInfo::REFERENCE_STORE_AS_ID: + if ($class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) { + throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']); + } + + return $class->getDatabaseIdentifierValue($id); + break; + + + case ClassMetadataInfo::REFERENCE_STORE_AS_REF: + $reference = ['id' => $class->getDatabaseIdentifierValue($id)]; + break; + + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF: + $reference = [ + '$ref' => $class->getCollection(), + '$id' => $class->getDatabaseIdentifierValue($id), + ]; + break; + + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB: + $reference = [ + '$ref' => $class->getCollection(), + '$id' => $class->getDatabaseIdentifierValue($id), + '$db' => $this->getDocumentDatabase($class->name)->getName(), + ]; + break; + + default: + throw new \InvalidArgumentException("Reference type {$storeAs} is invalid."); } /* If the class has a discriminator (field and value), use it. A child @@ -712,7 +730,7 @@ public function createDBRef($document, array $referenceMapping = null) * discriminator field and no value, so default to the full class name. */ if (isset($class->discriminatorField)) { - $dbRef[$class->discriminatorField] = isset($class->discriminatorValue) + $reference[$class->discriminatorField] = isset($class->discriminatorValue) ? $class->discriminatorValue : $class->name; } @@ -720,7 +738,7 @@ public function createDBRef($document, array $referenceMapping = null) /* Add a discriminator value if the referenced document is not mapped * explicitly to a targetDocument class. */ - if ($referenceMapping !== null && ! isset($referenceMapping['targetDocument'])) { + if (! isset($referenceMapping['targetDocument'])) { $discriminatorField = $referenceMapping['discriminatorField']; $discriminatorValue = isset($referenceMapping['discriminatorMap']) ? array_search($class->name, $referenceMapping['discriminatorMap']) @@ -736,10 +754,31 @@ public function createDBRef($document, array $referenceMapping = null) $discriminatorValue = $class->name; } - $dbRef[$discriminatorField] = $discriminatorValue; + $reference[$discriminatorField] = $discriminatorValue; + } + + return $reference; + } + + /** + * Returns a DBRef array for the supplied document. + * + * @param mixed $document A document object + * @param array $referenceMapping Mapping for the field that references the document + * + * @throws \InvalidArgumentException + * @return array A DBRef array + * @deprecated Deprecated in favor of createReference; will be removed in 2.0 + */ + public function createDBRef($document, array $referenceMapping = null) + { + @trigger_error('The ' . __METHOD__ . ' method has been deprecated and will be removed in ODM 2.0. Use createReference() instead.', E_USER_DEPRECATED); + + if (!isset($referenceMapping['storeAs'])) { + $referenceMapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF; } - return $dbRef; + return $this->createReference($document, $referenceMapping); } /** diff --git a/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php b/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php index cfc4842ee2..c8f9e6a1ea 100644 --- a/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php +++ b/lib/Doctrine/ODM/MongoDB/Hydrator/HydratorFactory.php @@ -255,13 +255,8 @@ private function generateHydratorClass(ClassMetadata $class, $hydratorClassName, /** @ReferenceOne */ if (isset(\$data['%1\$s'])) { \$reference = \$data['%1\$s']; - 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 { - \$className = \$this->unitOfWork->getClassNameForAssociation(\$this->class->fieldMappings['%2\$s'], \$reference); - \$mongoId = \$reference['\$id']; - } + \$className = \$this->unitOfWork->getClassNameForAssociation(\$this->class->fieldMappings['%2\$s'], \$reference); + \$mongoId = ClassMetadataInfo::getReferenceId(\$reference, \$this->class->fieldMappings['%2\$s']['storeAs']); \$targetMetadata = \$this->dm->getClassMetadata(\$className); \$id = \$targetMetadata->getPHPIdentifierValue(\$mongoId); \$return = \$this->dm->getReference(\$className, \$id); @@ -296,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['storeAs']) && \$mappedByMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID ? \$mapping['mappedBy'] : \$mapping['mappedBy'].'.\$id'; + \$mappedByFieldName = ClassMetadataInfo::getReferenceFieldName(\$mappedByMapping['storeAs'], \$mapping['mappedBy']); \$criteria = array_merge( array(\$mappedByFieldName => \$data['_id']), isset(\$this->class->fieldMappings['%2\$s']['criteria']) ? \$this->class->fieldMappings['%2\$s']['criteria'] : array() diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php index f8f43b85c5..060c2cb08b 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php @@ -103,6 +103,7 @@ class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMet const REFERENCE_STORE_AS_ID = 'id'; const REFERENCE_STORE_AS_DB_REF = 'dbRef'; const REFERENCE_STORE_AS_DB_REF_WITH_DB = 'dbRefWithDb'; + const REFERENCE_STORE_AS_REF = 'ref'; /* The inheritance mapping types */ /** @@ -474,6 +475,48 @@ public function __construct($documentName) $this->rootDocumentName = $documentName; } + /** + * Helper method to get reference id of ref* type references + * @param mixed $reference + * @param string $storeAs + * @return mixed + * @internal + */ + public static function getReferenceId($reference, $storeAs) + { + return $storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_ID ? $reference : $reference[ClassMetadataInfo::getReferencePrefix($storeAs) . 'id']; + } + + /** + * Returns the reference prefix used for a reference + * @param string $storeAs + * @return string + */ + private static function getReferencePrefix($storeAs) + { + if (!in_array($storeAs, [ClassMetadataInfo::REFERENCE_STORE_AS_REF, ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF, ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB])) { + throw new \LogicException('Can only get a reference prefix for DBRef and reference arrays'); + } + + return $storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_REF ? '' : '$'; + } + + /** + * Returns a fully qualified field name for a given reference + * @param string $storeAs + * @param string $pathPrefix The field path prefix + * @return string + * @internal + */ + public static function getReferenceFieldName($storeAs, $pathPrefix = '') + { + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { + return $pathPrefix; + } + + return ($pathPrefix ? $pathPrefix . '.' : '') . static::getReferencePrefix($storeAs) . 'id'; + } + /** * {@inheritDoc} */ diff --git a/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php b/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php index bcb39d839e..752274db71 100644 --- a/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php +++ b/lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php @@ -718,13 +718,8 @@ private function loadReferenceManyCollectionOwningSide(PersistentCollectionInter $sorted = isset($mapping['sort']) && $mapping['sort']; foreach ($collection->getMongoData() as $key => $reference) { - if (isset($mapping['storeAs']) && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - $className = $mapping['targetDocument']; - $mongoId = $reference; - } else { - $className = $this->uow->getClassNameForAssociation($mapping, $reference); - $mongoId = $reference['$id']; - } + $className = $this->uow->getClassNameForAssociation($mapping, $reference); + $mongoId = ClassMetadataInfo::getReferenceId($reference, $mapping['storeAs']); $id = $this->dm->getClassMetadata($className)->getPHPIdentifierValue($mongoId); // create a reference to the class and id @@ -806,7 +801,8 @@ 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['storeAs']) && $mappedByMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID ? $mapping['mappedBy'] : $mapping['mappedBy'] . '.$id'; + $mappedByFieldName = ClassMetadataInfo::getReferenceFieldName(isset($mappedByMapping['storeAs']) ? $mappedByMapping['storeAs'] : ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF, $mapping['mappedBy']); + $criteria = $this->cm->merge( array($mappedByFieldName => $ownerClass->getIdentifierObject($owner)), $this->dm->getFilterCollection()->getFilterCriteria($targetClass), @@ -1056,7 +1052,7 @@ private function prepareQueryElement($fieldName, $value = null, $class = null, $ if (! empty($mapping['reference']) && is_object($value) && ! ($value instanceof \MongoId)) { try { - return $this->prepareDbRefElement($fieldName, $value, $mapping, $inNewObj); + return $this->prepareReference($fieldName, $value, $mapping, $inNewObj); } catch (MappingException $e) { // do nothing in case passed object is not mapped document } @@ -1178,7 +1174,7 @@ private function prepareQueryElement($fieldName, $value = null, $class = null, $ // Prepare DBRef identifiers or the mapped field's property path $fieldName = ($objectPropertyIsId && ! empty($mapping['reference']) && $mapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) - ? $e[0] . '.$id' + ? ClassMetadataInfo::getReferenceFieldName($mapping['storeAs'], $e[0]) : $e[0] . '.' . $objectPropertyPrefix . $targetMapping['name']; // Process targetDocument identifier fields @@ -1422,28 +1418,41 @@ private function getWriteOptions(array $options = array()) * @param bool $inNewObj * @return array */ - private function prepareDbRefElement($fieldName, $value, array $mapping, $inNewObj) + private function prepareReference($fieldName, $value, array $mapping, $inNewObj) { - $dbRef = $this->dm->createDBRef($value, $mapping); - if ($inNewObj) { - return [[$fieldName, $dbRef]]; - } - $keys = ['$ref' => true, '$id' => true, '$db' => true]; - if ($mapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB) { - unset($keys['$db']); + $reference = $this->dm->createReference($value, $mapping); + if ($inNewObj || $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { + return [[$fieldName, $reference]]; } - if (isset($mapping['targetDocument'])) { - unset($keys['$ref'], $keys['$db']); + + switch ($mapping['storeAs']) { + case ClassMetadataInfo::REFERENCE_STORE_AS_REF: + $keys = ['id' => true]; + break; + + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF: + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB: + $keys = ['$ref' => true, '$id' => true, '$db' => true]; + + if ($mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { + unset($keys['$db']); + } + + if (isset($mapping['targetDocument'])) { + unset($keys['$ref'], $keys['$db']); + } + break; + + default: + throw new \InvalidArgumentException("Reference type {$mapping['storeAs']} is invalid."); } - if ($mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - return [[$fieldName, $dbRef]]; - } elseif ($mapping['type'] === 'many') { - return [[$fieldName, ['$elemMatch' => array_intersect_key($dbRef, $keys)]]]; + if ($mapping['type'] === 'many') { + return [[$fieldName, ['$elemMatch' => array_intersect_key($reference, $keys)]]]; } else { return array_map( - function ($key) use ($dbRef, $fieldName) { - return [$fieldName . '.' . $key, $dbRef[$key]]; + function ($key) use ($reference, $fieldName) { + return [$fieldName . '.' . $key, $reference[$key]]; }, array_keys($keys) ); diff --git a/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php b/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php index 44659b2c1a..caa90be3e9 100644 --- a/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php +++ b/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php @@ -308,7 +308,7 @@ public function prepareUpsertData($document) */ public function prepareReferencedDocumentValue(array $referenceMapping, $document) { - return $this->dm->createDBRef($document, $referenceMapping); + return $this->dm->createReference($document, $referenceMapping); } /** diff --git a/lib/Doctrine/ODM/MongoDB/Query/Expr.php b/lib/Doctrine/ODM/MongoDB/Query/Expr.php index 7c4830973e..1bed27c6db 100644 --- a/lib/Doctrine/ODM/MongoDB/Query/Expr.php +++ b/lib/Doctrine/ODM/MongoDB/Query/Expr.php @@ -73,29 +73,43 @@ public function references($document) { if ($this->currentField) { $mapping = $this->getReferenceMapping(); - $dbRef = $this->dm->createDBRef($document, $mapping); + $reference = $this->dm->createReference($document, $mapping); $storeAs = array_key_exists('storeAs', $mapping) ? $mapping['storeAs'] : null; - if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - $this->query[$mapping['name']] = $dbRef; - } else { - $keys = array('ref' => true, 'id' => true, 'db' => true); + switch ($storeAs) { + case ClassMetadataInfo::REFERENCE_STORE_AS_ID: + $this->query[$mapping['name']] = $reference; + return $this; + break; - if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { - unset($keys['db']); - } + case ClassMetadataInfo::REFERENCE_STORE_AS_REF: + $keys = ['id' => true]; + break; - if (isset($mapping['targetDocument'])) { - unset($keys['ref'], $keys['db']); - } + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF: + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB: + $keys = ['$ref' => true, '$id' => true, '$db' => true]; - foreach ($keys as $key => $value) { - $this->query[$mapping['name'] . '.$' . $key] = $dbRef['$' . $key]; - } + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { + unset($keys['$db']); + } + + if (isset($mapping['targetDocument'])) { + unset($keys['$ref'], $keys['$db']); + } + break; + + default: + throw new \InvalidArgumentException("Reference type {$storeAs} is invalid."); + } + + foreach ($keys as $key => $value) { + $this->query[$mapping['name'] . '.' . $key] = $reference[$key]; } } else { - $dbRef = $this->dm->createDBRef($document); - $this->query = $dbRef; + @trigger_error('Calling ' . __METHOD__ . ' without a current field set will no longer be possible in ODM 2.0.', E_USER_DEPRECATED); + + $this->query = $this->dm->createDBRef($document); } return $this; @@ -111,29 +125,43 @@ public function includesReferenceTo($document) { if ($this->currentField) { $mapping = $this->getReferenceMapping(); - $dbRef = $this->dm->createDBRef($document, $mapping); + $reference = $this->dm->createReference($document, $mapping); $storeAs = array_key_exists('storeAs', $mapping) ? $mapping['storeAs'] : null; - if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - $this->query[$mapping['name']] = $dbRef; - } else { - $keys = array('ref' => true, 'id' => true, 'db' => true); + switch ($storeAs) { + case ClassMetadataInfo::REFERENCE_STORE_AS_ID: + $this->query[$mapping['name']] = $reference; + return $this; + break; - if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { - unset($keys['db']); - } + case ClassMetadataInfo::REFERENCE_STORE_AS_REF: + $keys = ['id' => true]; + break; - if (isset($mapping['targetDocument'])) { - unset($keys['ref'], $keys['db']); - } + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF: + case ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB: + $keys = ['$ref' => true, '$id' => true, '$db' => true]; - foreach ($keys as $key => $value) { - $this->query[$mapping['name']]['$elemMatch']['$' . $key] = $dbRef['$' . $key]; - } + if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF) { + unset($keys['$db']); + } + + if (isset($mapping['targetDocument'])) { + unset($keys['$ref'], $keys['$db']); + } + break; + + default: + throw new \InvalidArgumentException("Reference type {$storeAs} is invalid."); + } + + foreach ($keys as $key => $value) { + $this->query[$mapping['name']]['$elemMatch'][$key] = $reference[$key]; } } else { - $dbRef = $this->dm->createDBRef($document); - $this->query['$elemMatch'] = $dbRef; + @trigger_error('Calling ' . __METHOD__ . ' without a current field set will no longer be possible in ODM 2.0.', E_USER_DEPRECATED); + + $this->query['$elemMatch'] = $this->dm->createDBRef($document); } return $this; diff --git a/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php b/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php index 2d5529f479..4db943d925 100644 --- a/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php +++ b/lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php @@ -261,10 +261,9 @@ private function addManyReferences(PersistentCollectionInterface $persistentColl } foreach ($persistentCollection->getMongoData() as $reference) { - if ($mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) { - $id = $reference; - } else { - $id = $reference['$id']; + $id = ClassMetadataInfo::getReferenceId($reference, $mapping['storeAs']); + + if ($mapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) { $className = $this->uow->getClassNameForAssociation($mapping, $reference); $class = $this->dm->getClassMetadata($className); } diff --git a/lib/Doctrine/ODM/MongoDB/SchemaManager.php b/lib/Doctrine/ODM/MongoDB/SchemaManager.php index dbf4d35301..b2b12965b2 100644 --- a/lib/Doctrine/ODM/MongoDB/SchemaManager.php +++ b/lib/Doctrine/ODM/MongoDB/SchemaManager.php @@ -193,9 +193,7 @@ private function doGetDocumentIndexes($documentName, array &$visited) $newKeys = array(); foreach ($index['keys'] as $key => $v) { if ($key == $fieldMapping['name']) { - $key = $fieldMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID - ? $key - : $key . '.$id'; + $key = ClassMetadataInfo::getReferenceFieldName($fieldMapping['storeAs'], $key); } $newKeys[$key] = $v; } diff --git a/lib/Doctrine/ODM/MongoDB/UnitOfWork.php b/lib/Doctrine/ODM/MongoDB/UnitOfWork.php index 8669822170..6e1625faff 100644 --- a/lib/Doctrine/ODM/MongoDB/UnitOfWork.php +++ b/lib/Doctrine/ODM/MongoDB/UnitOfWork.php @@ -2625,7 +2625,7 @@ public function getClassNameForAssociation(array $mapping, $data) : $discriminatorValue; } - $class = $this->dm->getClassMetadata($mapping['targetDocument']); + $class = $this->dm->getClassMetadata($mapping['targetDocument']); if (isset($class->discriminatorField, $data[$class->discriminatorField])) { $discriminatorValue = $data[$class->discriminatorField]; diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/LookupTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/LookupTest.php index ade3200cce..66ed68f968 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/LookupTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Aggregation/Stage/LookupTest.php @@ -4,11 +4,17 @@ class LookupTest extends \Doctrine\ODM\MongoDB\Tests\BaseTest { - public function testLookupStage() + /** + * @before + */ + public function prepareTest() { $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); $this->insertTestData(); + } + public function testLookupStage() + { $builder = $this->dm->createAggregationBuilder(\Documents\SimpleReferenceUser::class); $builder ->lookup('user') @@ -36,9 +42,6 @@ public function testLookupStage() public function testLookupStageWithClassName() { - $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); - $this->insertTestData(); - $builder = $this->dm->createAggregationBuilder(\Documents\SimpleReferenceUser::class); $builder ->lookup(\Documents\User::class) @@ -68,9 +71,6 @@ public function testLookupStageWithClassName() public function testLookupStageWithCollectionName() { - $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); - $this->insertTestData(); - $builder = $this->dm->createAggregationBuilder(\Documents\SimpleReferenceUser::class); $builder ->lookup('randomCollectionName') @@ -99,9 +99,6 @@ public function testLookupStageWithCollectionName() public function testLookupStageReferenceMany() { - $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); - $this->insertTestData(); - $builder = $this->dm->createAggregationBuilder(\Documents\SimpleReferenceUser::class); $builder ->unwind('$users') @@ -133,11 +130,42 @@ public function testLookupStageReferenceMany() $this->assertSame('malarzm', $result[1]['users'][0]['username']); } + public function testLookupStageReferenceManyStoreAsRef() + { + $builder = $this->dm->createAggregationBuilder(\Documents\ReferenceUser::class); + $builder + ->unwind('$referencedUsers') + ->lookup('referencedUsers') + ->alias('users'); + + $expectedPipeline = [ + [ + '$unwind' => '$referencedUsers', + ], + [ + '$lookup' => [ + 'from' => 'users', + 'localField' => 'referencedUsers.id', + 'foreignField' => '_id', + 'as' => 'users', + ] + ] + ]; + + $this->assertEquals($expectedPipeline, $builder->getPipeline()); + + $result = $builder->execute()->toArray(); + + $this->assertCount(2, $result); + $this->assertCount(1, $result[0]['users']); + $this->assertSame('alcaeus', $result[0]['users'][0]['username']); + $this->assertCount(1, $result[1]['users']); + $this->assertSame('malarzm', $result[1]['users'][0]['username']); + } + public function testLookupStageReferenceManyWithoutUnwindMongoDB32() { - $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); $this->skipOnMongoDB34('$lookup tests without unwind will not work on MongoDB 3.4.0'); - $this->insertTestData(); $builder = $this->dm->createAggregationBuilder(\Documents\SimpleReferenceUser::class); $builder @@ -166,7 +194,6 @@ public function testLookupStageReferenceManyWithoutUnwindMongoDB32() public function testLookupStageReferenceManyWithoutUnwindMongoDB34() { $this->requireMongoDB34('$lookup tests with unwind require at least MongoDB 3.4.0'); - $this->insertTestData(); $builder = $this->dm->createAggregationBuilder(\Documents\SimpleReferenceUser::class); $builder @@ -196,9 +223,6 @@ public function testLookupStageReferenceManyWithoutUnwindMongoDB34() public function testLookupStageReferenceOneInverse() { - $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); - $this->insertTestData(); - $builder = $this->dm->createAggregationBuilder(\Documents\User::class); $builder ->match() @@ -231,9 +255,6 @@ public function testLookupStageReferenceOneInverse() public function testLookupStageReferenceManyInverse() { - $this->requireMongoDB32('$lookup tests require at least MongoDB 3.2.0'); - $this->insertTestData(); - $builder = $this->dm->createAggregationBuilder(\Documents\User::class); $builder ->match() @@ -264,6 +285,70 @@ public function testLookupStageReferenceManyInverse() $this->assertCount(1, $result[0]['simpleReferenceManyInverse']); } + public function testLookupStageReferenceOneInverseStoreAsRef() + { + $builder = $this->dm->createAggregationBuilder(\Documents\User::class); + $builder + ->match() + ->field('username') + ->equals('alcaeus') + ->lookup('embeddedReferenceOneInverse') + ->alias('embeddedReferenceOneInverse'); + + $expectedPipeline = [ + [ + '$match' => ['username' => 'alcaeus'] + ], + [ + '$lookup' => [ + 'from' => 'ReferenceUser', + 'localField' => '_id', + 'foreignField' => 'referencedUser.id', + 'as' => 'embeddedReferenceOneInverse', + ] + ] + ]; + + $this->assertEquals($expectedPipeline, $builder->getPipeline()); + + $result = $builder->execute()->toArray(); + + $this->assertCount(1, $result); + $this->assertCount(1, $result[0]['embeddedReferenceOneInverse']); + } + + public function testLookupStageReferenceManyInverseStoreAsRef() + { + $builder = $this->dm->createAggregationBuilder(\Documents\User::class); + $builder + ->match() + ->field('username') + ->equals('alcaeus') + ->lookup('embeddedReferenceManyInverse') + ->alias('embeddedReferenceManyInverse'); + + $expectedPipeline = [ + [ + '$match' => ['username' => 'alcaeus'] + ], + [ + '$lookup' => [ + 'from' => 'ReferenceUser', + 'localField' => '_id', + 'foreignField' => 'referencedUsers.id', + 'as' => 'embeddedReferenceManyInverse', + ] + ] + ]; + + $this->assertEquals($expectedPipeline, $builder->getPipeline()); + + $result = $builder->execute()->toArray(); + + $this->assertCount(1, $result); + $this->assertCount(1, $result[0]['embeddedReferenceManyInverse']); + } + private function insertTestData() { $user1 = new \Documents\User(); @@ -281,7 +366,13 @@ private function insertTestData() $simpleReferenceUser->addUser($user1); $simpleReferenceUser->addUser($user2); + $referenceUser = new \Documents\ReferenceUser(); + $referenceUser->setReferencedUser($user1); + $referenceUser->addReferencedUser($user1); + $referenceUser->addReferencedUser($user2); + $this->dm->persist($simpleReferenceUser); + $this->dm->persist($referenceUser); $this->dm->flush(); } } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php b/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php index 0d9b7d0d2e..5b3a3934fa 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/DocumentManagerTest.php @@ -5,6 +5,7 @@ use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; use Doctrine\ODM\MongoDB\Tests\Mocks\DocumentManagerMock; +use Documents\CmsPhonenumber; class DocumentManagerTest extends \Doctrine\ODM\MongoDB\Tests\BaseTest { @@ -195,16 +196,16 @@ public function testGetDocumentCollectionAppliesClassMetadataSlaveOkay() public function testCannotCreateDbRefWithoutId() { $d = new \Documents\User(); - $this->dm->createDBRef($d); + $this->dm->createReference($d, ['storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF]); } public function testCreateDbRefWithNonNullEmptyId() { - $phonenumber = new \Documents\CmsPhonenumber(); + $phonenumber = new CmsPhonenumber(); $phonenumber->phonenumber = 0; $this->dm->persist($phonenumber); - $dbRef = $this->dm->createDBRef($phonenumber); + $dbRef = $this->dm->createReference($phonenumber, ['storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF, 'targetDocument' => CmsPhonenumber::class]); $this->assertSame(array('$ref' => 'CmsPhonenumber', '$id' => 0), $dbRef); } @@ -219,7 +220,7 @@ public function testDisriminatedSimpleReferenceFails() $r = new \Documents\Tournament\ParticipantSolo('Maciej'); $this->dm->persist($r); $class = $this->dm->getClassMetadata(get_class($d)); - $this->dm->createDBRef($r, $class->associationMappings['ref']); + $this->dm->createReference($r, $class->associationMappings['ref']); } public function testDifferentStoreAsDbReferences() @@ -229,19 +230,23 @@ public function testDifferentStoreAsDbReferences() $d = new ReferenceStoreAsDocument(); $class = $this->dm->getClassMetadata(get_class($d)); - $dbRef = $this->dm->createDBRef($r, $class->associationMappings['ref1']); + $dbRef = $this->dm->createReference($r, $class->associationMappings['ref1']); $this->assertInstanceOf('MongoId', $dbRef); - $dbRef = $this->dm->createDBRef($r, $class->associationMappings['ref2']); + $dbRef = $this->dm->createReference($r, $class->associationMappings['ref2']); $this->assertCount(2, $dbRef); $this->assertArrayHasKey('$ref', $dbRef); $this->assertArrayHasKey('$id', $dbRef); - $dbRef = $this->dm->createDBRef($r, $class->associationMappings['ref3']); + $dbRef = $this->dm->createReference($r, $class->associationMappings['ref3']); $this->assertCount(3, $dbRef); $this->assertArrayHasKey('$ref', $dbRef); $this->assertArrayHasKey('$id', $dbRef); $this->assertArrayHasKey('$db', $dbRef); + + $dbRef = $this->dm->createReference($r, $class->associationMappings['ref4']); + $this->assertCount(1, $dbRef); + $this->assertArrayHasKey('id', $dbRef); } private function getMockClassMetadataFactory() @@ -279,4 +284,7 @@ class ReferenceStoreAsDocument /** @ODM\ReferenceOne(targetDocument="Documents\User", storeAs="dbRefWithDb") */ public $ref3; + + /** @ODM\ReferenceOne(targetDocument="Documents\User", storeAs="ref") */ + public $ref4; } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php index bf9321b6e3..c7a130db4c 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/DocumentPersisterTest.php @@ -345,6 +345,83 @@ public function testPrepareQueryOrNewObjWithDBRefReferenceToTargetDocumentWithHa $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); } + public function testPrepareQueryOrNewObjWithEmbeddedReferenceToTargetDocumentWithNormalIdType() + { + $class = DocumentPersisterTestHashIdDocument::class; + $documentPersister = $this->uow->getDocumentPersister($class); + + $id = new \MongoId(); + + $value = array('embeddedRef.id' => (string) $id); + $expected = array('embeddedRef.id' => $id); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$exists' => true)); + $expected = array('embeddedRef.id' => array('$exists' => true)); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$elemMatch' => (string) $id)); + $expected = array('embeddedRef.id' => array('$elemMatch' => $id)); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$in' => array((string) $id))); + $expected = array('embeddedRef.id' => array('$in' => array($id))); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$not' => array('$elemMatch' => (string) $id))); + $expected = array('embeddedRef.id' => array('$not' => array('$elemMatch' => $id))); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$not' => array('$in' => array((string) $id)))); + $expected = array('embeddedRef.id' => array('$not' => array('$in' => array($id)))); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + } + + /** + * @dataProvider provideHashIdentifiers + */ + public function testPrepareQueryOrNewObjWithEmbeddedReferenceToTargetDocumentWithHashIdType($hashId) + { + $class = DocumentPersisterTestDocument::class; + $documentPersister = $this->uow->getDocumentPersister($class); + + $value = array('embeddedRef.id' => $hashId); + $expected = array('embeddedRef.id' => (object) $hashId); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$exists' => true)); + $expected = array('embeddedRef.id' => array('$exists' => true)); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$elemMatch' => $hashId)); + $expected = array('embeddedRef.id' => array('$elemMatch' => (object) $hashId)); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$in' => array($hashId))); + $expected = array('embeddedRef.id' => array('$in' => array((object) $hashId))); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$not' => array('$elemMatch' => $hashId))); + $expected = array('embeddedRef.id' => array('$not' => array('$elemMatch' => (object) $hashId))); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + + $value = array('embeddedRef.id' => array('$not' => array('$in' => array($hashId)))); + $expected = array('embeddedRef.id' => array('$not' => array('$in' => array((object) $hashId)))); + + $this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value)); + } + /** * @return array */ @@ -547,6 +624,9 @@ class DocumentPersisterTestDocument /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument", storeAs="dbRefWithDb") */ public $complexRef; + + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestHashIdDocument", storeAs="ref") */ + public $embeddedRef; } /** @ODM\Document */ @@ -628,6 +708,9 @@ class DocumentPersisterTestHashIdDocument /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument", storeAs="dbRefWithDb") */ public $complexRef; + + /** @ODM\ReferenceOne(targetDocument="DocumentPersisterTestDocument", storeAs="ref") */ + public $embeddedRef; } /** @ODM\Document(writeConcern="majority") */ diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php index fc3c736dfd..1161501889 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php @@ -4,6 +4,7 @@ use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; +use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; use Doctrine\ODM\MongoDB\Proxy\Proxy; use Doctrine\ODM\MongoDB\Query\Query; use Documents\Account; @@ -446,7 +447,7 @@ public function testPrimeReferencesInFindAndModifyResult() $this->dm->persist($group); $this->dm->flush(); - $groupDBRef = $this->dm->createDBRef($group); + $groupDBRef = $this->dm->createReference($group, ['storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF, 'targetDocument' => Group::class]); $this->dm->clear(); diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php index 6b4495ea09..61e6d88f87 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php @@ -149,7 +149,7 @@ public function testArrayUpdateOperatorsOnReferenceMany($class, $field) ->field($field)->addToSet($f) ->getQuery()->debug(); - $expected = $this->dm->createDBRef($f, $this->dm->getClassMetadata($class)->fieldMappings[$field]); + $expected = $this->dm->createReference($f, $this->dm->getClassMetadata($class)->fieldMappings[$field]); $this->assertEquals($expected, $q1['newObj']['$addToSet'][$field]); } @@ -173,7 +173,7 @@ public function testArrayUpdateOperatorsOnReferenceOne($class, $field) ->field($field)->set($f) ->getQuery()->debug(); - $expected = $this->dm->createDBRef($f, $this->dm->getClassMetadata($class)->fieldMappings[$field]); + $expected = $this->dm->createReference($f, $this->dm->getClassMetadata($class)->fieldMappings[$field]); $this->assertEquals($expected, $q1['newObj']['$set'][$field]); } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php index 355ee81a4a..348c230b32 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php @@ -192,7 +192,7 @@ public function testReferencesUsesMinimalKeys() $expected = array('foo.$id' => '1234'); $dm->expects($this->once()) - ->method('createDBRef') + ->method('createReference') ->will($this->returnValue(array('$ref' => 'coll', '$id' => '1234', '$db' => 'db'))); $dm->expects($this->once()) ->method('getUnitOfWork') @@ -206,7 +206,7 @@ public function testReferencesUsesMinimalKeys() ->will($this->returnValue($expected)); $class->expects($this->once()) ->method('getFieldMapping') - ->will($this->returnValue(array('targetDocument' => 'Foo', 'name' => 'foo'))); + ->will($this->returnValue(array('targetDocument' => 'Foo', 'name' => 'foo', 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB))); $expr = new Expr($dm); $expr->setClassMetadata($class); @@ -225,7 +225,7 @@ public function testReferencesUsesAllKeys() $expected = array('foo.$ref' => 'coll', 'foo.$id' => '1234', 'foo.$db' => 'db'); $dm->expects($this->once()) - ->method('createDBRef') + ->method('createReference') ->will($this->returnValue(array('$ref' => 'coll', '$id' => '1234', '$db' => 'db'))); $dm->expects($this->once()) ->method('getUnitOfWork') @@ -239,7 +239,7 @@ public function testReferencesUsesAllKeys() ->will($this->returnValue($expected)); $class->expects($this->once()) ->method('getFieldMapping') - ->will($this->returnValue(array('name' => 'foo'))); + ->will($this->returnValue(array('name' => 'foo', 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB))); $expr = new Expr($dm); $expr->setClassMetadata($class); @@ -258,7 +258,7 @@ public function testReferencesUsesSomeKeys() $expected = array('foo.$ref' => 'coll', 'foo.$id' => '1234'); $dm->expects($this->once()) - ->method('createDBRef') + ->method('createReference') ->will($this->returnValue(array('$ref' => 'coll', '$id' => '1234'))); $dm->expects($this->once()) ->method('getUnitOfWork') diff --git a/tests/Documents/ReferenceUser.php b/tests/Documents/ReferenceUser.php index 51542bd6bd..088bd96eeb 100644 --- a/tests/Documents/ReferenceUser.php +++ b/tests/Documents/ReferenceUser.php @@ -58,6 +58,20 @@ class ReferenceUser */ public $otherUsers = array(); + /** + * @ODM\ReferenceOne(targetDocument="Documents\User", storeAs="ref") + * + * @var User + */ + public $referencedUser; + + /** + * @ODM\ReferenceMany(targetDocument="Documents\User", storeAs="ref") + * + * @var User[] + */ + public $referencedUsers = array(); + /** * @ODM\Field(type="string") * @@ -161,6 +175,38 @@ public function getOtherUsers() return $this->otherUsers; } + /** + * @param User $referencedUser + */ + public function setReferencedUser(User $referencedUser) + { + $this->referencedUser = $referencedUser; + } + + /** + * @return User + */ + public function getreferencedUser() + { + return $this->referencedUser; + } + + /** + * @param User $referencedUser + */ + public function addReferencedUser(User $referencedUser) + { + $this->referencedUsers[] = $referencedUser; + } + + /** + * @return User[] + */ + public function getReferencedUsers() + { + return $this->referencedUsers; + } + /** * @param string $name */ diff --git a/tests/Documents/User.php b/tests/Documents/User.php index 1e7d0c4972..b421fecbb2 100644 --- a/tests/Documents/User.php +++ b/tests/Documents/User.php @@ -80,6 +80,12 @@ class User extends BaseDocument /** @ODM\ReferenceMany(targetDocument="Documents\SimpleReferenceUser", mappedBy="users") */ protected $simpleReferenceManyInverse; + /** @ODM\ReferenceOne(targetDocument="Documents\ReferenceUser", mappedBy="referencedUser") */ + protected $embeddedReferenceOneInverse; + + /** @ODM\ReferenceMany(targetDocument="Documents\ReferenceUser", mappedBy="referencedUsers") */ + protected $embeddedReferenceManyInverse; + /** @ODM\Field(type="collection") */ private $logs = array();