Permalink
Browse files

[MODM-52] Fixing issue with computing changesets of nested embedded d…

…ocuments that are multiple levels deep
  • Loading branch information...
1 parent 485fbdf commit 3e71c6a6f99360d88c66043ff989d7671e2ded08 @jwage jwage committed Aug 18, 2010
@@ -207,6 +207,7 @@ public function update($document, array $options = array())
{
$id = $this->uow->getDocumentIdentifier($document);
$update = $this->prepareUpdateData($document);
+
if ( ! empty($update)) {
if ($this->dm->getEventManager()->hasListeners(ODMEvents::onUpdatePrepared)) {
$this->dm->getEventManager()->dispatchEvent(
@@ -418,6 +419,9 @@ public function prepareInsertData($document)
*/
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);
@@ -447,8 +451,13 @@ public function prepareUpdateData($document)
if ($old !== $new) {
$old = $old ? $old : array();
$new = $new ? $new : array();
- $deleteDiff = array_udiff_assoc($old, $new, function($a, $b) {return $a === $b ? 0 : 1; });
- $insertDiff = array_udiff_assoc($new, $old, function($a, $b) {return $a === $b ? 0 : 1;});
+ $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) {
@@ -323,6 +323,58 @@ public function getDocumentChangeSet($document)
return array();
}
+ public function getDocumentActualData($document)
+ {
+ $class = $this->dm->getClassMetadata(get_class($document));
+ $actualData = array();
+ foreach ($class->reflFields as $name => $refProp) {
+ $mapping = $class->fieldMappings[$name];
+
+ // Skip identifiers if custom ones are not allowed
+ if ($class->isIdentifier($name) && ! $class->getAllowCustomID()) {
+ continue;
+ }
+
+ $origValue = $class->getFieldValue($document, $mapping['fieldName']);
+
+ if (($class->isCollectionValuedReference($name) || $class->isCollectionValuedEmbed($name))
+ && $origValue !== null && ! ($origValue instanceof PersistentCollection)) {
+ // If $actualData[$name] is not a Collection then use an ArrayCollection.
+ if ( ! $origValue instanceof Collection) {
+ $value = new ArrayCollection($origValue);
+ } else {
+ $value = $origValue;
+ }
+
+ // Inject PersistentCollection
+ if ($class->isCollectionValuedReference($name)) {
+ $coll = new PersistentCollection($value, $this->dm);
+ } else {
+ $coll = new PersistentCollection($value);
+ }
+ $coll->setOwner($document, $mapping);
+ $coll->setDirty( ! $coll->isEmpty());
+ $class->reflFields[$name]->setValue($document, $coll);
+ }
+
+ if ($class->isCollectionValuedEmbed($name) && $origValue) {
+ $embeddedDocuments = $origValue;
+ $actualData[$name] = array();
+ foreach ($embeddedDocuments as $key => $embeddedDocument) {
+ $actualData[$name][$key] = $this->getDocumentActualData($embeddedDocument);
+ $actualData[$name][$key]['originalObject'] = $embeddedDocument;
+ }
+ } elseif ($class->isSingleValuedEmbed($name) && is_object($origValue)) {
+ $embeddedDocument = $origValue;
+ $actualData[$name] = $this->getDocumentActualData($embeddedDocument);
+ $actualData[$name]['originalObject'] = $embeddedDocument;
+ } else {
+ $actualData[$name] = $origValue;
+ }
+ }
+ return $actualData;
+ }
+
/**
* Computes the changes that happened to a single document.
*
@@ -355,41 +407,7 @@ public function computeChangeSet($parentDocument, Mapping\ClassMetadata $class,
}
$oid = spl_object_hash($document);
- $parentOid = spl_object_hash($parentDocument);
-
- $actualData = array();
- foreach ($class->reflFields as $name => $refProp) {
- $mapping = $class->fieldMappings[$name];
- if ( ! $class->isIdentifier($name) || $class->getAllowCustomID()) {
- $actualData[$name] = $class->getFieldValue($document, $mapping['fieldName']);
- }
- if (($class->isCollectionValuedReference($name) || $class->isCollectionValuedEmbed($name))
- && $actualData[$name] !== null && ! ($actualData[$name] instanceof PersistentCollection)) {
- // If $actualData[$name] is not a Collection then use an ArrayCollection.
- if ( ! $actualData[$name] instanceof Collection) {
- $actualData[$name] = new ArrayCollection($actualData[$name]);
- }
-
- // Inject PersistentCollection
- if ($class->isCollectionValuedReference($name)) {
- $coll = new PersistentCollection($actualData[$name], $this->dm);
- } else {
- $coll = new PersistentCollection($actualData[$name]);
- }
- $coll->setOwner($document, $mapping);
- $coll->setDirty( ! $coll->isEmpty());
- $class->reflFields[$name]->setValue($document, $coll);
- $actualData[$name] = $coll;
- } elseif ($class->isSingleValuedEmbed($name) && is_object($actualData[$name])) {
- $embeddedDocument = $actualData[$name];
- $embeddedMetadata = $this->dm->getClassMetadata(get_class($embeddedDocument));
- $actualData[$name] = array();
- foreach ($embeddedMetadata->fieldMappings as $mapping) {
- $actualData[$name][$mapping['fieldName']] = $embeddedMetadata->getFieldValue($embeddedDocument, $mapping['fieldName']);
- }
- $actualData[$name]['originalObject'] = $embeddedDocument;
- }
- }
+ $actualData = $this->getDocumentActualData($document);
if ( ! isset($this->originalDocumentData[$oid])) {
// Document is either NEW or MANAGED but not yet fully persisted (only has an id).
@@ -0,0 +1,58 @@
+<?php
+
+namespace Doctrine\ODM\MongoDB\Tests\Functional\Ticket;
+
+require_once __DIR__ . '/../../../../../../TestInit.php';
+
+class MODM52Test extends \Doctrine\ODM\MongoDB\Tests\BaseTest
+{
+ public function testTest()
+ {
+ $emb = new MODM52Embedded(array(new MODM52Embedded(), new MODM52Embedded()));
+ $doc = new MODM52Doc(array($emb));
+
+ $this->dm->persist($doc);
+ $this->dm->flush(array('safe' => true));
+ $this->dm->refresh($doc);
+
+ // change nested embedded collection:
+ $doc->getItem(0)->removeItem(1);
+ $before = count($doc->getItem(0)->getItems());
+
+ $this->dm->persist($doc);
+ $this->dm->flush();
+ $this->dm->refresh($doc);
+
+ $after = count($doc->getItem(0)->getItems());
+ $this->assertEquals(1, $before);
+ $this->assertEquals(1, $after);
+ }
+}
+
+/**
+ * @MappedSuperClass
+ */
+class MODM52Container
+{
+ /** @String */
+ protected $tmp = 'ensureSaved';
+
+ /** @EmbedMany(targetDocument="MODM52Embedded", cascade="all", strategy="set") */
+ protected $items = array();
+
+ function __construct($items = null) {if($items) $this->items = $items;}
+ function getItems() {return $this->items;}
+ function getItem($index) {return $this->items[$index];}
+ function removeItem($i) {unset($this->items[$i]);}
+}
+
+/** @EmbeddedDocument */
+class MODM52Embedded extends MODM52Container
+{}
+
+/** @Document(db="tests", collection="tests") */
+class MODM52Doc extends MODM52Container
+{
+ /** @Id */
+ protected $id;
+}

0 comments on commit 3e71c6a

Please sign in to comment.