Skip to content
This repository
Browse code

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

…ocuments that are multiple levels deep
  • Loading branch information...
commit 3e71c6a6f99360d88c66043ff989d7671e2ded08 1 parent 485fbdf
Jonathan H. Wage authored August 18, 2010
13  lib/Doctrine/ODM/MongoDB/Persisters/BasicDocumentPersister.php
@@ -207,6 +207,7 @@ public function update($document, array $options = array())
207 207
     {
208 208
         $id = $this->uow->getDocumentIdentifier($document);
209 209
         $update = $this->prepareUpdateData($document);
  210
+
210 211
         if ( ! empty($update)) {
211 212
             if ($this->dm->getEventManager()->hasListeners(ODMEvents::onUpdatePrepared)) {
212 213
                 $this->dm->getEventManager()->dispatchEvent(
@@ -418,6 +419,9 @@ public function prepareInsertData($document)
418 419
      */
419 420
     public function prepareUpdateData($document)
420 421
     {
  422
+        if (is_array($document) && isset($document['originalObject'])) {
  423
+            $document = $document['originalObject'];
  424
+        }
421 425
         $oid = spl_object_hash($document);
422 426
         $class = $this->dm->getClassMetadata(get_class($document));
423 427
         $changeset = $this->uow->getDocumentChangeSet($document);
@@ -447,8 +451,13 @@ public function prepareUpdateData($document)
447 451
                     if ($old !== $new) {
448 452
                         $old = $old ? $old : array();
449 453
                         $new = $new ? $new : array();
450  
-                        $deleteDiff = array_udiff_assoc($old, $new, function($a, $b) {return $a === $b ? 0 : 1; });
451  
-                        $insertDiff = array_udiff_assoc($new, $old, function($a, $b) {return $a === $b ? 0 : 1;});
  454
+                        $compare = function($a, $b) {
  455
+                            $a = is_array($a) && isset($a['originalObject']) ? $a['originalObject'] : $a;
  456
+                            $b = is_array($b) && isset($b['originalObject']) ? $b['originalObject'] : $b;
  457
+                            return $a === $b ? 0 : 1;
  458
+                        };
  459
+                        $deleteDiff = array_udiff_assoc($old, $new, $compare);
  460
+                        $insertDiff = array_udiff_assoc($new, $old, $compare);
452 461
 
453 462
                         // insert diff
454 463
                         if ($insertDiff) {
88  lib/Doctrine/ODM/MongoDB/UnitOfWork.php
@@ -323,6 +323,58 @@ public function getDocumentChangeSet($document)
323 323
         return array();
324 324
     }
325 325
 
  326
+    public function getDocumentActualData($document)
  327
+    {
  328
+        $class = $this->dm->getClassMetadata(get_class($document));
  329
+        $actualData = array();
  330
+        foreach ($class->reflFields as $name => $refProp) {
  331
+            $mapping = $class->fieldMappings[$name];
  332
+            
  333
+            // Skip identifiers if custom ones are not allowed
  334
+            if ($class->isIdentifier($name) && ! $class->getAllowCustomID()) {
  335
+                continue;
  336
+            }
  337
+
  338
+            $origValue = $class->getFieldValue($document, $mapping['fieldName']);
  339
+
  340
+            if (($class->isCollectionValuedReference($name) || $class->isCollectionValuedEmbed($name))
  341
+                    && $origValue !== null && ! ($origValue instanceof PersistentCollection)) {
  342
+                // If $actualData[$name] is not a Collection then use an ArrayCollection.
  343
+                if ( ! $origValue instanceof Collection) {
  344
+                    $value = new ArrayCollection($origValue);
  345
+                } else {
  346
+                    $value = $origValue;
  347
+                }
  348
+
  349
+                // Inject PersistentCollection
  350
+                if ($class->isCollectionValuedReference($name)) {
  351
+                    $coll = new PersistentCollection($value, $this->dm);
  352
+                } else {
  353
+                    $coll = new PersistentCollection($value);
  354
+                }
  355
+                $coll->setOwner($document, $mapping);
  356
+                $coll->setDirty( ! $coll->isEmpty());
  357
+                $class->reflFields[$name]->setValue($document, $coll);
  358
+            }
  359
+
  360
+            if ($class->isCollectionValuedEmbed($name) && $origValue) {
  361
+                $embeddedDocuments = $origValue;
  362
+                $actualData[$name] = array();
  363
+                foreach ($embeddedDocuments as $key => $embeddedDocument) {
  364
+                    $actualData[$name][$key] = $this->getDocumentActualData($embeddedDocument);
  365
+                    $actualData[$name][$key]['originalObject'] = $embeddedDocument;
  366
+                }
  367
+            } elseif ($class->isSingleValuedEmbed($name) && is_object($origValue)) {
  368
+                $embeddedDocument = $origValue;
  369
+                $actualData[$name] = $this->getDocumentActualData($embeddedDocument);
  370
+                $actualData[$name]['originalObject'] = $embeddedDocument;
  371
+            } else {
  372
+                $actualData[$name] = $origValue;
  373
+            }
  374
+        }
  375
+        return $actualData;
  376
+    }
  377
+
326 378
     /**
327 379
      * Computes the changes that happened to a single document.
328 380
      *
@@ -355,41 +407,7 @@ public function computeChangeSet($parentDocument, Mapping\ClassMetadata $class,
355 407
         }
356 408
         
357 409
         $oid = spl_object_hash($document);
358  
-        $parentOid = spl_object_hash($parentDocument);
359  
-
360  
-        $actualData = array();
361  
-        foreach ($class->reflFields as $name => $refProp) {
362  
-            $mapping = $class->fieldMappings[$name];
363  
-            if ( ! $class->isIdentifier($name) || $class->getAllowCustomID()) {
364  
-                $actualData[$name] = $class->getFieldValue($document, $mapping['fieldName']);
365  
-            }
366  
-            if (($class->isCollectionValuedReference($name) || $class->isCollectionValuedEmbed($name))
367  
-                    && $actualData[$name] !== null && ! ($actualData[$name] instanceof PersistentCollection)) {
368  
-                // If $actualData[$name] is not a Collection then use an ArrayCollection.
369  
-                if ( ! $actualData[$name] instanceof Collection) {
370  
-                    $actualData[$name] = new ArrayCollection($actualData[$name]);
371  
-                }
372  
-
373  
-                // Inject PersistentCollection
374  
-                if ($class->isCollectionValuedReference($name)) {
375  
-                    $coll = new PersistentCollection($actualData[$name], $this->dm);
376  
-                } else {
377  
-                    $coll = new PersistentCollection($actualData[$name]);
378  
-                }
379  
-                $coll->setOwner($document, $mapping);
380  
-                $coll->setDirty( ! $coll->isEmpty());
381  
-                $class->reflFields[$name]->setValue($document, $coll);
382  
-                $actualData[$name] = $coll;
383  
-            } elseif ($class->isSingleValuedEmbed($name) && is_object($actualData[$name])) {
384  
-                $embeddedDocument = $actualData[$name];
385  
-                $embeddedMetadata = $this->dm->getClassMetadata(get_class($embeddedDocument));
386  
-                $actualData[$name] = array();
387  
-                foreach ($embeddedMetadata->fieldMappings as $mapping) {
388  
-                    $actualData[$name][$mapping['fieldName']] = $embeddedMetadata->getFieldValue($embeddedDocument, $mapping['fieldName']);
389  
-                }
390  
-                $actualData[$name]['originalObject'] = $embeddedDocument;
391  
-            }
392  
-        }
  410
+        $actualData = $this->getDocumentActualData($document);
393 411
 
394 412
         if ( ! isset($this->originalDocumentData[$oid])) {
395 413
             // Document is either NEW or MANAGED but not yet fully persisted (only has an id).
58  tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/MODM52Test.php
... ...
@@ -0,0 +1,58 @@
  1
+<?php
  2
+
  3
+namespace Doctrine\ODM\MongoDB\Tests\Functional\Ticket;
  4
+
  5
+require_once __DIR__ . '/../../../../../../TestInit.php';
  6
+
  7
+class MODM52Test extends \Doctrine\ODM\MongoDB\Tests\BaseTest
  8
+{
  9
+    public function testTest()
  10
+    {
  11
+        $emb = new MODM52Embedded(array(new MODM52Embedded(), new MODM52Embedded()));
  12
+        $doc = new MODM52Doc(array($emb));
  13
+
  14
+        $this->dm->persist($doc);
  15
+        $this->dm->flush(array('safe' => true));
  16
+        $this->dm->refresh($doc);
  17
+
  18
+        // change nested embedded collection:
  19
+        $doc->getItem(0)->removeItem(1);
  20
+        $before = count($doc->getItem(0)->getItems());
  21
+
  22
+        $this->dm->persist($doc);
  23
+        $this->dm->flush();
  24
+        $this->dm->refresh($doc);
  25
+
  26
+        $after = count($doc->getItem(0)->getItems());
  27
+        $this->assertEquals(1, $before);
  28
+        $this->assertEquals(1, $after);
  29
+    }
  30
+}
  31
+
  32
+/**
  33
+ * @MappedSuperClass
  34
+ */
  35
+class MODM52Container
  36
+{
  37
+    /** @String */
  38
+    protected $tmp = 'ensureSaved';
  39
+
  40
+    /** @EmbedMany(targetDocument="MODM52Embedded", cascade="all", strategy="set") */
  41
+    protected $items = array();
  42
+
  43
+    function __construct($items = null) {if($items) $this->items = $items;}
  44
+    function getItems() {return $this->items;}
  45
+    function getItem($index) {return $this->items[$index];}
  46
+    function removeItem($i) {unset($this->items[$i]);}
  47
+}
  48
+
  49
+/** @EmbeddedDocument */
  50
+class MODM52Embedded extends MODM52Container
  51
+{}
  52
+
  53
+/** @Document(db="tests", collection="tests") */
  54
+class MODM52Doc extends MODM52Container
  55
+{
  56
+    /** @Id */
  57
+    protected $id;
  58
+}

0 notes on commit 3e71c6a

Please sign in to comment.
Something went wrong with that request. Please try again.