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();
}
}