/** * Executes a merge operation on an document. * * @param object $document * @param array $visited * @return object The managed copy of the document. * @throws InvalidArgumentException If the document instance is NEW. */ private function doMerge($document, array &$visited, $prevManagedCopy = null, $assoc = null) { $oid = spl_object_hash($document); if (isset($visited[$oid])) { return; // Prevent infinite recursion } $visited[$oid] = $document; // mark visited $class = $this->dm->getClassMetadata(get_class($document)); // First we assume DETACHED, although it can still be NEW but we can avoid // an extra db-roundtrip this way. If it is not MANAGED but has an identity, // we need to fetch it from the db anyway in order to merge. // MANAGED documents are ignored by the merge operation. if ($this->getDocumentState($document, self::STATE_DETACHED) == self::STATE_MANAGED) { $managedCopy = $document; } else { // Try to look the entity up in the identity map. $id = $class->getIdentifierValue($document); // If there is no ID, it is actually NEW. if (!$id) { $managedCopy = $class->newInstance(); $this->persistNew($class, $managedCopy); } else { $managedCopy = $this->tryGetById($id, $class->rootDocumentName); if ($managedCopy) { // We have the entity in-memory already, just make sure its not removed. if ($this->getDocumentState($managedCopy) == self::STATE_REMOVED) { throw new InvalidArgumentException('Removed entity detected during merge.' . ' Can not merge with a removed entity.'); } } else { // We need to fetch the managed copy in order to merge. $managedCopy = $this->dm->find($class->name, $id); } if ($managedCopy === null) { // If the identifier is ASSIGNED, it is NEW, otherwise an error // since the managed entity was not found. $managedCopy = $class->newInstance(); $class->setIdentifierValue($managedCopy, $id); $this->persistNew($class, $managedCopy); } } if ($class->isVersioned) { $managedCopyVersion = $class->reflFields[$class->versionField]->getValue($managedCopy); $documentVersion = $class->reflFields[$class->versionField]->getValue($document); // Throw exception if versions dont match. if ($managedCopyVersion != $documentVersion) { throw LockException::lockFailedVersionMissmatch($documentVersion, $managedCopyVersion); } } // Merge state of $document into existing (managed) entity foreach ($class->reflFields as $name => $prop) { if (!isset($class->fieldMappings[$name]['embedded']) && !isset($class->fieldMappings[$name]['reference'])) { $prop->setValue($managedCopy, $prop->getValue($document)); } else { $assoc2 = $class->fieldMappings[$name]; if ($assoc2['type'] === 'one') { $other = $prop->getValue($document); if ($other === null) { $prop->setValue($managedCopy, null); } else { if ($other instanceof Proxy && !$other->__isInitialized__) { // do not merge fields marked lazy that have not been fetched. continue; } else { if (!isset($assoc2['embedded']) && !$assoc2['isCascadeMerge']) { if ($this->getDocumentState($other, self::STATE_DETACHED) == self::STATE_MANAGED) { $prop->setValue($managedCopy, $other); } else { $targetDocument = isset($assoc2['targetDocument']) ? $assoc2['targetDocument'] : get_class($other); $targetClass = $this->dm->getClassMetadata($targetDocument); $id = $targetClass->getIdentifierValue($other); $proxy = $this->dm->getProxyFactory()->getProxy($targetDocument, $id); $prop->setValue($managedCopy, $proxy); $this->registerManaged($proxy, $id, array()); } } } } } else { $mergeCol = $prop->getValue($document); if ($mergeCol instanceof PersistentCollection && !$mergeCol->isInitialized()) { // do not merge fields marked lazy that have not been fetched. // keep the lazy persistent collection of the managed copy. continue; } foreach ($mergeCol as $entry) { $targetDocument = isset($assoc2['targetDocument']) ? $assoc2['targetDocument'] : get_class($entry); $targetClass = $this->dm->getClassMetadata($targetDocument); if ($targetClass->isEmbeddedDocument) { $this->registerManaged($entry, null, array()); } else { $id = $targetClass->getIdentifierValue($entry); $this->registerManaged($entry, $id, array()); } } if (!$mergeCol instanceof PersistentCollection) { $mergeCol = new PersistentCollection($mergeCol, $this->dm, $this, $this->cmd); $mergeCol->setInitialized(true); } $mergeCol->setOwner($managedCopy, $assoc2); $prop->setValue($managedCopy, $mergeCol); } } if ($class->isChangeTrackingNotify()) { // Just treat all properties as changed, there is no other choice. $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy)); } } if ($class->isChangeTrackingDeferredExplicit()) { $this->scheduleForDirtyCheck($document); } } if ($prevManagedCopy !== null) { $assocField = $assoc->sourceFieldName; $prevClass = $this->dm->getClassMetadata(get_class($prevManagedCopy)); if ($assoc->isOneToOne()) { $prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy); } else { $prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->unwrap()->add($managedCopy); if ($assoc->isOneToMany()) { $class->reflFields[$assoc->mappedBy]->setValue($managedCopy, $prevManagedCopy); } } } // Mark the managed copy visited as well $visited[spl_object_hash($managedCopy)] = true; $this->cascadeMerge($document, $managedCopy, $visited); return $managedCopy; }
private function fixPersistentCollectionOwnership(PersistentCollection $coll, $document, $class, $propName) { $owner = $coll->getOwner(); if ($owner === null) { // cloned $coll->setOwner($document, $class->fieldMappings[$propName]); } elseif ($owner !== $document) { // no clone, we have to fix if (!$coll->isInitialized()) { $coll->initialize(); // we have to do this otherwise the cols share state } $newValue = clone $coll; $newValue->setOwner($document, $class->fieldMappings[$propName]); $class->reflFields[$propName]->setValue($document, $newValue); return $newValue; } return $coll; }
/** * Executes a merge operation on a document. * * @param object $document * @param array $visited * @param object|null $prevManagedCopy * @param array|null $assoc * * @return object The managed copy of the document. * * @throws InvalidArgumentException If the document instance is NEW. * @throws LockException If the entity uses optimistic locking through a * version attribute and the version check against the * managed copy fails. */ private function doMerge($document, array &$visited, $prevManagedCopy = null, $assoc = null) { $oid = spl_object_hash($document); if (isset($visited[$oid])) { return $visited[$oid]; // Prevent infinite recursion } $visited[$oid] = $document; // mark visited $class = $this->dm->getClassMetadata(get_class($document)); /* First we assume DETACHED, although it can still be NEW but we can * avoid an extra DB round trip this way. If it is not MANAGED but has * an identity, we need to fetch it from the DB anyway in order to * merge. MANAGED documents are ignored by the merge operation. */ $managedCopy = $document; if ($this->getDocumentState($document, self::STATE_DETACHED) !== self::STATE_MANAGED) { if ($document instanceof Proxy && !$document->__isInitialized()) { $document->__load(); } // Try to look the document up in the identity map. $id = $class->isEmbeddedDocument ? null : $class->getIdentifierObject($document); if ($id === null) { // If there is no identifier, it is actually NEW. $managedCopy = $class->newInstance(); $this->persistNew($class, $managedCopy); } else { $managedCopy = $this->tryGetById($id, $class); if ($managedCopy) { // We have the document in memory already, just make sure it is not removed. if ($this->getDocumentState($managedCopy) === self::STATE_REMOVED) { throw new \InvalidArgumentException('Removed entity detected during merge. Cannot merge with a removed entity.'); } } else { // We need to fetch the managed copy in order to merge. $managedCopy = $this->dm->find($class->name, $id); } if ($managedCopy === null) { // If the identifier is ASSIGNED, it is NEW $managedCopy = $class->newInstance(); $class->setIdentifierValue($managedCopy, $id); $this->persistNew($class, $managedCopy); } else { if ($managedCopy instanceof Proxy && !$managedCopy->__isInitialized__) { $managedCopy->__load(); } } } if ($class->isVersioned) { $managedCopyVersion = $class->reflFields[$class->versionField]->getValue($managedCopy); $documentVersion = $class->reflFields[$class->versionField]->getValue($document); // Throw exception if versions don't match if ($managedCopyVersion != $documentVersion) { throw LockException::lockFailedVersionMissmatch($document, $documentVersion, $managedCopyVersion); } } // Merge state of $document into existing (managed) document foreach ($class->reflClass->getProperties() as $prop) { $name = $prop->name; $prop->setAccessible(true); if (!isset($class->associationMappings[$name])) { if (!$class->isIdentifier($name)) { $prop->setValue($managedCopy, $prop->getValue($document)); } } else { $assoc2 = $class->associationMappings[$name]; if ($assoc2['type'] === 'one') { $other = $prop->getValue($document); if ($other === null) { $prop->setValue($managedCopy, null); } elseif ($other instanceof Proxy && !$other->__isInitialized__) { // Do not merge fields marked lazy that have not been fetched continue; } elseif (!$assoc2['isCascadeMerge']) { if ($this->getDocumentState($other) === self::STATE_DETACHED) { $targetDocument = isset($assoc2['targetDocument']) ? $assoc2['targetDocument'] : get_class($other); /* @var $targetClass \Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo */ $targetClass = $this->dm->getClassMetadata($targetDocument); $relatedId = $targetClass->getIdentifierObject($other); if ($targetClass->subClasses) { $other = $this->dm->find($targetClass->name, $relatedId); } else { $other = $this->dm->getProxyFactory()->getProxy($assoc2['targetDocument'], array($targetClass->identifier => $relatedId)); $this->registerManaged($other, $relatedId, array()); } } $prop->setValue($managedCopy, $other); } } else { $mergeCol = $prop->getValue($document); if ($mergeCol instanceof PersistentCollection && !$mergeCol->isInitialized()) { /* Do not merge fields marked lazy that have not * been fetched. Keep the lazy persistent collection * of the managed copy. */ continue; } $managedCol = $prop->getValue($managedCopy); if (!$managedCol) { $managedCol = new PersistentCollection(new ArrayCollection(), $this->dm, $this); $managedCol->setOwner($managedCopy, $assoc2); $prop->setValue($managedCopy, $managedCol); $this->originalDocumentData[$oid][$name] = $managedCol; } /* Note: do not process association's target documents. * They will be handled during the cascade. Initialize * and, if necessary, clear $managedCol for now. */ if ($assoc2['isCascadeMerge']) { $managedCol->initialize(); // If $managedCol differs from the merged collection, clear and set dirty if (!$managedCol->isEmpty() && $managedCol !== $mergeCol) { $managedCol->unwrap()->clear(); $managedCol->setDirty(true); if ($assoc2['isOwningSide'] && $class->isChangeTrackingNotify()) { $this->scheduleForDirtyCheck($managedCopy); } } } } } if ($class->isChangeTrackingNotify()) { // Just treat all properties as changed, there is no other choice. $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy)); } } if ($class->isChangeTrackingDeferredExplicit()) { $this->scheduleForDirtyCheck($document); } } if ($prevManagedCopy !== null) { $assocField = $assoc['fieldName']; $prevClass = $this->dm->getClassMetadata(get_class($prevManagedCopy)); if ($assoc['type'] === 'one') { $prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy); } else { $prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->add($managedCopy); if ($assoc['type'] === 'many' && isset($assoc['mappedBy'])) { $class->reflFields[$assoc['mappedBy']]->setValue($managedCopy, $prevManagedCopy); } } } // Mark the managed copy visited as well $visited[spl_object_hash($managedCopy)] = true; $this->cascadeMerge($document, $managedCopy, $visited); return $managedCopy; }
/** * Fixes PersistentCollection state if it wasn't used exactly as we had in mind: * 1) sets owner if it was cloned * 2) clones collection, sets owner, updates document's property and, if necessary, updates originalData * 3) NOP if state is OK * Returned collection should be used from now on (only important with 2nd point) * * @param PersistentCollection $coll * @param object $document * @param ClassMetadata $class * @param string $propName * @return PersistentCollection */ private function fixPersistentCollectionOwnership(PersistentCollection $coll, $document, ClassMetadata $class, $propName) { $owner = $coll->getOwner(); if ($owner === null) { // cloned $coll->setOwner($document, $class->fieldMappings[$propName]); } elseif ($owner !== $document) { // no clone, we have to fix if (!$coll->isInitialized()) { $coll->initialize(); // we have to do this otherwise the cols share state } $newValue = clone $coll; $newValue->setOwner($document, $class->fieldMappings[$propName]); $class->reflFields[$propName]->setValue($document, $newValue); if ($this->isScheduledForUpdate($document)) { // @todo following line should be superfluous once collections are stored in change sets $this->setOriginalDocumentProperty(spl_object_hash($document), $propName, $newValue); } return $newValue; } return $coll; }
/** * Executes a merge operation on an document. * * @param object $document * @param array $visited * @return object The managed copy of the document. * @throws InvalidArgumentException If the document instance is NEW. */ private function _doMerge($document, array &$visited, $prevManagedCopy = null, $mapping = null) { $class = $this->_dm->getClassMetadata(get_class($document)); $id = $class->getIdentifierValues($document); if (!$id) { throw new \InvalidArgumentException('New document detected during merge.' . ' Persist the new document before merging.'); } // MANAGED documents are ignored by the merge operation if ($this->getDocumentState($document, self::STATE_DETACHED) == self::STATE_MANAGED) { $managedCopy = $document; } else { // Try to look the document up in the identity map. $managedCopy = $this->tryGetById($id, $class->rootDocumentName); if ($managedCopy) { // We have the document in-memory already, just make sure its not removed. if ($this->getDocumentState($managedCopy) == self::STATE_REMOVED) { throw new \InvalidArgumentException('Removed document detected during merge.' . ' Can not merge with a removed document.'); } } else { // We need to fetch the managed copy in order to merge. $managedCopy = $this->_dm->find($class->name, $id); } if ($managedCopy === null) { throw new \InvalidArgumentException('New document detected during merge.' . ' Persist the new document before merging.'); } // Merge state of $document into existing (managed) document foreach ($class->reflFields as $name => $prop) { if (!isset($class->fieldMappings[$name]['reference'])) { $prop->setValue($managedCopy, $prop->getValue($document)); } else { $mapping2 = $class->fieldMappings[$name]; if ($mapping2['type'] === 'one') { if (!$assoc2['isCascadeMerge']) { $other = $class->reflFields[$name]->getValue($document); //TODO: Just $prop->getValue($document)? if ($other !== null) { $targetClass = $this->_dm->getClassMetadata($mapping2['targetDocument']); $id = $targetClass->getIdentifierValue($other); $proxy = $this->_dm->getProxyFactory()->getProxy($mapping2['targetDocument'], $id); $prop->setValue($managedCopy, $proxy); $this->registerManaged($proxy, $id, array()); } } } else { $coll = new PersistentCollection($this->_dm, $this->_dm->getClassMetadata($mapping2['targetDocument']), new ArrayCollection()); $coll->setOwner($managedCopy, $mapping2); $coll->setInitialized($mapping2['isCascadeMerge']); $prop->setValue($managedCopy, $coll); } } } } if ($prevManagedCopy !== null) { $assocField = $mapping['fieldName']; $prevClass = $this->_dm->getClassMetadata(get_class($prevManagedCopy)); if ($mapping['type'] === 'one') { $prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy); } else { $prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->unwrap()->add($managedCopy); } } $this->_cascadeMerge($document, $managedCopy, $visited); return $managedCopy; }
/** * {@inheritdoc} */ public function setOwner($document, array $mapping) { $this->collection->setOwner($document, $mapping); }
private function doGenericHydration(ClassMetadata $metadata, $document, $data) { foreach ($metadata->fieldMappings as $mapping) { // Find the raw value. It may be in one of the mapped alsoLoadFields. $found = false; if (isset($mapping['alsoLoadFields']) && $mapping['alsoLoadFields']) { foreach ($mapping['alsoLoadFields'] as $name) { if (isset($data[$name])) { $rawValue = $data[$name]; $found = true; break; } } } // If nothing then lets get it from the default mapping field name if ($found === false) { $rawValue = isset($data[$mapping['name']]) ? $data[$mapping['name']] : null; } $value = null; // Prepare the different types of mapped values converting them from the MongoDB // types to the portable Doctrine types. // @Field if (!isset($mapping['association'])) { $value = Type::getType($mapping['type'])->convertToPHPValue($rawValue); // @ReferenceOne } elseif ($mapping['association'] === ClassMetadata::REFERENCE_ONE) { $reference = $rawValue; if ($reference === null || !isset($reference[$this->cmd . 'id'])) { continue; } $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $reference); $targetMetadata = $this->dm->getClassMetadata($className); $id = $targetMetadata->getPHPIdentifierValue($reference[$this->cmd . 'id']); $value = $this->dm->getReference($className, $id); // @ReferenceMany and @EmbedMany } elseif ($mapping['association'] === ClassMetadata::REFERENCE_MANY || $mapping['association'] === ClassMetadata::EMBED_MANY) { $value = new PersistentCollection(new ArrayCollection(), $this->dm, $this->unitOfWork, $this->cmd); $value->setOwner($document, $mapping); $value->setInitialized(false); if ($rawValue) { $value->setMongoData($rawValue); } // @EmbedOne } elseif ($mapping['association'] === ClassMetadata::EMBED_ONE) { if ($rawValue === null) { continue; } $embeddedDocument = $rawValue; $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $embeddedDocument); $embeddedMetadata = $this->dm->getClassMetadata($className); $value = $embeddedMetadata->newInstance(); $embeddedHydratedData = $this->hydrate($value, $embeddedDocument); $this->unitOfWork->registerManaged($value, null, $embeddedHydratedData); $this->unitOfWork->setParentAssociation($value, $mapping, $document, $mapping['name']); } unset($data[$mapping['name']]); // Hydrate the prepared value to the document if ($value !== null) { $metadata->reflFields[$mapping['fieldName']]->setValue($document, $value); $data[$mapping['fieldName']] = $value; } } return $data; }
/** * Hydrate array of MongoDB document data into the given document object. * * @param object $document The document object to hydrate the data into. * @param array $data The array of document data. * @return array $values The array of hydrated values. */ public function hydrate($document, &$data) { $metadata = $this->dm->getClassMetadata(get_class($document)); if (isset($metadata->alsoLoadMethods)) { foreach ($metadata->alsoLoadMethods as $fieldName => $method) { if (isset($data[$fieldName])) { $document->{$method}($data[$fieldName]); } } } foreach ($metadata->fieldMappings as $mapping) { if (isset($mapping['alsoLoadFields'])) { $rawValue = null; $names = isset($mapping['alsoLoadFields']) ? $mapping['alsoLoadFields'] : array(); array_unshift($names, $mapping['name']); foreach ($names as $name) { if (isset($data[$name])) { $rawValue = $data[$name]; break; } } } else { $rawValue = isset($data[$mapping['name']]) ? $data[$mapping['name']] : null; } if ($rawValue === null) { continue; } $value = null; // Hydrate embedded if (isset($mapping['embedded'])) { if ($mapping['type'] === 'one') { $embeddedDocument = $rawValue; $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $embeddedDocument); $embeddedMetadata = $this->dm->getClassMetadata($className); $value = $embeddedMetadata->newInstance(); $this->hydrate($value, $embeddedDocument); $this->dm->getUnitOfWork()->registerManagedEmbeddedDocument($value, $embeddedDocument); } elseif ($mapping['type'] === 'many') { $embeddedDocuments = $rawValue; $coll = new PersistentCollection(new ArrayCollection()); foreach ($embeddedDocuments as $embeddedDocument) { $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $embeddedDocument); $embeddedMetadata = $this->dm->getClassMetadata($className); $embeddedDocumentObject = $embeddedMetadata->newInstance(); $this->hydrate($embeddedDocumentObject, $embeddedDocument); $this->dm->getUnitOfWork()->registerManagedEmbeddedDocument($embeddedDocumentObject, $embeddedDocument); $coll->add($embeddedDocumentObject); } $coll->setOwner($document, $mapping); $coll->takeSnapshot(); $value = $coll; } // Hydrate reference } elseif (isset($mapping['reference'])) { $reference = $rawValue; if ($mapping['type'] === 'one' && isset($reference[$this->cmd . 'id'])) { $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $reference); $targetMetadata = $this->dm->getClassMetadata($className); $id = $targetMetadata->getPHPIdentifierValue($reference[$this->cmd . 'id']); $value = $this->dm->getReference($className, $id); } elseif ($mapping['type'] === 'many' && (is_array($reference) || $reference instanceof Collection)) { $references = $reference; $value = new PersistentCollection(new ArrayCollection(), $this->dm); $value->setInitialized(false); $value->setOwner($document, $mapping); // Delay any hydration of reference objects until the collection is // accessed and initialized for the first ime $value->setReferences($references); } // Hydrate regular field } else { $value = Type::getType($mapping['type'])->convertToPHPValue($rawValue); } // Set hydrated field value to document if ($value !== null) { $data[$mapping['name']] = $value; $metadata->setFieldValue($document, $mapping['fieldName'], $value); } } // Set the document identifier if (isset($data['_id'])) { $metadata->setIdentifierValue($document, $data['_id']); $data[$metadata->identifier] = $data['_id']; unset($data['_id']); } return $document; }
/** * Hydrate array of MongoDB document data into the given document object. * * @param object $document The document object to hydrate the data into. * @param array $data The array of document data. * @return array $values The array of hydrated values. */ public function hydrate($document, &$data) { $metadata = $this->dm->getClassMetadata(get_class($document)); if (isset($metadata->lifecycleCallbacks[Events::preLoad])) { $args = array(&$data); $metadata->invokeLifecycleCallbacks(Events::preLoad, $document, $args); } if ($this->evm->hasListeners(Events::preLoad)) { $this->evm->dispatchEvent(Events::preLoad, new PreLoadEventArgs($document, $this->dm, $data)); } if (isset($metadata->alsoLoadMethods)) { foreach ($metadata->alsoLoadMethods as $fieldName => $method) { if (isset($data[$fieldName])) { $document->$method($data[$fieldName]); } } } foreach ($metadata->fieldMappings as $mapping) { if (isset($mapping['alsoLoadFields'])) { $rawValue = null; $names = isset($mapping['alsoLoadFields']) ? $mapping['alsoLoadFields'] : array(); array_unshift($names, $mapping['name']); foreach ($names as $name) { if (isset($data[$name])) { $rawValue = $data[$name]; break; } } } else { $rawValue = isset($data[$mapping['name']]) ? $data[$mapping['name']] : null; } $value = null; if (isset($mapping['embedded'])) { $uow = $this->dm->getUnitOfWork(); if ($mapping['type'] === 'one') { if ($rawValue === null) { continue; } $embeddedDocument = $rawValue; $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $embeddedDocument); $embeddedMetadata = $this->dm->getClassMetadata($className); $value = $embeddedMetadata->newInstance(); // unset a potential discriminator map field (unless it's a persisted property) $discriminatorField = isset($mapping['discriminatorField']) ? $mapping['discriminatorField'] : '_doctrine_class_name'; if (!isset($embeddedMetadata->fieldMappings[$discriminatorField])) { unset($embeddedDocument[$discriminatorField]); } $this->hydrate($value, $embeddedDocument); $uow->registerManaged($value, null, $embeddedDocument); $uow->setParentAssociation($value, $mapping, $document, $mapping['name']); } elseif ($mapping['type'] === 'many') { $embeddedDocuments = $rawValue; $coll = new PersistentCollection(new ArrayCollection(), $this->dm, $this->dm->getConfiguration()); if ($embeddedDocuments) { foreach ($embeddedDocuments as $key => $embeddedDocument) { $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $embeddedDocument); $embeddedMetadata = $this->dm->getClassMetadata($className); $embeddedDocumentObject = $embeddedMetadata->newInstance(); // unset a potential discriminator map field (unless it's a persisted property) $discriminatorField = isset($mapping['discriminatorField']) ? $mapping['discriminatorField'] : '_doctrine_class_name'; if (!isset($embeddedMetadata->fieldMappings[$discriminatorField])) { unset($embeddedDocument[$discriminatorField]); } $this->hydrate($embeddedDocumentObject, $embeddedDocument); $uow->registerManaged($embeddedDocumentObject, null, $embeddedDocument); $uow->setParentAssociation($embeddedDocumentObject, $mapping, $document, $mapping['name'].'.'.$key); $coll->add($embeddedDocumentObject); } } $coll->setOwner($document, $mapping); $coll->takeSnapshot(); $value = $coll; } // Hydrate reference } elseif (isset($mapping['reference'])) { $reference = $rawValue; if ($mapping['type'] === 'one' && isset($reference[$this->cmd . 'id'])) { if ($reference === null) { continue; } $className = $this->dm->getClassNameFromDiscriminatorValue($mapping, $reference); $targetMetadata = $this->dm->getClassMetadata($className); $id = $targetMetadata->getPHPIdentifierValue($reference[$this->cmd . 'id']); $value = $this->dm->getReference($className, $id); } elseif ($mapping['type'] === 'many' && (is_array($reference) || $reference instanceof Collection)) { $references = $reference; $value = new PersistentCollection(new ArrayCollection(), $this->dm, $this->dm->getConfiguration()); $value->setInitialized(false); $value->setOwner($document, $mapping); // Delay any hydration of reference objects until the collection is // accessed and initialized for the first ime $value->setReferences($references); } // Hydrate regular field } else { $value = Type::getType($mapping['type'])->convertToPHPValue($rawValue); } unset($data[$mapping['name']]); // Set hydrated field value to document if ($value !== null) { $metadata->setFieldValue($document, $mapping['fieldName'], $value); $data[$mapping['fieldName']] = $value; } } // Set the document identifier if (isset($data['_id'])) { $metadata->setIdentifierValue($document, $data['_id']); $data[$metadata->identifier] = Type::getType($metadata->fieldMappings[$metadata->identifier]['type'])->convertToPHPValue($data['_id']); unset($data['_id']); } if (isset($metadata->lifecycleCallbacks[Events::postLoad])) { $metadata->invokeLifecycleCallbacks(Events::postLoad, $document); } if ($this->evm->hasListeners(Events::postLoad)) { $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($document, $this->dm)); } return $document; }