Skip to content

Commit

Permalink
Fix joinData being lost when belongsToMany is marshalled by id.
Browse files Browse the repository at this point in the history
When patching belongsToMany records by id, the existing joinData record
should be retained and not replaced.

Refs #8159
  • Loading branch information
markstory committed Feb 13, 2016
1 parent 4d8a51f commit 4ad72ad
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/ORM/Marshaller.php
Expand Up @@ -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);
}
Expand Down
30 changes: 30 additions & 0 deletions tests/TestCase/ORM/MarshallerTest.php
Expand Up @@ -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.
*
Expand Down

0 comments on commit 4ad72ad

Please sign in to comment.