/** {@inheritdoc} */
 public function takeSnapshot()
 {
     if (CollectionHelper::isList($this->mapping['strategy'])) {
         $array = $this->coll->toArray();
         $this->coll->clear();
         foreach ($array as $document) {
             $this->coll->add($document);
         }
     }
     $this->snapshot = $this->coll->toArray();
     $this->isDirty = false;
 }
Exemplo n.º 2
0
 /**
  * Cascades the save operation to associated documents.
  *
  * @param object $document
  * @param array $visited
  */
 private function cascadePersist($document, array &$visited)
 {
     $class = $this->dm->getClassMetadata(get_class($document));
     $associationMappings = array_filter($class->associationMappings, function ($assoc) {
         return $assoc['isCascadePersist'];
     });
     foreach ($associationMappings as $fieldName => $mapping) {
         $relatedDocuments = $class->reflFields[$fieldName]->getValue($document);
         if ($relatedDocuments instanceof Collection || is_array($relatedDocuments)) {
             if ($relatedDocuments instanceof PersistentCollectionInterface) {
                 if ($relatedDocuments->getOwner() !== $document) {
                     $relatedDocuments = $this->fixPersistentCollectionOwnership($relatedDocuments, $document, $class, $mapping['fieldName']);
                 }
                 // Unwrap so that foreach() does not initialize
                 $relatedDocuments = $relatedDocuments->unwrap();
             }
             $count = 0;
             foreach ($relatedDocuments as $relatedKey => $relatedDocument) {
                 if (!empty($mapping['embedded'])) {
                     list(, $knownParent, ) = $this->getParentAssociation($relatedDocument);
                     if ($knownParent && $knownParent !== $document) {
                         $relatedDocument = clone $relatedDocument;
                         $relatedDocuments[$relatedKey] = $relatedDocument;
                     }
                     $pathKey = CollectionHelper::isList($mapping['strategy']) ? $count++ : $relatedKey;
                     $this->setParentAssociation($relatedDocument, $mapping, $document, $mapping['fieldName'] . '.' . $pathKey);
                 }
                 $this->doPersist($relatedDocument, $visited);
             }
         } elseif ($relatedDocuments !== null) {
             if (!empty($mapping['embedded'])) {
                 list(, $knownParent, ) = $this->getParentAssociation($relatedDocuments);
                 if ($knownParent && $knownParent !== $document) {
                     $relatedDocuments = clone $relatedDocuments;
                     $class->setFieldValue($document, $mapping['fieldName'], $relatedDocuments);
                 }
                 $this->setParentAssociation($relatedDocuments, $mapping, $document, $mapping['fieldName']);
             }
             $this->doPersist($relatedDocuments, $visited);
         }
     }
 }
Exemplo n.º 3
0
 /**
  * Computes the changes of an association.
  *
  * @param object $parentDocument
  * @param array $assoc
  * @param mixed $value The value of the association.
  * @throws \InvalidArgumentException
  */
 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 PersistentCollection && $value->isDirty() && $assoc['isOwningSide']) {
         if ($topOrExistingDocument || CollectionHelper::usesSet($assoc['strategy'])) {
             $this->scheduleCollectionUpdate($value);
         }
         $topmostOwner = $this->getOwningDocument($value->getOwner());
         $this->visitedCollections[spl_object_hash($topmostOwner)][] = $value;
     }
     // 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: " . self::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) {
                     $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.");
                 break;
             default:
                 // MANAGED associated documents are already taken into account
                 // during changeset calculation anyway, since they are in the identity map.
         }
     }
 }
Exemplo n.º 4
0
 /**
  * Returns the collection representation to be stored and unschedules it afterwards.
  *
  * @param PersistentCollection $coll
  * @param bool $includeNestedCollections
  * @return array
  */
 public function prepareAssociatedCollectionValue(PersistentCollection $coll, $includeNestedCollections = false)
 {
     $mapping = $coll->getMapping();
     $pb = $this;
     $callback = isset($mapping['embedded']) ? function ($v) use($pb, $mapping, $includeNestedCollections) {
         return $pb->prepareEmbeddedDocumentValue($mapping, $v, $includeNestedCollections);
     } : function ($v) use($pb, $mapping) {
         return $pb->prepareReferencedDocumentValue($mapping, $v);
     };
     $setData = $coll->map($callback)->toArray();
     if (CollectionHelper::isList($mapping['strategy'])) {
         $setData = array_values($setData);
     }
     $this->uow->unscheduleCollectionDeletion($coll);
     $this->uow->unscheduleCollectionUpdate($coll);
     return $setData;
 }