Browse Source

Merge pull request #6077 from cakephp/3.0-associated-dirty-check

Only marking an association property as dirty if it changed
Mark Story 11 years ago
parent
commit
314ba31750
2 changed files with 48 additions and 3 deletions
  1. 12 1
      src/ORM/Marshaller.php
  2. 36 2
      tests/TestCase/ORM/MarshallerTest.php

+ 12 - 1
src/ORM/Marshaller.php

@@ -355,7 +355,7 @@ class Marshaller
 
         $errors = $this->_validate($data + $keys, $options, $isNew);
         $schema = $this->_table->schema();
-        $properties = [];
+        $properties = $marshalledAssocs = [];
         foreach ($data as $key => $value) {
             if (!empty($errors[$key])) {
                 continue;
@@ -367,6 +367,7 @@ class Marshaller
             if (isset($propertyMap[$key])) {
                 $assoc = $propertyMap[$key]['association'];
                 $value = $this->_mergeAssociation($original, $assoc, $value, $propertyMap[$key]);
+                $marshalledAssocs[$key] = true;
             } elseif ($columnType) {
                 $converter = Type::build($columnType);
                 $value = $converter->marshal($value);
@@ -384,12 +385,22 @@ class Marshaller
         if (!isset($options['fieldList'])) {
             $entity->set($properties);
             $entity->errors($errors);
+
+            foreach (array_keys($marshalledAssocs) as $field) {
+                if ($properties[$field] instanceof EntityInterface) {
+                    $entity->dirty($field, $properties[$field]->dirty());
+                }
+            }
             return $entity;
         }
 
         foreach ((array)$options['fieldList'] as $field) {
             if (array_key_exists($field, $properties)) {
                 $entity->set($field, $properties[$field]);
+                if ($properties[$field] instanceof EntityInterface &&
+                    isset($marshalledAssocs[$field])) {
+                    $entity->dirty($assoc, $properties[$field]->dirty());
+                }
             }
         }
 

+ 36 - 2
tests/TestCase/ORM/MarshallerTest.php

@@ -764,7 +764,7 @@ class MarshallerTest extends TestCase
             'password' => 'secret'
         ]);
         $entity = new Entity([
-            'tile' => 'My Title',
+            'title' => 'My Title',
             'user' => $user
         ]);
         $user->accessible('*', true);
@@ -794,7 +794,7 @@ class MarshallerTest extends TestCase
     public function testMergeCreateAssociation()
     {
         $entity = new Entity([
-            'tile' => 'My Title'
+            'title' => 'My Title'
         ]);
         $entity->accessible('*', true);
         $data = [
@@ -1970,4 +1970,38 @@ class MarshallerTest extends TestCase
         $this->assertEquals(1, $entity->tags[0]->_joinData->modified_by);
         $this->assertEquals(1, $entity->tags[1]->_joinData->modified_by);
     }
+
+    /**
+     * Tests that patching an association resulting in no changes, will
+     * not mark the parent entity as dirty
+     *
+     * @return void
+     */
+    public function testAssociationNoChanges()
+    {
+        $options = ['markClean' => true, 'isNew' => false];
+        $entity = new Entity([
+            'title' => 'My Title',
+            'user' => new Entity([
+                'username' => 'mark',
+                'password' => 'not a secret'
+            ], $options)
+        ], $options);
+
+        $data = [
+            'body' => 'My Content',
+            'user' => [
+                'username' => 'mark',
+                'password' => 'not a secret'
+            ]
+        ];
+        $marshall = new Marshaller($this->articles);
+        $marshall->merge($entity, $data, ['associated' => ['Users']]);
+        $this->assertEquals('My Content', $entity->body);
+        $this->assertInstanceOf('Cake\ORM\Entity', $entity->user);
+        $this->assertEquals('mark', $entity->user->username);
+        $this->assertEquals('not a secret', $entity->user->password);
+        $this->assertFalse($entity->dirty('user'));
+        $this->assertTrue($entity->user->isNew());
+    }
 }