Permalink
Browse files

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.
  • Loading branch information...
1 parent 365e802 commit b537ee28a25bb0403e6b62a31d19fce13d4351f3 @ajshort ajshort committed Mar 2, 2013
Showing with 70 additions and 5 deletions.
  1. +21 −5 model/ManyManyList.php
  2. +49 −0 tests/model/ManyManyListTest.php
View
@@ -168,11 +168,27 @@ public function removeByID($itemID) {
* 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 @@ public function testSubtractOnAManyManyList() {
$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));
+ }
+
}

0 comments on commit b537ee2

Please sign in to comment.