diff --git a/src/ORM/Marshaller.php b/src/ORM/Marshaller.php index 1c619a7bd46..2a75d1bd1e7 100644 --- a/src/ORM/Marshaller.php +++ b/src/ORM/Marshaller.php @@ -704,19 +704,27 @@ protected function _mergeJoinData($original, $assoc, $value, $options) } $options['accessibleFields'] = ['_joinData' => true]; + $records = $this->mergeMany($original, $value, $options); foreach ($records as $record) { $hash = spl_object_hash($record); $value = $record->get('_joinData'); + // Already an entity, no further marshalling required. + if ($value instanceof EntityInterface) { + continue; + } + + // Scalar data can't be handled if (!is_array($value)) { $record->unsetProperty('_joinData'); continue; } + // Marshal data into the old object, or make a new joinData object. if (isset($extra[$hash])) { $record->set('_joinData', $marshaller->merge($extra[$hash], $value, $nested)); - } else { + } elseif (is_array($value)) { $joinData = $marshaller->one($value, $nested); $record->set('_joinData', $joinData); } diff --git a/tests/TestCase/ORM/MarshallerTest.php b/tests/TestCase/ORM/MarshallerTest.php index e7ae242120c..62af3168cb2 100644 --- a/tests/TestCase/ORM/MarshallerTest.php +++ b/tests/TestCase/ORM/MarshallerTest.php @@ -2003,6 +2003,36 @@ public function testMergeJoinDataAssociations() $this->assertEquals('ber', $entity->tags[1]->_joinData->user->username); } + /** + * Tests that merging belongsToMany association doesn't erase _joinData + * on existing objects. + * + * @return void + */ + public function testMergeBelongsToManyIdsRetainJoinData() + { + $this->articles->belongsToMany('Tags'); + $entity = $this->articles->get(1, ['contain' => ['Tags']]); + $entity->accessible('*', true); + $original = $entity->tags[0]->_joinData; + + $this->assertInstanceOf('Cake\ORM\Entity', $entity->tags[0]->_joinData); + + $data = [ + 'title' => 'Haz moar tags', + 'tags' => [ + ['id' => 1], + ] + ]; + $marshall = new Marshaller($this->articles); + $result = $marshall->merge($entity, $data, ['associated' => ['Tags']]); + + $this->assertCount(1, $result->tags); + $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]); + $this->assertInstanceOf('Cake\ORM\Entity', $result->tags[0]->_joinData); + $this->assertSame($original, $result->tags[0]->_joinData, 'Should be same object'); + } + /** * Test mergeMany() with a simple set of data. *