Doctrine\ODM\MongoDB\UnitOfWork::computeOrRecomputeChangeSet PHP Method

computeOrRecomputeChangeSet() private method

Used to do the common work of computeChangeSet and recomputeSingleDocumentChangeSet
private computeOrRecomputeChangeSet ( ClassMetadata $class, object $document, boolean $recompute = false )
$class Doctrine\ODM\MongoDB\Mapping\ClassMetadata
$document object
$recompute boolean
    private function computeOrRecomputeChangeSet(ClassMetadata $class, $document, $recompute = false)
    {
        $oid = spl_object_hash($document);
        $actualData = $this->getDocumentActualData($document);
        $isNewDocument = !isset($this->originalDocumentData[$oid]);
        if ($isNewDocument) {
            // Document is either NEW or MANAGED but not yet fully persisted (only has an id).
            // These result in an INSERT.
            $this->originalDocumentData[$oid] = $actualData;
            $changeSet = array();
            foreach ($actualData as $propName => $actualValue) {
                /* At this PersistentCollection shouldn't be here, probably it
                 * was cloned and its ownership must be fixed
                 */
                if ($actualValue instanceof PersistentCollectionInterface && $actualValue->getOwner() !== $document) {
                    $actualData[$propName] = $this->fixPersistentCollectionOwnership($actualValue, $document, $class, $propName);
                    $actualValue = $actualData[$propName];
                }
                // ignore inverse side of reference relationship
                if (isset($class->fieldMappings[$propName]['reference']) && $class->fieldMappings[$propName]['isInverseSide']) {
                    continue;
                }
                $changeSet[$propName] = array(null, $actualValue);
            }
            $this->documentChangeSets[$oid] = $changeSet;
        } else {
            // Document is "fully" MANAGED: it was already fully persisted before
            // and we have a copy of the original data
            $originalData = $this->originalDocumentData[$oid];
            $isChangeTrackingNotify = $class->isChangeTrackingNotify();
            if ($isChangeTrackingNotify && !$recompute && isset($this->documentChangeSets[$oid])) {
                $changeSet = $this->documentChangeSets[$oid];
            } else {
                $changeSet = array();
            }
            foreach ($actualData as $propName => $actualValue) {
                // skip not saved fields
                if (isset($class->fieldMappings[$propName]['notSaved']) && $class->fieldMappings[$propName]['notSaved'] === true) {
                    continue;
                }
                $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
                // skip if value has not changed
                if ($orgValue === $actualValue) {
                    if ($actualValue instanceof PersistentCollectionInterface) {
                        if (!$actualValue->isDirty() && !$this->isCollectionScheduledForDeletion($actualValue)) {
                            // consider dirty collections as changed as well
                            continue;
                        }
                    } elseif (!(isset($class->fieldMappings[$propName]['file']) && $actualValue->isDirty())) {
                        // but consider dirty GridFSFile instances as changed
                        continue;
                    }
                }
                // if relationship is a embed-one, schedule orphan removal to trigger cascade remove operations
                if (isset($class->fieldMappings[$propName]['embedded']) && $class->fieldMappings[$propName]['type'] === 'one') {
                    if ($orgValue !== null) {
                        $this->scheduleOrphanRemoval($orgValue);
                    }
                    $changeSet[$propName] = array($orgValue, $actualValue);
                    continue;
                }
                // if owning side of reference-one relationship
                if (isset($class->fieldMappings[$propName]['reference']) && $class->fieldMappings[$propName]['type'] === 'one' && $class->fieldMappings[$propName]['isOwningSide']) {
                    if ($orgValue !== null && $class->fieldMappings[$propName]['orphanRemoval']) {
                        $this->scheduleOrphanRemoval($orgValue);
                    }
                    $changeSet[$propName] = array($orgValue, $actualValue);
                    continue;
                }
                if ($isChangeTrackingNotify) {
                    continue;
                }
                // ignore inverse side of reference relationship
                if (isset($class->fieldMappings[$propName]['reference']) && $class->fieldMappings[$propName]['isInverseSide']) {
                    continue;
                }
                // Persistent collection was exchanged with the "originally"
                // created one. This can only mean it was cloned and replaced
                // on another document.
                if ($actualValue instanceof PersistentCollectionInterface && $actualValue->getOwner() !== $document) {
                    $actualValue = $this->fixPersistentCollectionOwnership($actualValue, $document, $class, $propName);
                }
                // if embed-many or reference-many relationship
                if (isset($class->fieldMappings[$propName]['type']) && $class->fieldMappings[$propName]['type'] === 'many') {
                    $changeSet[$propName] = array($orgValue, $actualValue);
                    /* If original collection was exchanged with a non-empty value
                     * and $set will be issued, there is no need to $unset it first
                     */
                    if ($actualValue && $actualValue->isDirty() && CollectionHelper::usesSet($class->fieldMappings[$propName]['strategy'])) {
                        continue;
                    }
                    if ($orgValue !== $actualValue && $orgValue instanceof PersistentCollectionInterface) {
                        $this->scheduleCollectionDeletion($orgValue);
                    }
                    continue;
                }
                // skip equivalent date values
                if (isset($class->fieldMappings[$propName]['type']) && $class->fieldMappings[$propName]['type'] === 'date') {
                    $dateType = Type::getType('date');
                    $dbOrgValue = $dateType->convertToDatabaseValue($orgValue);
                    $dbActualValue = $dateType->convertToDatabaseValue($actualValue);
                    if ($dbOrgValue instanceof \MongoDate && $dbActualValue instanceof \MongoDate && $dbOrgValue == $dbActualValue) {
                        continue;
                    }
                }
                // regular field
                $changeSet[$propName] = array($orgValue, $actualValue);
            }
            if ($changeSet) {
                $this->documentChangeSets[$oid] = isset($this->documentChangeSets[$oid]) ? $changeSet + $this->documentChangeSets[$oid] : $changeSet;
                $this->originalDocumentData[$oid] = $actualData;
                $this->scheduleForUpdate($document);
            }
        }
        // Look for changes in associations of the document
        $associationMappings = array_filter($class->associationMappings, function ($assoc) {
            return empty($assoc['notSaved']);
        });
        foreach ($associationMappings as $mapping) {
            $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
            if ($value === null) {
                continue;
            }
            $this->computeAssociationChanges($document, $mapping, $value);
            if (isset($mapping['reference'])) {
                continue;
            }
            $values = $mapping['type'] === ClassMetadata::ONE ? array($value) : $value->unwrap();
            foreach ($values as $obj) {
                $oid2 = spl_object_hash($obj);
                if (isset($this->documentChangeSets[$oid2])) {
                    if (empty($this->documentChangeSets[$oid][$mapping['fieldName']])) {
                        // instance of $value is the same as it was previously otherwise there would be
                        // change set already in place
                        $this->documentChangeSets[$oid][$mapping['fieldName']] = array($value, $value);
                    }
                    if (!$isNewDocument) {
                        $this->scheduleForUpdate($document);
                    }
                    break;
                }
            }
        }
    }
UnitOfWork