diff --git a/src/ORM/Marshaller.php b/src/ORM/Marshaller.php index 8ad2b64ba2f..00c3736209e 100644 --- a/src/ORM/Marshaller.php +++ b/src/ORM/Marshaller.php @@ -243,7 +243,9 @@ public function merge(EntityInterface $entity, array $data, $include = []) { public function mergeMany($entities, array $data, $include = []) { $primary = (array)$this->_table->primaryKey(); - $indexed = (new Collection($data))->indexBy($primary[0]); + $indexed = (new Collection($data))->groupBy($primary[0])->toArray(); + $new = [$indexed[null]]; + unset($indexed[null]); $output = []; foreach ($entities as $entity) { @@ -251,12 +253,14 @@ public function mergeMany($entities, array $data, $include = []) { if ($key === null || !isset($indexed[$key])) { continue; } - $output[] = $this->merge($entity, $indexed[$key], $include); + $output[] = $this->merge($entity, $indexed[$key][0], $include); unset($indexed[$key]); } - foreach ($indexed as $record) { - $output[] = $this->one($record, $include); + foreach (array_merge($indexed, $new) as $record) { + foreach ($record as $value) { + $output[] = $this->one($value, $include); + } } return $output; } diff --git a/tests/TestCase/ORM/MarshallerTest.php b/tests/TestCase/ORM/MarshallerTest.php index 5a63ab53e82..1928dc29727 100644 --- a/tests/TestCase/ORM/MarshallerTest.php +++ b/tests/TestCase/ORM/MarshallerTest.php @@ -568,4 +568,118 @@ public function testMergeDirty() { $this->assertTrue($entity->dirty('crazy')); } +/** + * Tests merging data into an associated entity + * + * @return void + */ + public function testMergeWithSingleAssociation() { + $user = new Entity([ + 'username' => 'mark', + 'password' => 'secret' + ]); + $entity = new Entity([ + 'tile' => 'My Title', + 'user' => $user + ]); + $user->accessible('*', true); + $entity->accessible('*', true); + + $data = [ + 'body' => 'My Content', + 'user' => [ + 'password' => 'not a secret' + ] + ]; + $marshall = new Marshaller($this->articles); + $result = $marshall->merge($entity, $data, ['Users']); + $this->assertEquals('My Content', $entity->body); + $this->assertSame($user, $entity->user); + $this->assertEquals('mark', $entity->user->username); + $this->assertEquals('not a secret', $entity->user->password); + $this->assertTrue($entity->dirty('user')); + } + +/** + * Tests that new associated entities can be created when merging data into + * a parent entity + * + * @return void + */ + public function testMergeCreateAssociation() { + $entity = new Entity([ + 'tile' => 'My Title' + ]); + $entity->accessible('*', true); + $data = [ + 'body' => 'My Content', + 'user' => [ + 'username' => 'mark', + 'password' => 'not a secret' + ] + ]; + $marshall = new Marshaller($this->articles); + $result = $marshall->merge($entity, $data, ['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->assertTrue($entity->dirty('user')); + $this->assertNull($entity->user->isNew()); + } + +/** + * Tests merging one to many associations + * + * @return void + */ + public function testMergeMultipleAssociations() { + $user = new Entity(['username' => 'mark', 'password' => 'secret']); + $comment1 = new Entity(['id' => 1, 'comment' => 'A comment']); + $comment2 = new Entity(['id' => 2, 'comment' => 'Another comment']); + $entity = new Entity([ + 'title' => 'My Title', + 'user' => $user, + 'comments' => [$comment1, $comment2] + ]); + + $user->accessible('*', true); + $comment1->accessible('*', true); + $comment2->accessible('*', true); + $entity->accessible('*', true); + + $data = [ + 'title' => 'Another title', + 'user' => ['password' => 'not so secret'], + 'comments' => [ + ['comment' => 'Extra comment 1'], + ['id' => 2, 'comment' => 'Altered comment 2'], + ['id' => 1, 'comment' => 'Altered comment 1'], + ['id' => 3, 'comment' => 'Extra comment 3'], + ['comment' => 'Extra comment 2'] + ] + ]; + $marshall = new Marshaller($this->articles); + $result = $marshall->merge($entity, $data, ['Users', 'Comments']); + $this->assertSame($entity, $result); + $this->assertSame($user, $result->user); + $this->assertEquals('not so secret', $entity->user->password); + $this->assertSame($comment1, $entity->comments[0]); + $this->assertSame($comment2, $entity->comments[1]); + $this->assertEquals('Altered comment 1', $entity->comments[0]->comment); + $this->assertEquals('Altered comment 2', $entity->comments[1]->comment); + $this->assertEquals( + ['comment' => 'Extra comment 3', 'id' => 3], + $entity->comments[2]->toArray() + ); + $this->assertEquals( + ['comment' => 'Extra comment 1'], + $entity->comments[3]->toArray() + ); + $this->assertEquals( + ['comment' => 'Extra comment 2'], + $entity->comments[4]->toArray() + ); + } + }