Skip to content

Commit

Permalink
Cascade delete also triggered when foreign key does not accept nullva…
Browse files Browse the repository at this point in the history
…lues
  • Loading branch information
mylux committed Oct 1, 2015
1 parent 10f8798 commit 85a2e8c
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 10 deletions.
26 changes: 24 additions & 2 deletions src/ORM/Association/HasMany.php
Expand Up @@ -185,7 +185,7 @@ public function saveAssociated(EntityInterface $entity, array $options = [])
}

/**
* Deletes/sets null the related objects according to the dependency between source and targets
* Deletes/sets null the related objects according to the dependency between source and targets and foreign key nullability
*
* @param array $properties array of foreignKey properties
* @param EntityInterface $entity the entity which should have its associated entities unassigned
Expand All @@ -195,14 +195,36 @@ public function saveAssociated(EntityInterface $entity, array $options = [])
*/
protected function _unlinkAssociated(array $properties, EntityInterface $entity, Table $target, array $options)
{
if ($this->dependent()) {
$mustBeDependent = (!$this->_foreignKeyAcceptsNull($target, $properties) || $this->dependent());
$this->dependent($mustBeDependent);

if ($mustBeDependent) {
$this->cascadeDelete($entity, $options);
} else {
$updateFields = array_fill_keys(array_keys($properties), null);
$target->updateAll($updateFields, $properties);
}
}

/**
* Checks the nullable flag of the foreign key
*
* @param Table $table the table containing the foreign key
* @param array $properties the list of fields that compose the foreign key
* @return bool
*/
protected function _foreignKeyAcceptsNull(Table $table, array $properties)
{
return array_product(
array_map(
function ($prop) use ($table) {
return $table->schema()->isNullable($prop);
},
array_keys($properties)
)
);
}

/**
* {@inheritDoc}
*/
Expand Down
63 changes: 55 additions & 8 deletions tests/TestCase/ORM/TableTest.php
Expand Up @@ -1829,15 +1829,12 @@ public function testSaveAppendSaveStrategy()
*/
public function testSaveDefaultSaveStrategy()
{
$authors = $this->getMock(
'Cake\ORM\Table',
['exists'],
$authors = new Table(
[
[
'connection' => $this->connection,
'alias' => 'Authors',
'table' => 'authors',
]
'table' => 'authors',
'alias' => 'Authors',
'connection' => $this->connection,
'entityClass' => 'Cake\ORM\Entity',
]
);
$authors->hasMany('Articles', ['saveStrategy' => 'append']);
Expand Down Expand Up @@ -1886,6 +1883,56 @@ public function testSaveReplaceSaveStrategyDependent()
$this->assertFalse($authors->Articles->exists(['id' => $articleId]));
}

/**
* Test that the associated entities are unlinked and deleted when they have a not nullable foreign key
*
* @return void
*/
public function testSaveReplaceSaveStrategyNotNullable()
{
$articles = $this->getMock(
'Cake\ORM\Table',
['exists'],
[
[
'connection' => $this->connection,
'alias' => 'Articles',
'table' => 'articles',
]
]
);

$articles->hasMany('Comments', ['saveStrategy' => 'replace']);

$article = $articles->newEntity([
'title' => 'Bakeries are sky rocketing',
'body' => 'All because of cake',
'comments' => [
[
'user_id' => 1,
'comment' => 'That is true!'
],
[
'user_id' => 2,
'comment' => 'Of course'
]
]
], ['associated' => ['Comments']]);

$article = $articles->save($article, ['associated' => ['Comments']]);
$commentId = $article->comments[0]->id;

$this->assertEquals(2, $articles->Comments->find('all')->where(['article_id' => $article->id])->count());
$this->assertTrue($articles->Comments->exists(['id' => $commentId]));

unset($article->comments[0]);
$article->dirty('comments', true);
$article = $articles->save($article, ['associated' => ['Comments']]);

$this->assertEquals(1, $articles->Comments->find('all')->where(['article_id' => $article->id])->count());
$this->assertFalse($articles->Comments->exists(['id' => $commentId]));
}

/**
* Test that saving a new entity with a Primary Key set does not call exists when checkExisting is false.
*
Expand Down

0 comments on commit 85a2e8c

Please sign in to comment.