mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
BUG: Fix ManyManyList->removeAll() when filters are applied to the query
In order to be cross-database compatible and support filters, the IDs to delete must be retrieved in a sub-query.
This commit is contained in:
parent
365e8021ba
commit
b537ee28a2
@ -168,11 +168,27 @@ class ManyManyList extends RelationList {
|
||||
* Remove all items from this many-many join. To remove a subset of items, filter it first.
|
||||
*/
|
||||
public function removeAll() {
|
||||
$query = $this->dataQuery()->query();
|
||||
$query->setDelete(true);
|
||||
$query->setSelect(array('*'));
|
||||
$query->setFrom("\"$this->joinTable\"");
|
||||
$query->execute();
|
||||
$base = ClassInfo::baseDataClass($this->dataClass());
|
||||
|
||||
// Remove the join to the join table to avoid MySQL row locking issues.
|
||||
$query = $this->dataQuery();
|
||||
$query->removeFilterOn($query->getQueryParam('Foreign.Filter'));
|
||||
|
||||
$query = $query->query();
|
||||
$query->setSelect("\"$base\".\"ID\"");
|
||||
|
||||
$from = $query->getFrom();
|
||||
unset($from[$this->joinTable]);
|
||||
$query->setFrom($from);
|
||||
|
||||
// Use a sub-query as SQLite does not support setting delete targets in
|
||||
// joined queries.
|
||||
$delete = new SQLQuery();
|
||||
$delete->setDelete(true);
|
||||
$delete->setFrom("\"$this->joinTable\"");
|
||||
$delete->addWhere($this->foreignIDFilter());
|
||||
$delete->addWhere("\"$this->joinTable\".\"$this->localKey\" IN ({$query->sql()})");
|
||||
$delete->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,4 +161,53 @@ class ManyManyListTest extends SapphireTest {
|
||||
$this->assertEquals($teamTwoID, $teamsWithoutTheCaptain->first()->ID,
|
||||
'The ManyManyList contains the wrong team');
|
||||
}
|
||||
|
||||
public function testRemoveAll() {
|
||||
$first = new DataObjectTest_Team();
|
||||
$first->write();
|
||||
|
||||
$second = new DataObjectTest_Team();
|
||||
$second->write();
|
||||
|
||||
$firstPlayers = $first->Players();
|
||||
$secondPlayers = $second->Players();
|
||||
|
||||
$a = new DataObjectTest_Player();
|
||||
$a->ShirtNumber = 'a';
|
||||
$a->write();
|
||||
|
||||
$b = new DataObjectTest_Player();
|
||||
$b->ShirtNumber = 'b';
|
||||
$b->write();
|
||||
|
||||
$firstPlayers->add($a);
|
||||
$firstPlayers->add($b);
|
||||
|
||||
$secondPlayers->add($a);
|
||||
$secondPlayers->add($b);
|
||||
|
||||
$this->assertEquals(array('a', 'b'), $firstPlayers->sort('ShirtNumber')->column('ShirtNumber'));
|
||||
$this->assertEquals(array('a', 'b'), $secondPlayers->sort('ShirtNumber')->column('ShirtNumber'));
|
||||
|
||||
$firstPlayers->removeAll();
|
||||
|
||||
$this->assertEquals(0, count($firstPlayers));
|
||||
$this->assertEquals(2, count($secondPlayers));
|
||||
|
||||
$firstPlayers->removeAll();
|
||||
|
||||
$firstPlayers->add($a);
|
||||
$firstPlayers->add($b);
|
||||
|
||||
$this->assertEquals(array('a', 'b'), $firstPlayers->sort('ShirtNumber')->column('ShirtNumber'));
|
||||
|
||||
$firstPlayers->filter('ShirtNumber', 'b')->removeAll();
|
||||
|
||||
$this->assertEquals(array('a'), $firstPlayers->column('ShirtNumber'));
|
||||
$this->assertEquals(array('a', 'b'), $secondPlayers->sort('ShirtNumber')->column('ShirtNumber'));
|
||||
|
||||
$this->assertNotNull(DataObjectTest_Player::get()->byID($a->ID));
|
||||
$this->assertNotNull(DataObjectTest_Player::get()->byID($b->ID));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user