/**
* @param ClassMetadata $class
* @param object $document
* @return void
*/
public function computeChangeSet(ClassMetadata $class, $document)
{
if ($document instanceof Proxy\Proxy && !$document->__isInitialized__) {
return;
}
$oid = \spl_object_hash($document);
$actualData = array();
$embeddedActualData = array();
// 1. compute the actual values of the current document
foreach ($class->reflFields as $fieldName => $reflProperty) {
$value = $reflProperty->getValue($document);
if ($class->isCollectionValuedAssociation($fieldName) && $value !== null && !$value instanceof PersistentCollection) {
if (!$value instanceof Collection) {
$value = new ArrayCollection($value);
}
if ($class->associationsMappings[$fieldName]['isOwning']) {
$coll = new PersistentIdsCollection($value, $class->associationsMappings[$fieldName]['targetDocument'], $this->dm, array());
} else {
$coll = new PersistentViewCollection($value, $this->dm, $this->documentIdentifiers[$oid], $class->associationsMappings[$fieldName]);
}
$class->reflFields[$fieldName]->setValue($document, $coll);
$actualData[$fieldName] = $coll;
} else {
$actualData[$fieldName] = $value;
if (isset($class->fieldMappings[$fieldName]['embedded']) && $value !== null) {
// serializing embedded value right here, to be able to detect changes for later invocations
$embeddedActualData[$fieldName] = $this->embeddedSerializer->serializeEmbeddedDocument($value, $class->fieldMappings[$fieldName]);
}
}
// TODO: ORM transforms arrays and collections into persistent collections
}
// unset the revision field if necessary, it is not to be managed by the user in write scenarios.
if ($class->isVersioned) {
unset($actualData[$class->versionField]);
}
// 2. Compare to the original, or find out that this document is new.
if (!isset($this->originalData[$oid])) {
// document is New and should be inserted
$this->originalData[$oid] = $actualData;
$this->scheduledUpdates[$oid] = $document;
$this->originalEmbeddedData[$oid] = $embeddedActualData;
} else {
// document is "fully" MANAGED: it was already fully persisted before
// and we have a copy of the original data
$changed = false;
foreach ($actualData as $fieldName => $fieldValue) {
// Important to not check embeded values here, because those are objects, equality check isn't enough
//
if (isset($class->fieldMappings[$fieldName]) && !isset($class->fieldMappings[$fieldName]['embedded']) && $this->originalData[$oid][$fieldName] !== $fieldValue) {
$changed = true;
break;
} else {
if (isset($class->associationsMappings[$fieldName])) {
if (!$class->associationsMappings[$fieldName]['isOwning']) {
continue;
}
if ($class->associationsMappings[$fieldName]['type'] & ClassMetadata::TO_ONE && $this->originalData[$oid][$fieldName] !== $fieldValue) {
$changed = true;
break;
} else {
if ($class->associationsMappings[$fieldName]['type'] & ClassMetadata::TO_MANY) {
if (!$fieldValue instanceof PersistentCollection) {
// if its not a persistent collection and the original value changed. otherwise it could just be null
$changed = true;
break;
} else {
if ($fieldValue->changed()) {
$this->visitedCollections[] = $fieldValue;
$changed = true;
break;
}
}
}
}
} else {
if ($class->hasAttachments && $fieldName == $class->attachmentField) {
// array of value objects, can compare that stricly
if ($this->originalData[$oid][$fieldName] !== $fieldValue) {
$changed = true;
break;
}
}
}
}
}
// Check embedded documents here, only if there is no change yet
if (!$changed) {
foreach ($embeddedActualData as $fieldName => $fieldValue) {
if (!isset($this->originalEmbeddedData[$oid][$fieldName]) || $this->embeddedSerializer->isChanged($actualData[$fieldName], $this->originalEmbeddedData[$oid][$fieldName], $class->fieldMappings[$fieldName])) {
$changed = true;
break;
}
}
}
if ($changed) {
$this->originalData[$oid] = $actualData;
$this->scheduledUpdates[$oid] = $document;
$this->originalEmbeddedData[$oid] = $embeddedActualData;
}
}
// 3. check if any cascading needs to happen
foreach ($class->associationsMappings as $name => $assoc) {
if ($this->originalData[$oid][$name]) {
$this->computeAssociationChanges($assoc, $this->originalData[$oid][$name]);
}
}
}