Example #1
0
 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;
 }
 /**
  * {@inheritDoc}
  */
 public function findTranslation($className, $id, $locale, $fallback = true)
 {
     return $this->wrapped->findTranslation($className, $id, $locale, $fallback);
 }