/** * @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]); } } }