Doctrine\ODM\PHPCR\UnitOfWork::doMerge PHP Method

doMerge() private method

private doMerge ( $document, array &$visited, $prevManagedCopy = null, $assoc = null )
$visited array
    private function doMerge($document, array &$visited, $prevManagedCopy = null, $assoc = null)
    {
        $oid = spl_object_hash($document);
        if (isset($visited[$oid])) {
            return $document;
            // Prevent infinite recursion
        }
        $visited[$oid] = $document;
        // mark visited
        $class = $this->dm->getClassMetadata(get_class($document));
        $locale = $this->getCurrentLocale($document, $class);
        // 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 entities are ignored by the merge operation.
        if ($this->getDocumentState($document) == self::STATE_MANAGED) {
            $managedCopy = $document;
        } else {
            $id = $this->determineDocumentId($document, $class);
            $persist = false;
            if (!$id) {
                // document is new
                $managedCopy = $class->newInstance();
                $persist = true;
            } else {
                $managedCopy = $this->getDocumentById($id);
                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 at '{$id}'. Cannot merge with a removed document.");
                    }
                    if (ClassUtils::getClass($managedCopy) != ClassUtils::getClass($document)) {
                        throw new InvalidArgumentException('Can not merge documents of different classes.');
                    }
                    if ($this->getCurrentLocale($managedCopy, $class) !== $locale) {
                        $this->doLoadTranslation($document, $class, $locale, true);
                    }
                } elseif ($locale) {
                    // We need to fetch the managed copy in order to merge.
                    $managedCopy = $this->dm->findTranslation($class->name, $id, $locale);
                } 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 document was not found.
                    if ($class->idGenerator !== ClassMetadata::GENERATOR_TYPE_ASSIGNED) {
                        throw new InvalidArgumentException("Document not found in merge operation: {$id}");
                    }
                    $managedCopy = $class->newInstance();
                    $class->setIdentifierValue($managedCopy, $id);
                    $persist = true;
                }
            }
            $managedOid = spl_object_hash($managedCopy);
            // Merge state of $document into existing (managed) document
            foreach ($class->reflFields as $fieldName => $prop) {
                $other = $prop->getValue($document);
                if ($other instanceof PersistentCollection && !$other->isInitialized() || $other instanceof Proxy && !$other->__isInitialized()) {
                    // do not merge fields marked lazy that have not been fetched.
                    // keep the lazy persistent collection of the managed copy.
                    continue;
                }
                $mapping = $class->mappings[$fieldName];
                if (ClassMetadata::MANY_TO_ONE === $mapping['type']) {
                    $this->doMergeSingleDocumentProperty($managedCopy, $other, $prop, $mapping);
                } elseif (ClassMetadata::MANY_TO_MANY === $mapping['type']) {
                    $managedCol = $prop->getValue($managedCopy);
                    if (!$managedCol) {
                        $managedCol = new ReferenceManyCollection($this->dm, $document, $mapping['property'], array(), isset($mapping['targetDocument']) ? $mapping['targetDocument'] : null, $locale, $this->getReferenceManyCollectionTypeFromMetadata($mapping));
                        $prop->setValue($managedCopy, $managedCol);
                        $this->originalData[$managedOid][$fieldName] = $managedCol;
                    }
                    $this->cascadeMergeCollection($managedCol, $mapping);
                } elseif ('child' === $mapping['type']) {
                    if (null !== $other) {
                        $this->doMergeSingleDocumentProperty($managedCopy, $other, $prop, $mapping);
                    }
                } elseif ('children' === $mapping['type']) {
                    $managedCol = $prop->getValue($managedCopy);
                    if (!$managedCol) {
                        $managedCol = new ChildrenCollection($this->dm, $managedCopy, $mapping['filter'], $mapping['fetchDepth'], $locale);
                        $prop->setValue($managedCopy, $managedCol);
                        $this->originalData[$managedOid][$fieldName] = $managedCol;
                    }
                    $this->cascadeMergeCollection($managedCol, $mapping);
                } elseif ('referrers' === $mapping['type']) {
                    $managedCol = $prop->getValue($managedCopy);
                    if (!$managedCol) {
                        $referringMeta = $this->dm->getClassMetadata($mapping['referringDocument']);
                        $referringField = $referringMeta->mappings[$mapping['referencedBy']];
                        $managedCol = new ReferrersCollection($this->dm, $managedCopy, $referringField['strategy'], $referringField['property'], $locale);
                        $prop->setValue($managedCopy, $managedCol);
                        $this->originalData[$managedOid][$fieldName] = $managedCol;
                    }
                    $this->cascadeMergeCollection($managedCol, $mapping);
                } elseif ('mixedreferrers' === $mapping['type']) {
                    $managedCol = $prop->getValue($managedCopy);
                    if (!$managedCol) {
                        $managedCol = new ImmutableReferrersCollection($this->dm, $managedCopy, $mapping['referenceType'], $locale);
                        $prop->setValue($managedCopy, $managedCol);
                        $this->originalData[$managedOid][$fieldName] = $managedCol;
                    }
                    $this->cascadeMergeCollection($managedCol, $mapping);
                } elseif ('parent' === $mapping['type']) {
                    $this->doMergeSingleDocumentProperty($managedCopy, $other, $prop, $mapping);
                } elseif (in_array($mapping['type'], array('locale', 'versionname', 'versioncreated', 'node', 'nodename'))) {
                    if (null !== $other) {
                        $prop->setValue($managedCopy, $other);
                    }
                } elseif (!$class->isIdentifier($fieldName)) {
                    $prop->setValue($managedCopy, $other);
                }
            }
            if ($persist) {
                $this->persistNew($class, $managedCopy);
            }
            // Mark the managed copy visited as well
            $visited[$managedOid] = true;
        }
        if ($prevManagedCopy !== null) {
            $prevClass = $this->dm->getClassMetadata(get_class($prevManagedCopy));
            if ($assoc['type'] == ClassMetadata::MANY_TO_ONE) {
                $prevClass->reflFields[$assoc['fieldName']]->setValue($prevManagedCopy, $managedCopy);
            } else {
                $prevClass->reflFields[$assoc['fieldName']]->getValue($prevManagedCopy)->add($managedCopy);
            }
        }
        $this->cascadeMerge($class, $document, $managedCopy, $visited);
        return $managedCopy;
    }
UnitOfWork