Browse Source

Merge pull request #12397 from cakephp/issue-12373

Enable `_ids` to work when updating has many associations
Mark Story 7 years ago
parent
commit
25f4ff04c7
2 changed files with 62 additions and 0 deletions
  1. 11 0
      src/ORM/Marshaller.php
  2. 51 0
      tests/TestCase/ORM/MarshallerTest.php

+ 11 - 0
src/ORM/Marshaller.php

@@ -753,6 +753,17 @@ class Marshaller
             return $marshaller->_mergeBelongsToMany($original, $assoc, $value, (array)$options);
         }
 
+        if ($assoc->type() === Association::ONE_TO_MANY) {
+            $hasIds = array_key_exists('_ids', $value);
+            $onlyIds = array_key_exists('onlyIds', $options) && $options['onlyIds'];
+            if ($hasIds && is_array($value['_ids'])) {
+                return $this->_loadAssociatedByIds($assoc, $value['_ids']);
+            }
+            if ($hasIds || $onlyIds) {
+                return [];
+            }
+        }
+
         return $marshaller->mergeMany($original, $value, (array)$options);
     }
 

+ 51 - 0
tests/TestCase/ORM/MarshallerTest.php

@@ -1732,6 +1732,57 @@ class MarshallerTest extends TestCase
     }
 
     /**
+     * Tests that merging data to a hasMany association with _ids works.
+     *
+     * @return void
+     */
+    public function testMergeHasManyEntitiesFromIds()
+    {
+        $entity = $this->articles->get(1, ['contain' => ['Comments']]);
+        $this->assertNotEmpty($entity->comments);
+
+        $marshall = new Marshaller($this->articles);
+        $data = ['comments' => ['_ids' => [1, 2, 3]]];
+        $result = $marshall->merge($entity, $data, ['associated' => ['Comments']]);
+
+        $this->assertCount(3, $result->comments);
+        $this->assertTrue($result->isDirty('comments'), 'Updated prop should be dirty');
+        $this->assertInstanceOf(Entity::class, $result->comments[0]);
+        $this->assertEquals(1, $result->comments[0]->id);
+        $this->assertInstanceOf(Entity::class, $result->comments[1]);
+        $this->assertEquals(2, $result->comments[1]->id);
+        $this->assertInstanceOf(Entity::class, $result->comments[2]);
+        $this->assertEquals(3, $result->comments[2]->id);
+    }
+
+    /**
+     * Tests that merging data to a hasMany association using onlyIds restricts operations.
+     *
+     * @return void
+     */
+    public function testMergeHasManyEntitiesFromIdsOnlyIds()
+    {
+        $entity = $this->articles->get(1, ['contain' => ['Comments']]);
+        $this->assertNotEmpty($entity->comments);
+
+        $marshall = new Marshaller($this->articles);
+        $data = [
+            'comments' => [
+                '_ids' => [1],
+                [
+                    'comment' => 'Nope'
+                ]
+            ]
+        ];
+        $result = $marshall->merge($entity, $data, ['associated' => ['Comments' => ['onlyIds' => true]]]);
+
+        $this->assertCount(1, $result->comments);
+        $this->assertTrue($result->isDirty('comments'), 'Updated prop should be dirty');
+        $this->assertInstanceOf(Entity::class, $result->comments[0]);
+        $this->assertNotEquals('Nope', $result->comments[0]);
+    }
+
+    /**
      * Tests that merging data to an entity containing belongsToMany and _ids
      * will just overwrite the data
      *