Skip to content

Commit

Permalink
Avoiding bonus UPDATE statements when saving belongsToMny associations
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Jul 16, 2015
1 parent fc54441 commit 04c7191
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/ORM/Association/BelongsToMany.php
Expand Up @@ -543,11 +543,17 @@ protected function _saveLinks(EntityInterface $sourceEntity, $targetEntities, $o
$joint = new $entityClass([], ['markNew' => true, 'source' => $junctionAlias]); $joint = new $entityClass([], ['markNew' => true, 'source' => $junctionAlias]);
} }


$joint->set(array_combine( $sourceKeys = array_combine($foreignKey, $sourceEntity->extract($bindingKey));
$foreignKey, $targetKeys = array_combine($assocForeignKey, $e->extract($targetPrimaryKey));
$sourceEntity->extract($bindingKey)
), ['guard' => false]); if ($sourceKeys !== $joint->extract($foreignKey)) {
$joint->set(array_combine($assocForeignKey, $e->extract($targetPrimaryKey)), ['guard' => false]); $joint->set($sourceKeys, ['guard' => false]);
}

if ($targetKeys !== $joint->extract($assocForeignKey)) {
$joint->set($targetKeys, ['guard' => false]);
}

$saved = $junction->save($joint, $options); $saved = $junction->save($joint, $options);


if (!$saved && !empty($options['atomic'])) { if (!$saved && !empty($options['atomic'])) {
Expand Down
37 changes: 37 additions & 0 deletions tests/TestCase/ORM/TableTest.php
Expand Up @@ -4382,6 +4382,43 @@ public function testSaveHasManyNoWasteSave()
$this->assertEquals(1, $counter); $this->assertEquals(1, $counter);
} }


/**
* Tests that on second save, entities for the belongsToMany relation are not marked
* as dirty unnecessarily. This helps avoid wasteful database statements and makes
* for a cleaner transaction log
*
* @return void
*/
public function testSaveBelongsToManyNoWasteSave()
{
$data = [
'title' => 'foo',
'body' => 'bar',
'tags' => [
'_ids' => [1, 2]
]
];

$table = TableRegistry::get('Articles');
$table->belongsToMany('Tags');
$article = $table->save($table->newEntity($data, ['associated' => ['Tags']]));

$counter = 0;
$table->Tags->junction()
->eventManager()
->on('Model.afterSave', function ($event, $entity) use (&$counter) {
if ($entity->dirty()) {
$counter++;
}
});

$article->tags[] = $table->Tags->get(3);
$this->assertCount(3, $article->tags);
$article->dirty('tags', true);
$table->save($article);
$this->assertEquals(1, $counter);
}

/** /**
* Tests that after saving then entity contains the right primary * Tests that after saving then entity contains the right primary
* key casted to the right type * key casted to the right type
Expand Down

0 comments on commit 04c7191

Please sign in to comment.