unscheduleCollectionDeletion() public method

INTERNAL: Unschedules a collection from being deleted when this UnitOfWork commits.
public unscheduleCollectionDeletion ( Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface $coll )
$coll Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface
Ejemplo n.º 1
0
 private function getAtomicCollectionUpdateQuery($document)
 {
     $update = array();
     $collections = $this->uow->getScheduledCollections($document);
     $collPersister = $this->uow->getCollectionPersister();
     foreach ($collections as $coll) {
         /* @var $coll PersistentCollection */
         $mapping = $coll->getMapping();
         if ($mapping['strategy'] !== "atomicSet" && $mapping['strategy'] !== "atomicSetArray") {
             continue;
         }
         if ($this->uow->isCollectionScheduledForUpdate($coll)) {
             $update = array_merge_recursive($update, $collPersister->prepareSetQuery($coll));
             $this->uow->unscheduleCollectionUpdate($coll);
             /* TODO:
              * Collection can be set for both deletion and update if
              * PersistentCollection instance was changed. Since we're dealing
              * with collection update in one query we won't need the $unset.
              * Line can be removed once the issue is fixed.
              */
             $this->uow->unscheduleCollectionDeletion($coll);
         } elseif ($this->uow->isCollectionScheduledForDeletion($coll)) {
             $update = array_merge_recursive($update, $collPersister->prepareDeleteQuery($coll));
             $this->uow->unscheduleCollectionDeletion($coll);
         }
     }
     return $update;
 }
Ejemplo n.º 2
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;
 }
Ejemplo n.º 3
0
 /**
  * Returns the embedded document to be stored in MongoDB.
  *
  * The return value will usually be an associative array with string keys
  * corresponding to field names on the embedded document. An object may be
  * returned if the document is empty, to ensure that a BSON object will be
  * stored in lieu of an array.
  *
  * If $includeNestedCollections is true, nested collections will be included
  * in this prepared value and the option will cascade to all embedded
  * associations. If any nested PersistentCollections (embed or reference)
  * within this value were previously scheduled for deletion or update, they
  * will also be unscheduled.
  *
  * @param array $embeddedMapping
  * @param object $embeddedDocument
  * @param boolean $includeNestedCollections
  * @return array|object
  * @throws \UnexpectedValueException if an unsupported associating mapping is found
  */
 public function prepareEmbeddedDocumentValue(array $embeddedMapping, $embeddedDocument, $includeNestedCollections = false)
 {
     $embeddedDocumentValue = array();
     $class = $this->dm->getClassMetadata(get_class($embeddedDocument));
     foreach ($class->fieldMappings as $mapping) {
         // Skip notSaved fields
         if (!empty($mapping['notSaved'])) {
             continue;
         }
         // Inline ClassMetadataInfo::getFieldValue()
         $rawValue = $class->reflFields[$mapping['fieldName']]->getValue($embeddedDocument);
         $value = null;
         if ($rawValue !== null) {
             switch (isset($mapping['association']) ? $mapping['association'] : null) {
                 // @Field, @String, @Date, etc.
                 case null:
                     $value = Type::getType($mapping['type'])->convertToDatabaseValue($rawValue);
                     break;
                 case ClassMetadata::EMBED_ONE:
                 case ClassMetadata::REFERENCE_ONE:
                     // Nested collections should only be included for embedded relationships
                     $value = $this->prepareAssociatedDocumentValue($mapping, $rawValue, $includeNestedCollections && isset($mapping['embedded']));
                     break;
                 case ClassMetadata::EMBED_MANY:
                 case ClassMetadata::REFERENCE_MANY:
                     // Skip PersistentCollections already scheduled for deletion
                     if (!$includeNestedCollections && $rawValue instanceof PersistentCollection && $this->uow->isCollectionScheduledForDeletion($rawValue)) {
                         break;
                     }
                     // We're handling atomicSet or atomicSetArray collection
                     if ($includeNestedCollections && $rawValue instanceof PersistentCollection) {
                         $this->uow->unscheduleCollectionDeletion($rawValue);
                         $this->uow->unscheduleCollectionUpdate($rawValue);
                     }
                     $pb = $this;
                     $value = $rawValue->map(function ($v) use($pb, $mapping, $includeNestedCollections) {
                         // Nested collections should only be included for embedded relationships
                         return $pb->prepareAssociatedDocumentValue($mapping, $v, $includeNestedCollections && isset($mapping['embedded']));
                     })->toArray();
                     // Numerical reindexing may be necessary to ensure BSON array storage
                     if (in_array($mapping['strategy'], array('atomicSetArray', 'setArray', 'pushAll', 'addToSet'))) {
                         $value = array_values($value);
                     }
                     break;
                 default:
                     throw new \UnexpectedValueException('Unsupported mapping association: ' . $mapping['association']);
             }
         }
         // Omit non-nullable fields that would have a null value
         if ($value === null && $mapping['nullable'] === false) {
             continue;
         }
         $embeddedDocumentValue[$mapping['name']] = $value;
     }
     /* Add a discriminator value if the embedded document is not mapped
      * explicitly to a targetDocument class.
      */
     if (!isset($embeddedMapping['targetDocument'])) {
         $discriminatorField = $embeddedMapping['discriminatorField'];
         $discriminatorValue = isset($embeddedMapping['discriminatorMap']) ? array_search($class->name, $embeddedMapping['discriminatorMap']) : $class->name;
         /* If the discriminator value was not found in the map, use the full
          * class name. In the future, it may be preferable to throw an
          * exception here (perhaps based on some strictness option).
          *
          * @see DocumentManager::createDBRef()
          */
         if ($discriminatorValue === false) {
             $discriminatorValue = $class->name;
         }
         $embeddedDocumentValue[$discriminatorField] = $discriminatorValue;
     }
     /* If the class has a discriminator (field and value), use it. A child
      * class that is not defined in the discriminator map may only have a
      * discriminator field and no value, so default to the full class name.
      */
     if (isset($class->discriminatorField)) {
         $embeddedDocumentValue[$class->discriminatorField] = isset($class->discriminatorValue) ? $class->discriminatorValue : $class->name;
     }
     // Ensure empty embedded documents are stored as BSON objects
     if (empty($embeddedDocumentValue)) {
         return (object) $embeddedDocumentValue;
     }
     /* @todo Consider always casting the return value to an object, or
      * building $embeddedDocumentValue as an object instead of an array, to
      * handle the edge case where all database field names are sequential,
      * numeric keys.
      */
     return $embeddedDocumentValue;
 }
Ejemplo n.º 4
0
 private function getAtomicCollectionUpdateQuery($document)
 {
     $update = array();
     $atomicCollUpdates = array();
     $atomicCollDeletes = array();
     $collPersister = $this->uow->getCollectionPersister();
     /* Collect all atomic collections (top-level and nested) to be included
      * in the update.
      */
     foreach ($this->uow->getScheduledCollections($document) as $coll) {
         /* If this is a top-level, atomic collection, its scheduled update
          * or deletion must be included in the document's update query.
          */
         if ($coll->getOwner() === $document) {
             $mapping = $coll->getMapping();
             if ($mapping['strategy'] !== "atomicSet" && $mapping['strategy'] !== "atomicSetArray") {
                 continue;
             }
             if ($this->uow->isCollectionScheduledForUpdate($coll)) {
                 $atomicCollUpdates[spl_object_hash($coll)] = $coll;
             } elseif ($this->uow->isCollectionScheduledForDeletion($coll)) {
                 $atomicCollDeletes[spl_object_hash($coll)] = $coll;
             }
             continue;
         }
         /* Otherwise, the collection is nested. Check if its top-most parent
          * is an atomic collection and include it for updating if so. This
          * is necessary because the atomic parent may not have directly
          * changed.
          */
         $parent = $coll->getOwner();
         while (null !== ($parentAssoc = $this->uow->getParentAssociation($parent))) {
             list($mapping, $parent, ) = $parentAssoc;
         }
         if (!isset($mapping['association']) || $mapping['association'] !== ClassMetadata::EMBED_MANY || $mapping['strategy'] !== 'atomicSet' && $mapping['strategy'] !== 'atomicSetArray') {
             continue;
         }
         $classMetadata = $this->dm->getClassMetadata(get_class($document));
         $parentColl = $classMetadata->getFieldValue($document, $mapping['fieldName']);
         /* It's possible that the atomic parent was independently scheduled
          * for deletion. In that case, updating nested data is unnecessary.
          */
         if (!$this->uow->isCollectionScheduledForDeletion($parentColl)) {
             $atomicCollUpdates[spl_object_hash($parentColl)] = $parentColl;
         }
     }
     foreach ($atomicCollUpdates as $coll) {
         $update = array_merge_recursive($update, $collPersister->prepareSetQuery($coll));
         /* Note: If the collection is only be handled because it's an atomic
          * parent of a scheduled child, the following calls are NOPs.
          */
         $this->uow->unscheduleCollectionUpdate($coll);
     }
     foreach ($atomicCollDeletes as $coll) {
         $update = array_merge_recursive($update, $collPersister->prepareDeleteQuery($coll));
         /* Note: We don't need to call unscheduleCollectionUpdate(), because
          * the collection should never have been added to $atomicCollDeletes
          * if it was independently scheduled for update.
          */
         $this->uow->unscheduleCollectionDeletion($coll);
     }
     return $update;
 }