Skip to content

Commit 10f8798

Browse files
committed
Adding cascade delete for dependent HasMany associations
1 parent a237c89 commit 10f8798

File tree

2 files changed

+69
-5
lines changed

2 files changed

+69
-5
lines changed

src/ORM/Association/HasMany.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,7 @@ public function saveAssociated(EntityInterface $entity, array $options = [])
148148
$options['_sourceTable'] = $this->source();
149149

150150
if ($this->_saveStrategy === self::SAVE_REPLACE) {
151-
$updateFields = array_fill_keys(array_keys($properties), null);
152-
$target->updateAll($updateFields, $properties);
151+
$this->_unlinkAssociated($properties, $entity, $target, $options);
153152
}
154153

155154
foreach ($targetEntities as $k => $targetEntity) {
@@ -185,6 +184,25 @@ public function saveAssociated(EntityInterface $entity, array $options = [])
185184
return $entity;
186185
}
187186

187+
/**
188+
* Deletes/sets null the related objects according to the dependency between source and targets
189+
*
190+
* @param array $properties array of foreignKey properties
191+
* @param EntityInterface $entity the entity which should have its associated entities unassigned
192+
* @param Table $target The associated table
193+
* @param array $options original list of options passed in constructor
194+
* @return void
195+
*/
196+
protected function _unlinkAssociated(array $properties, EntityInterface $entity, Table $target, array $options)
197+
{
198+
if ($this->dependent()) {
199+
$this->cascadeDelete($entity, $options);
200+
} else {
201+
$updateFields = array_fill_keys(array_keys($properties), null);
202+
$target->updateAll($updateFields, $properties);
203+
}
204+
}
205+
188206
/**
189207
* {@inheritDoc}
190208
*/

tests/TestCase/ORM/TableTest.php

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,7 @@ public function testSavePrimaryKeyEntityExists()
17391739

17401740

17411741
/**
1742-
* Test that save works with replace saveStrategy
1742+
* Test that save works with replace saveStrategy and are not deleted once they are not null
17431743
*
17441744
* @return void
17451745
*/
@@ -1770,17 +1770,19 @@ public function testSaveReplaceSaveStrategy()
17701770

17711771
$this->assertEquals(2, $authors->Articles->find('all')->where(['author_id' => $entity['id']])->count());
17721772

1773+
$articleId = $entity->articles[0]->id;
17731774
unset($entity->articles[0]);
17741775
$entity->dirty('articles', true);
17751776

17761777
$authors->save($entity, ['associated' => ['Articles']]);
17771778

17781779
$this->assertEquals(1, $authors->Articles->find('all')->where(['author_id' => $entity['id']])->count());
1780+
$this->assertTrue($authors->Articles->exists(['id' => $articleId]));
17791781
}
17801782

17811783

17821784
/**
1783-
* Test that save works with append saveStrategy
1785+
* Test that save works with append saveStrategy not deleting or setting null anything
17841786
*
17851787
* @return void
17861788
*/
@@ -1810,13 +1812,15 @@ public function testSaveAppendSaveStrategy()
18101812
$entity = $authors->save($entity, ['associated' => ['Articles']]);
18111813

18121814
$this->assertEquals(2, $authors->Articles->find('all')->where(['author_id' => $entity['id']])->count());
1813-
1815+
1816+
$articleId = $entity->articles[0]->id;
18141817
unset($entity->articles[0]);
18151818
$entity->dirty('articles', true);
18161819

18171820
$authors->save($entity, ['associated' => ['Articles']]);
18181821

18191822
$this->assertEquals(2, $authors->Articles->find('all')->where(['author_id' => $entity['id']])->count());
1823+
$this->assertTrue($authors->Articles->exists(['id' => $articleId]));
18201824
}
18211825
/**
18221826
* Test that save has append as the default save strategy
@@ -1840,6 +1844,48 @@ public function testSaveDefaultSaveStrategy()
18401844
$this->assertEquals('append', $authors->association('articles')->saveStrategy());
18411845
}
18421846

1847+
/**
1848+
* Test that the associated entities are unlinked and deleted when they are dependent
1849+
*
1850+
* @return void
1851+
*/
1852+
public function testSaveReplaceSaveStrategyDependent()
1853+
{
1854+
$authors = $this->getMock(
1855+
'Cake\ORM\Table',
1856+
['exists'],
1857+
[
1858+
[
1859+
'connection' => $this->connection,
1860+
'alias' => 'Authors',
1861+
'table' => 'authors',
1862+
]
1863+
]
1864+
);
1865+
$authors->hasMany('Articles', ['saveStrategy' => 'replace', 'dependent' => true]);
1866+
1867+
$entity = $authors->newEntity([
1868+
'name' => 'mylux',
1869+
'articles' => [
1870+
['title' => 'One Random Post', 'body' => 'The cake is not a lie'],
1871+
['title' => 'Another Random Post', 'body' => 'The cake is nice'],
1872+
]
1873+
], ['associated' => ['Articles']]);
1874+
1875+
$entity = $authors->save($entity, ['associated' => ['Articles']]);
1876+
1877+
$this->assertEquals(2, $authors->Articles->find('all')->where(['author_id' => $entity['id']])->count());
1878+
1879+
$articleId = $entity->articles[0]->id;
1880+
unset($entity->articles[0]);
1881+
$entity->dirty('articles', true);
1882+
1883+
$authors->save($entity, ['associated' => ['Articles']]);
1884+
1885+
$this->assertEquals(1, $authors->Articles->find('all')->where(['author_id' => $entity['id']])->count());
1886+
$this->assertFalse($authors->Articles->exists(['id' => $articleId]));
1887+
}
1888+
18431889
/**
18441890
* Test that saving a new entity with a Primary Key set does not call exists when checkExisting is false.
18451891
*

0 commit comments

Comments
 (0)