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

computeAssociationChanges() private method

Computes the changes of an association.
private computeAssociationChanges ( object $parentDocument, array $assoc, mixed $value )
$parentDocument object
$assoc array
$value mixed The value of the association.
    private function computeAssociationChanges($parentDocument, array $assoc, $value)
    {
        $isNewParentDocument = isset($this->documentInsertions[spl_object_hash($parentDocument)]);
        $class = $this->dm->getClassMetadata(get_class($parentDocument));
        $topOrExistingDocument = !$isNewParentDocument || !$class->isEmbeddedDocument;
        if ($value instanceof Proxy && !$value->__isInitialized__) {
            return;
        }
        if ($value instanceof PersistentCollectionInterface && $value->isDirty() && ($assoc['isOwningSide'] || isset($assoc['embedded']))) {
            if ($topOrExistingDocument || CollectionHelper::usesSet($assoc['strategy'])) {
                $this->scheduleCollectionUpdate($value);
            }
            $topmostOwner = $this->getOwningDocument($value->getOwner());
            $this->visitedCollections[spl_object_hash($topmostOwner)][] = $value;
            if (!empty($assoc['orphanRemoval']) || isset($assoc['embedded'])) {
                $value->initialize();
                foreach ($value->getDeletedDocuments() as $orphan) {
                    $this->scheduleOrphanRemoval($orphan);
                }
            }
        }
        // Look through the documents, and in any of their associations,
        // for transient (new) documents, recursively. ("Persistence by reachability")
        // Unwrap. Uninitialized collections will simply be empty.
        $unwrappedValue = $assoc['type'] === ClassMetadata::ONE ? array($value) : $value->unwrap();
        $count = 0;
        foreach ($unwrappedValue as $key => $entry) {
            if (!is_object($entry)) {
                throw new \InvalidArgumentException(sprintf('Expected object, found "%s" in %s::%s', $entry, get_class($parentDocument), $assoc['name']));
            }
            $targetClass = $this->dm->getClassMetadata(get_class($entry));
            $state = $this->getDocumentState($entry, self::STATE_NEW);
            // Handle "set" strategy for multi-level hierarchy
            $pathKey = !isset($assoc['strategy']) || CollectionHelper::isList($assoc['strategy']) ? $count : $key;
            $path = $assoc['type'] === 'many' ? $assoc['name'] . '.' . $pathKey : $assoc['name'];
            $count++;
            switch ($state) {
                case self::STATE_NEW:
                    if (!$assoc['isCascadePersist']) {
                        throw new \InvalidArgumentException('A new document was found through a relationship that was not' . ' configured to cascade persist operations: ' . $this->objToStr($entry) . '.' . ' Explicitly persist the new document or configure cascading persist operations' . ' on the relationship.');
                    }
                    $this->persistNew($targetClass, $entry);
                    $this->setParentAssociation($entry, $assoc, $parentDocument, $path);
                    $this->computeChangeSet($targetClass, $entry);
                    break;
                case self::STATE_MANAGED:
                    if ($targetClass->isEmbeddedDocument) {
                        list(, $knownParent, ) = $this->getParentAssociation($entry);
                        if ($knownParent && $knownParent !== $parentDocument) {
                            $entry = clone $entry;
                            if ($assoc['type'] === ClassMetadata::ONE) {
                                $class->setFieldValue($parentDocument, $assoc['fieldName'], $entry);
                                $this->setOriginalDocumentProperty(spl_object_hash($parentDocument), $assoc['fieldName'], $entry);
                            } else {
                                // must use unwrapped value to not trigger orphan removal
                                $unwrappedValue[$key] = $entry;
                            }
                            $this->persistNew($targetClass, $entry);
                        }
                        $this->setParentAssociation($entry, $assoc, $parentDocument, $path);
                        $this->computeChangeSet($targetClass, $entry);
                    }
                    break;
                case self::STATE_REMOVED:
                    // Consume the $value as array (it's either an array or an ArrayAccess)
                    // and remove the element from Collection.
                    if ($assoc['type'] === ClassMetadata::MANY) {
                        unset($value[$key]);
                    }
                    break;
                case self::STATE_DETACHED:
                    // Can actually not happen right now as we assume STATE_NEW,
                    // so the exception will be raised from the DBAL layer (constraint violation).
                    throw new \InvalidArgumentException('A detached document was found through a ' . 'relationship during cascading a persist operation.');
                default:
                    // MANAGED associated documents are already taken into account
                    // during changeset calculation anyway, since they are in the identity map.
            }
        }
    }
UnitOfWork