getDocumentChangeSet() public method

Gets the changeset for a document.
public getDocumentChangeSet ( object $document ) : array
$document object
return array array('property' => array(0 => mixed|null, 1 => mixed|null))
Esempio n. 1
0
 /**
  * Prepares the update query to upsert a given document object in mongodb.
  *
  * @param object $document
  * @return array $updateData
  */
 public function prepareUpsertData($document)
 {
     $class = $this->dm->getClassMetadata(get_class($document));
     $changeset = $this->uow->getDocumentChangeSet($document);
     $updateData = array();
     foreach ($changeset as $fieldName => $change) {
         $mapping = $class->fieldMappings[$fieldName];
         /* Do nothing for embed-many or reference-many collections. If it
          * uses an atomic strategy, the data will be included when preparing
          * the atomic query in DocumentPersister::executeUpserts(). Other
          * strategies will be handled by CollectionPersister.
          */
         if ($mapping['type'] === ClassMetadata::MANY) {
             continue;
         }
         list($old, $new) = $change;
         // @Inc
         if ($mapping['type'] === 'increment') {
             if ($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);
             }
             // @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 do nothing on upsert
             } elseif (!$new) {
                 // Update existing embedded document
             } else {
                 $update = $this->prepareUpsertData($new);
                 foreach ($update as $cmd => $values) {
                     foreach ($values as $key => $value) {
                         $updateData[$cmd][$mapping['name'] . '.' . $key] = $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);
             }
         }
         // @EmbedMany and @ReferenceMany are handled by CollectionPersister
     }
     // add discriminator if the class has one
     if (isset($class->discriminatorField)) {
         $updateData['$set'][$class->discriminatorField] = isset($class->discriminatorValue) ? $class->discriminatorValue : $class->name;
     }
     return $updateData;
 }
 /**
  * Prepares the update query to upsert a given document object in mongodb.
  *
  * @param object $document
  * @return array $updateData
  */
 public function prepareUpsertData($document)
 {
     $class = $this->dm->getClassMetadata(get_class($document));
     $changeset = $this->uow->getDocumentChangeSet($document);
     $updateData = array();
     foreach ($changeset as $fieldName => $change) {
         $mapping = $class->fieldMappings[$fieldName];
         list($old, $new) = $change;
         // @Inc
         if ($mapping['type'] === 'increment') {
             if ($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);
             }
             // @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 do nothing on upsert
             } elseif (!$new) {
                 // Update existing embedded document
             } else {
                 $update = $this->prepareUpsertData($new);
                 foreach ($update as $cmd => $values) {
                     foreach ($values as $key => $value) {
                         $updateData[$cmd][$mapping['name'] . '.' . $key] = $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);
             }
             // @ReferenceMany, @EmbedMany
         } elseif ($mapping['type'] === ClassMetadata::MANY && !$mapping['isInverseSide'] && $new instanceof PersistentCollection && $new->isDirty() && CollectionHelper::isAtomic($mapping['strategy'])) {
             $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true);
         }
         // @EmbedMany and @ReferenceMany are handled by CollectionPersister
     }
     // add discriminator if the class has one
     if (isset($class->discriminatorField)) {
         $updateData['$set'][$class->discriminatorField] = isset($class->discriminatorValue) ? $class->discriminatorValue : $class->name;
     }
     return $updateData;
 }
Esempio n. 3
0
 /**
  * If the document is new, ignore shard key field value, otherwise throw an exception.
  * Also, shard key field should be present in actual document data.
  *
  * @param object $document
  * @param string $shardKeyField
  * @param array  $actualDocumentData
  *
  * @throws MongoDBException
  */
 private function guardMissingShardKey($document, $shardKeyField, $actualDocumentData)
 {
     $dcs = $this->uow->getDocumentChangeSet($document);
     $isUpdate = $this->uow->isScheduledForUpdate($document);
     $fieldMapping = $this->class->getFieldMappingByDbFieldName($shardKeyField);
     $fieldName = $fieldMapping['fieldName'];
     if ($isUpdate && isset($dcs[$fieldName]) && $dcs[$fieldName][0] != $dcs[$fieldName][1]) {
         throw MongoDBException::shardKeyFieldCannotBeChanged($shardKeyField, $this->class->getName());
     }
     if (!isset($actualDocumentData[$fieldName])) {
         throw MongoDBException::shardKeyFieldMissing($shardKeyField, $this->class->getName());
     }
 }
 /**
  * Cascades the postUpdate and postPersist events to embedded documents.
  *
  * @param ClassMetadata $class
  * @param object $document
  */
 private function cascadePostUpdate(ClassMetadata $class, $document)
 {
     foreach ($class->getEmbeddedFieldsMappings() as $mapping) {
         $value = $class->reflFields[$mapping['fieldName']]->getValue($document);
         if ($value === null) {
             continue;
         }
         $values = $mapping['type'] === ClassMetadata::ONE ? array($value) : $value;
         foreach ($values as $entry) {
             if (empty($this->uow->getDocumentChangeSet($entry)) && !$this->uow->hasScheduledCollections($entry)) {
                 continue;
             }
             $entryClass = $this->dm->getClassMetadata(get_class($entry));
             $event = $this->uow->isScheduledForInsert($entry) ? Events::postPersist : Events::postUpdate;
             $entryClass->invokeLifecycleCallbacks($event, $entry, array(new LifecycleEventArgs($entry, $this->dm)));
             $this->evm->dispatchEvent($event, new LifecycleEventArgs($entry, $this->dm));
             $this->cascadePostUpdate($entryClass, $entry);
         }
     }
 }
 /**
  * @param $document
  * @return array
  * @throws MongoDBException
  */
 public function getShardKeyQuery($document)
 {
     $shardKeysQueryPart = array();
     $dcs = $this->uow->getDocumentChangeSet($document);
     $data = $this->uow->getDocumentActualData($document);
     $md = $this->dm->getMetadataFactory()->getMetadataFor(get_class($document));
     $keys = $md->shardKeys;
     $fieldMappings = $this->dm->getClassMetadata(get_class($document))->fieldMappings;
     foreach ($keys as $key) {
         if ($key !== 'id') {
             $queryKey = $fieldMappings[$key]['name'];
         } else {
             $queryKey = '_id';
         }
         //If the document is new, we can ignore shard key value, otherwise throw exception
         $isUpdate = $this->uow->isScheduledForUpdate($document);
         if ($isUpdate && isset($dcs[$key]) && $dcs[$key][0] !== null && $dcs[$key][0] != $dcs[$key][1] && (!isset($options['upsert']) || isset($options['upsert']) && $options['upsert'] === true)) {
             throw MongoDBException::shardKeyChange($key);
         }
         if (!isset($data[$key])) {
             throw MongoDBException::shardKeyMissing($key);
         }
         $new = $data[$key];
         $mapping = $fieldMappings[$key];
         // @Field, @String, @Date, etc.
         if (!isset($mapping['association'])) {
             if (isset($new) || $mapping['nullable'] === true) {
                 $shardKeysQueryPart[$queryKey] = is_null($new) ? null : Type::getType($mapping['type'])->convertToDatabaseValue($new);
             }
             // @ReferenceOne
         } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_ONE && $mapping['isOwningSide']) {
             if (isset($new) || $mapping['nullable'] === true) {
                 $shardKeysQueryPart[$queryKey] = is_null($new) ? null : $this->pb->prepareReferencedDocumentValue($mapping, $new);
             }
             // @ReferenceMany
         } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_MANY) {
             // Do nothing right now
         }
     }
     return $shardKeysQueryPart;
 }
 /**
  * Prepares update array for document, using atomic operators
  *
  * @param mixed $document
  * @return array
  */
 public function prepareUpdateData($document)
 {
     $oid = spl_object_hash($document);
     $changeset = $this->_uow->getDocumentChangeSet($document);
     $result = array();
     foreach ($this->_class->fieldMappings as $mapping) {
         if (isset($mapping['notSaved']) && $mapping['notSaved'] === true) {
             continue;
         }
         $old = isset($changeset[$mapping['fieldName']][0]) ? $changeset[$mapping['fieldName']][0] : null;
         $new = isset($changeset[$mapping['fieldName']][1]) ? $changeset[$mapping['fieldName']][1] : null;
         $new = $this->_prepareValue($mapping, $new);
         $old = $this->_prepareValue($mapping, $old);
         if ($this->_class->isIdentifier($mapping['fieldName']) && !$this->_equals($new, $old)) {
             throw MongoDBException::identifierCannotBeUpdated();
         }
         if ($mapping['type'] === 'many' || $mapping['type'] === 'collection') {
             $this->_addArrayUpdateAtomicOperator($mapping, (array) $new, (array) $old, $result);
         } else {
             $this->_addFieldUpdateAtomicOperator($mapping, $new, $old, $result);
         }
     }
     return $result;
 }
Esempio n. 7
0
 /**
  * Prepares the update query to update a given document object in mongodb.
  *
  * @param object $document
  * @return array $updateData
  */
 public function prepareUpdateData($document)
 {
     $oid = spl_object_hash($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 not saved fields
         if (isset($mapping['notSaved']) && $mapping['notSaved'] === true) {
             continue;
         }
         // Skip version and lock fields
         if (isset($mapping['version']) || isset($mapping['lock'])) {
             continue;
         }
         list($old, $new) = $change;
         // @Inc
         if ($mapping['type'] === 'increment') {
             if ($new >= $old) {
                 $updateData[$this->cmd . 'inc'][$mapping['name']] = $new - $old;
             } else {
                 $updateData[$this->cmd . 'inc'][$mapping['name']] = ($old - $new) * -1;
             }
             // @Field, @String, @Date, etc.
         } elseif (!isset($mapping['association'])) {
             if (isset($new) || $mapping['nullable'] === true) {
                 $updateData[$this->cmd . 'set'][$mapping['name']] = Type::getType($mapping['type'])->convertToDatabaseValue($new);
             } else {
                 $updateData[$this->cmd . '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[$this->cmd . 'set'][$mapping['name']] = $this->prepareEmbeddedDocumentValue($mapping, $new);
                 // If we don't have a new value then lets unset the embedded document
             } elseif (!$new) {
                 $updateData[$this->cmd . '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;
                     }
                 }
             }
             // @EmbedMany
         } elseif (isset($mapping['association']) && $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[$this->cmd . 'set'][$mapping['name']] = $this->prepareReferencedDocumentValue($mapping, $new);
             } else {
                 $updateData[$this->cmd . 'unset'][$mapping['name']] = true;
             }
             // @ReferenceMany
         } elseif (isset($mapping['association']) && $mapping['association'] === ClassMetadata::REFERENCE_MANY) {
             // Do nothing right now
         }
     }
     return $updateData;
 }
 /**
  * Prepares update array for document, using atomic operators
  *
  * @param mixed $document
  * @return array
  */
 public function prepareUpdateData($document)
 {
     if (is_array($document) && isset($document['originalObject'])) {
         $document = $document['originalObject'];
     }
     $oid = spl_object_hash($document);
     $class = $this->dm->getClassMetadata(get_class($document));
     $changeset = $this->uow->getDocumentChangeSet($document);
     $result = array();
     foreach ($class->fieldMappings as $mapping) {
         if (isset($mapping['notSaved']) && $mapping['notSaved'] === true) {
             continue;
         }
         $old = isset($changeset[$mapping['fieldName']][0]) ? $changeset[$mapping['fieldName']][0] : null;
         $new = isset($changeset[$mapping['fieldName']][1]) ? $changeset[$mapping['fieldName']][1] : null;
         if ($mapping['type'] === 'many' || $mapping['type'] === 'collection') {
             if ($mapping['strategy'] === 'pushPull') {
                 if (isset($mapping['embedded']) && $new) {
                     foreach ($new as $k => $v) {
                         if (!isset($old[$k])) {
                             continue;
                         }
                         $update = $this->prepareUpdateData($v);
                         foreach ($update as $cmd => $values) {
                             foreach ($values as $key => $value) {
                                 $result[$cmd][$mapping['name'] . '.' . $k . '.' . $key] = $value;
                             }
                         }
                     }
                 }
                 if ($old !== $new) {
                     $old = $old ? $old : array();
                     $new = $new ? $new : array();
                     $compare = function ($a, $b) {
                         $a = is_array($a) && isset($a['originalObject']) ? $a['originalObject'] : $a;
                         $b = is_array($b) && isset($b['originalObject']) ? $b['originalObject'] : $b;
                         return $a === $b ? 0 : 1;
                     };
                     $deleteDiff = array_udiff_assoc($old, $new, $compare);
                     $insertDiff = array_udiff_assoc($new, $old, $compare);
                     // insert diff
                     if ($insertDiff) {
                         $result[$this->cmd . 'pushAll'][$mapping['name']] = $this->prepareValue($mapping, $insertDiff);
                     }
                     // delete diff
                     if ($deleteDiff) {
                         $result[$this->cmd . 'pullAll'][$mapping['name']] = $this->prepareValue($mapping, $deleteDiff);
                     }
                 }
             } elseif ($mapping['strategy'] === 'set') {
                 if ($old !== $new) {
                     $new = $this->prepareValue($mapping, $new);
                     $result[$this->cmd . 'set'][$mapping['name']] = $new;
                 }
             }
         } else {
             if ($old !== $new) {
                 if ($mapping['type'] === 'increment') {
                     $new = $this->prepareValue($mapping, $new);
                     $old = $this->prepareValue($mapping, $old);
                     if ($new >= $old) {
                         $result[$this->cmd . 'inc'][$mapping['name']] = $new - $old;
                     } else {
                         $result[$this->cmd . 'inc'][$mapping['name']] = ($old - $new) * -1;
                     }
                 } else {
                     // Single embedded
                     if (isset($mapping['embedded']) && $mapping['type'] === 'one') {
                         // If we didn't have a value before and now we do
                         if (!$old && $new) {
                             $new = $this->prepareValue($mapping, $new);
                             if (isset($new) || $mapping['nullable'] === true) {
                                 $result[$this->cmd . 'set'][$mapping['name']] = $new;
                             }
                             // If we had an old value before and it has changed
                         } elseif ($old && $new) {
                             $embeddedDocument = $class->getFieldValue($document, $mapping['fieldName']);
                             $update = $this->prepareUpdateData($embeddedDocument);
                             foreach ($update as $cmd => $values) {
                                 foreach ($values as $key => $value) {
                                     $result[$cmd][$mapping['name'] . '.' . $key] = $value;
                                 }
                             }
                         }
                         // $set all other fields
                     } else {
                         $new = $this->prepareValue($mapping, $new);
                         if (isset($new) || $mapping['nullable'] === true) {
                             $result[$this->cmd . 'set'][$mapping['name']] = $new;
                         } else {
                             $result[$this->cmd . 'unset'][$mapping['name']] = true;
                         }
                     }
                 }
             }
         }
     }
     return $result;
 }
 /**
  * @param <type> $document
  * @override
  */
 public function getDocumentChangeSet($document)
 {
     $oid = spl_object_hash($document);
     return isset($this->_mockDataChangeSets[$oid]) ? $this->_mockDataChangeSets[$oid] : parent::getDocumentChangeSet($document);
 }
Esempio n. 10
0
 /**
  * Get the object changeset from a UnitOfWork
  *
  * @param UnitOfWork $uow
  * @param Object $object
  * @return array
  */
 public function getObjectChangeSet(UnitOfWork $uow, $object)
 {
     return $uow->getDocumentChangeSet($object);
 }
    /**
     * Prepares update array for document, using atomic operators
     *
     * @param mixed $document
     * @return array
     */
    public function prepareUpdateData($document)
    {
        $oid = spl_object_hash($document);
        $class = $this->dm->getClassMetadata(get_class($document));
        $changeset = $this->uow->getDocumentChangeSet($document);
        $result = array();
        foreach ($changeset as $fieldName => $change) {
            $mapping = $class->fieldMappings[$fieldName];
            // many references are persisted with CollectionPersister later
            if (isset($mapping['reference']) && $mapping['type'] === 'many') {
                continue;
            }
            // skip not saved fields
            if (isset($mapping['notSaved']) && $mapping['notSaved'] === true) {
                continue;
            }
            // Skip version and lock fields
            if (isset($mapping['version']) || isset($mapping['lock'])) {
                continue;
            }

            list($old, $new) = $change;

            // Build query to persist updates to an embedded one association
            if (isset($mapping['embedded']) && $mapping['type'] === 'one') {
                // If we have a new embedded document then lets set the whole thing
                if ($new && $this->uow->isScheduledForInsert($new)) {
                    $result[$this->cmd . 'set'][$mapping['name']] = $this->prepareEmbeddedDocValue($mapping, $new);
                // If we don't have a new value then lets unset the embedded document
                } else if ( ! $new) {
                    $result[$this->cmd . 'unset'][$mapping['name']] = true;
                // Update existing embedded document
                } else {
                    $update = $this->prepareUpdateData($new);
                    foreach ($update as $cmd => $values) {
                        foreach ($values as $key => $value) {
                            $result[$cmd][$mapping['name'] . '.' . $key] = $value;
                        }
                    }
                }
            // Build query to persist updates to an embedded many association
            } else if (isset($mapping['embedded']) && $mapping['type'] === '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) {
                                $result[$cmd][$mapping['name'] . '.' . $key . '.' . $name] = $value;
                            }
                        }
                    }
                }
            // Prepare increment type values
            } else if ($mapping['type'] === 'increment') {
                if ($new >= $old) {
                    $result[$this->cmd . 'inc'][$mapping['name']] = $new - $old;
                } else {
                    $result[$this->cmd . 'inc'][$mapping['name']] = ($old - $new) * -1;
                }
            // Persist all other types using $set and $unset
            } else {
                if (isset($new) || $mapping['nullable'] === true) {
                    $new = $this->prepareValue($mapping, $new);
                    $result[$this->cmd . 'set'][$mapping['name']] = $new;
                } else {
                    $result[$this->cmd . 'unset'][$mapping['name']] = true;
                }
            }
        }
        return $result;
    }