Exemple #1
0
 /**
  * Computes changeset for a given document.
  *
  * @param ClassMetadata $class
  * @param object        $document
  */
 public function computeChangeSet(ClassMetadata $class, $document)
 {
     if ($document instanceof Proxy && !$document->__isInitialized()) {
         return;
     }
     $oid = spl_object_hash($document);
     if (in_array($oid, $this->changesetComputed)) {
         return;
     }
     $this->changesetComputed[] = $oid;
     $changeSet = $actualData = $this->getDocumentActualData($class, $document);
     $id = $this->getDocumentId($document, false);
     $isNew = !isset($this->originalData[$oid]);
     if ($isNew) {
         // Document is New and should be inserted
         $this->originalData[$oid] = $changeSet;
     } elseif (!empty($this->documentChangesets[$oid]['fields'])) {
         foreach ($this->documentChangesets[$oid]['fields'] as $fieldName => $data) {
             $this->originalData[$oid][$fieldName] = $data[0];
         }
     }
     if ($class->parentMapping && isset($changeSet[$class->parentMapping])) {
         $parent = $changeSet[$class->parentMapping];
         $parentClass = $this->dm->getClassMetadata(get_class($parent));
         $state = $this->getDocumentState($parent);
         if ($state === self::STATE_MANAGED) {
             $this->computeChangeSet($parentClass, $parent);
         }
     }
     foreach ($class->childMappings as $fieldName) {
         if ($changeSet[$fieldName]) {
             if (is_array($changeSet[$fieldName]) || $changeSet[$fieldName] instanceof Collection) {
                 throw PHPCRException::childFieldIsArray(self::objToStr($document, $this->dm), $fieldName);
             }
             if (!is_object($changeSet[$fieldName])) {
                 throw PHPCRException::childFieldNoObject(self::objToStr($document, $this->dm), $fieldName, gettype($changeSet[$fieldName]));
             }
             $mapping = $class->mappings[$fieldName];
             $changeSet[$fieldName] = $this->computeChildChanges($mapping, $changeSet[$fieldName], $id, $mapping['nodeName']);
         }
     }
     $this->computeAssociationChanges($document, $class, $oid, $isNew, $changeSet, 'reference');
     $this->computeAssociationChanges($document, $class, $oid, $isNew, $changeSet, 'referrer');
     foreach ($class->mixedReferrersMappings as $fieldName) {
         if ($changeSet[$fieldName] && $changeSet[$fieldName] instanceof PersistentCollection && $changeSet[$fieldName]->isDirty()) {
             throw new PHPCRException("The immutable mixed referrer collection in field {$fieldName} is dirty");
         }
     }
     $this->computeChildrenChanges($document, $class, $oid, $isNew, $changeSet);
     if (!$isNew) {
         // collect assignment move operations
         $destPath = $destName = false;
         if (isset($this->originalData[$oid][$class->parentMapping]) && isset($changeSet[$class->parentMapping]) && $this->originalData[$oid][$class->parentMapping] !== $changeSet[$class->parentMapping]) {
             $destPath = $this->getDocumentId($changeSet[$class->parentMapping]);
         }
         if (isset($this->originalData[$oid][$class->nodename]) && isset($changeSet[$class->nodename]) && $this->originalData[$oid][$class->nodename] !== $changeSet[$class->nodename]) {
             $destName = $changeSet[$class->nodename];
         }
         // there was assignment move
         if ($destPath || $destName) {
             // add the other field if only one was changed
             if (false === $destPath) {
                 $destPath = isset($changeSet[$class->parentMapping]) ? $this->getDocumentId($changeSet[$class->parentMapping]) : PathHelper::getParentPath($this->getDocumentId($document));
             }
             if (false === $destName) {
                 $destName = $class->nodename !== null && $changeSet[$class->nodename] ? $changeSet[$class->nodename] : PathHelper::getNodeName($this->getDocumentId($document));
             }
             // make sure destination nodename is okay
             if ($exception = $class->isValidNodename($destName)) {
                 throw IdException::illegalName($document, $class->nodename, $destName);
             }
             // prevent path from becoming "//foobar" when moving to root node.
             $targetPath = '/' == $destPath ? "/{$destName}" : "{$destPath}/{$destName}";
             $this->scheduleMove($document, $targetPath);
         }
         if (isset($this->originalData[$oid][$class->identifier]) && isset($changeSet[$class->identifier]) && $this->originalData[$oid][$class->identifier] !== $changeSet[$class->identifier]) {
             throw new PHPCRException('The Id is immutable (' . $this->originalData[$oid][$class->identifier] . ' !== ' . $changeSet[$class->identifier] . '). Please use DocumentManager::move to move the document: ' . self::objToStr($document, $this->dm));
         }
     }
     $fields = array_intersect_key($changeSet, $class->mappings);
     if ($this->isDocumentTranslatable($class)) {
         $locale = $this->getCurrentLocale($document, $class);
         // ensure we do not bind a previously removed translation
         if (!$this->isTranslationRemoved($document, $locale)) {
             $this->doBindTranslation($document, $locale, $class);
         }
     }
     if ($isNew) {
         $this->documentChangesets[$oid]['fields'] = $fields;
         $this->scheduledInserts[$oid] = $document;
         return;
     }
     $translationChanges = false;
     if ($this->isDocumentTranslatable($class)) {
         $oid = spl_object_hash($document);
         if (isset($this->documentTranslations[$oid])) {
             foreach ($this->documentTranslations[$oid] as $localeToCheck => $data) {
                 // a translation was removed
                 if (empty($data)) {
                     $translationChanges = true;
                     break;
                 }
                 // a translation was added
                 if (empty($this->originalTranslatedData[$oid][$localeToCheck])) {
                     $translationChanges = true;
                     break;
                 }
                 // a translation was changed
                 foreach ($data as $fieldName => $fieldValue) {
                     if ($this->originalTranslatedData[$oid][$localeToCheck][$fieldName] !== $fieldValue) {
                         $translationChanges = true;
                         break;
                     }
                 }
             }
         }
         // ensure that locale changes are not considered a change in the document
         if ($class->localeMapping && array_key_exists($class->localeMapping, $fields)) {
             unset($fields[$class->localeMapping]);
         }
     }
     foreach ($fields as $fieldName => $fieldValue) {
         $keepChange = false;
         if ($fieldValue instanceof ReferenceManyCollection || $fieldValue instanceof ReferrersCollection) {
             if ($fieldValue->changed()) {
                 $keepChange = true;
             }
         } elseif ($this->originalData[$oid][$fieldName] !== $fieldValue) {
             $keepChange = true;
         }
         if ($keepChange) {
             $fields[$fieldName] = array($this->originalData[$oid][$fieldName], $fieldValue);
         } else {
             unset($fields[$fieldName]);
         }
     }
     if (!empty($fields) || $translationChanges) {
         $this->documentChangesets[$oid]['fields'] = $fields;
         $this->originalData[$oid] = $actualData;
         $this->scheduledUpdates[$oid] = $document;
     } elseif (empty($this->documentChangesets[$oid]['reorderings'])) {
         unset($this->documentChangesets[$oid]);
         unset($this->scheduledUpdates[$oid]);
     } else {
         $this->documentChangesets[$oid]['fields'] = array();
     }
 }