INTERNAL:
Gets PersistentCollections that are scheduled to update and related to $document
public getScheduledCollections ( object $document ) : array | ||
$document | object | |
Résultat | array |
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; }
private function handleCollections($document, $options) { // Collection deletions (deletions of complete collections) foreach ($this->uow->getScheduledCollections($document) as $coll) { if ($this->uow->isCollectionScheduledForDeletion($coll)) { $this->cp->delete($coll, $options); } } // Collection updates (deleteRows, updateRows, insertRows) foreach ($this->uow->getScheduledCollections($document) as $coll) { if ($this->uow->isCollectionScheduledForUpdate($coll)) { $this->cp->update($coll, $options); } } // Take new snapshots from visited collections foreach ($this->uow->getVisitedCollections($document) as $coll) { $coll->takeSnapshot(); } }
/** * Prepares the update query to update a given document object in mongodb. * * @param object $document * @return array $updateData */ public function prepareUpdateData($document) { $class = $this->dm->getClassMetadata(get_class($document)); $changeset = $this->uow->getDocumentChangeSet($document); $updateData = array(); foreach ($changeset as $fieldName => $change) { $mapping = $class->fieldMappings[$fieldName]; // skip non embedded document identifiers if (!$class->isEmbeddedDocument && !empty($mapping['id'])) { continue; } list($old, $new) = $change; // @Inc if ($mapping['type'] === 'increment') { if ($new === null) { if ($mapping['nullable'] === true) { $updateData['$set'][$mapping['name']] = null; } else { $updateData['$unset'][$mapping['name']] = true; } } elseif ($new >= $old) { $updateData['$inc'][$mapping['name']] = $new - $old; } else { $updateData['$inc'][$mapping['name']] = ($old - $new) * -1; } // @Field, @String, @Date, etc. } elseif (!isset($mapping['association'])) { if (isset($new) || $mapping['nullable'] === true) { $updateData['$set'][$mapping['name']] = is_null($new) ? null : Type::getType($mapping['type'])->convertToDatabaseValue($new); } else { $updateData['$unset'][$mapping['name']] = true; } // @EmbedOne } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::EMBED_ONE) { // If we have a new embedded document then lets set the whole thing if ($new && $this->uow->isScheduledForInsert($new)) { $updateData['$set'][$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new); // If we don't have a new value then lets unset the embedded document } elseif (!$new) { $updateData['$unset'][$mapping['name']] = true; // Update existing embedded document } else { $update = $this->prepareUpdateData($new); foreach ($update as $cmd => $values) { foreach ($values as $key => $value) { $updateData[$cmd][$mapping['name'] . '.' . $key] = $value; } } } // @ReferenceMany, @EmbedMany } elseif (isset($mapping['association']) && $mapping['type'] === 'many' && $new) { if (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForUpdate($new)) { $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true); } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($new)) { $updateData['$unset'][$mapping['name']] = true; $this->uow->unscheduleCollectionDeletion($new); } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($old)) { $updateData['$unset'][$mapping['name']] = true; $this->uow->unscheduleCollectionDeletion($old); } elseif ($mapping['association'] === ClassMetadata::EMBED_MANY) { foreach ($new as $key => $embeddedDoc) { if (!$this->uow->isScheduledForInsert($embeddedDoc)) { $update = $this->prepareUpdateData($embeddedDoc); foreach ($update as $cmd => $values) { foreach ($values as $name => $value) { $updateData[$cmd][$mapping['name'] . '.' . $key . '.' . $name] = $value; } } } } } // @ReferenceOne } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE && $mapping['isOwningSide']) { if (isset($new) || $mapping['nullable'] === true) { $updateData['$set'][$mapping['name']] = is_null($new) ? null : $this->prepareReferencedDocumentValue($mapping, $new); } else { $updateData['$unset'][$mapping['name']] = true; } } } // collections that aren't dirty but could be subject to update are // excluded from change set, let's go through them now foreach ($this->uow->getScheduledCollections($document) as $coll) { $mapping = $coll->getMapping(); if (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForUpdate($coll)) { $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($coll, true); } elseif (CollectionHelper::isAtomic($mapping['strategy']) && $this->uow->isCollectionScheduledForDeletion($coll)) { $updateData['$unset'][$mapping['name']] = true; $this->uow->unscheduleCollectionDeletion($coll); } // @ReferenceMany is handled by CollectionPersister } return $updateData; }
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; }