Skip to content

Commit

Permalink
Merge branch '4.11' into 4
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed May 27, 2022
2 parents 2cf1725 + dec8581 commit 8ae7f30
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 11 deletions.
1 change: 0 additions & 1 deletion src/ORM/ManyManyList.php
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,6 @@ public function removeByID($itemID)
*/
public function removeAll()
{

// Remove the join to the join table to avoid MySQL row locking issues.
$query = $this->dataQuery();
$foreignFilter = $query->getQueryParam('Foreign.Filter');
Expand Down
26 changes: 18 additions & 8 deletions src/ORM/ManyManyThroughList.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,37 @@ public function removeByID($itemID)
// Find has_many row with a local key matching the given id
$hasManyList = $this->manipulator->getParentRelationship($this->dataQuery());
$records = $hasManyList->filter($this->manipulator->getLocalKey(), $itemID);
$affectedIds = [];

// Rather than simple un-associating the record (as in has_many list)
// Delete the actual mapping row as many_many deletions behave.
/** @var DataObject $record */
foreach ($records as $record) {
$affectedIds[] = $record->ID;
$record->delete();
}

if ($this->removeCallbacks && $affectedIds) {
$this->removeCallbacks->call($this, $affectedIds);
if ($this->removeCallbacks && $itemID) {
$this->removeCallbacks->call($this, [$itemID]);
}
}

public function removeAll()
{
// Empty has_many table matching the current foreign key
$hasManyList = $this->manipulator->getParentRelationship($this->dataQuery());
$affectedIds = $hasManyList->column('ID');
$hasManyList->removeAll();
// Get the IDs of records in the current list
$affectedIds = $this->limit(null)->column('ID');
if (empty($affectedIds)) {
return;
}

// Get the join records that apply for the current list
$records = $this->manipulator->getJoinClass()::get()->filter([
$this->manipulator->getForeignIDKey() => $this->getForeignID(),
$this->manipulator->getLocalKey() => $affectedIds,
]);

/** @var DataObject $record */
foreach ($records as $record) {
$record->delete();
}

if ($this->removeCallbacks && $affectedIds) {
$this->removeCallbacks->call($this, $affectedIds);
Expand Down
1 change: 0 additions & 1 deletion src/ORM/ManyManyThroughQueryManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace SilverStripe\ORM;

use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation;
Expand Down
58 changes: 58 additions & 0 deletions tests/php/ORM/ManyManyThroughListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,64 @@ public function testRemove()
);
}

public function testRemoveAll()
{
$first = $this->objFromFixture(ManyManyThroughListTest\TestObject::class, 'parent1');
$first->Items()->add($this->objFromFixture(ManyManyThroughListTest\Item::class, 'child0'));
$second = $this->objFromFixture(ManyManyThroughListTest\TestObject::class, 'parent2');

$firstItems = $first->Items();
$secondItems = $second->Items();
$initialJoins = ManyManyThroughListTest\JoinObject::get()->count();
$initialItems = ManyManyThroughListTest\Item::get()->count();
$initialRelations = $firstItems->count();
$initialSecondListRelations = $secondItems->count();

$firstItems->removeAll();

// Validate all items were removed from the first list, but none were removed from the second list
$this->assertEquals(0, count($firstItems));
$this->assertEquals($initialSecondListRelations, count($secondItems));

// Validate that the JoinObjects were actually removed from the database
$this->assertEquals($initialJoins - $initialRelations, ManyManyThroughListTest\JoinObject::get()->count());

// Confirm Item objects were not removed from the database
$this->assertEquals($initialItems, ManyManyThroughListTest\Item::get()->count());
}

public function testRemoveAllIgnoresLimit()
{
$parent = $this->objFromFixture(ManyManyThroughListTest\TestObject::class, 'parent1');
$parent->Items()->add($this->objFromFixture(ManyManyThroughListTest\Item::class, 'child0'));
$initialJoins = ManyManyThroughListTest\JoinObject::get()->count();
// Validate there are enough items in the relation for this test
$this->assertTrue($initialJoins > 1);

$items = $parent->Items()->Limit(1);
$items->removeAll();

// Validate all items were removed from the list - not only one
$this->assertEquals(0, count($items));
}

public function testFilteredRemoveAll()
{
$parent = $this->objFromFixture(ManyManyThroughListTest\TestObject::class, 'parent1');
$parent->Items()->add($this->objFromFixture(ManyManyThroughListTest\Item::class, 'child0'));
$items = $parent->Items();
$initialJoins = ManyManyThroughListTest\JoinObject::get()->count();
$initialRelations = $items->count();

$items->filter('Title:not', 'not filtered')->removeAll();

// Validate only the filtered items were removed
$this->assertEquals(1, $items->count());

// Validate the list only contains the correct remaining item
$this->assertEquals(['not filtered'], $items->column('Title'));
}

/**
* Test validation
*/
Expand Down
15 changes: 14 additions & 1 deletion tests/php/ORM/ManyManyThroughListTest.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
SilverStripe\ORM\Tests\ManyManyThroughListTest\TestObject:
parent1:
Title: 'my object'
parent2:
Title: 'my object2'
SilverStripe\ORM\Tests\ManyManyThroughListTest\Item:
# Having this one first means the IDs of records aren't the same as the IDs of the join objects.
child0:
Title: 'not filtered'
child1:
Title: 'item 1'
child2:
Expand All @@ -17,6 +22,14 @@ SilverStripe\ORM\Tests\ManyManyThroughListTest\JoinObject:
Sort: 2
Parent: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\TestObject.parent1
Child: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\Item.child2
join3:
Title: 'join 3'
Parent: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\TestObject.parent2
Child: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\Item.child1
join4:
Title: 'join 4'
Parent: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\TestObject.parent2
Child: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\Item.child2
SilverStripe\ORM\Tests\ManyManyThroughListTest\PolyObjectA:
obja1:
Title: 'object A1'
Expand Down Expand Up @@ -75,4 +88,4 @@ SilverStripe\ORM\Tests\ManyManyThroughListTest\FallbackLocale:
mexico_argentina:
Sort: 1
Parent: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\Locale.mexico
Locale: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\Locale.argentina
Locale: =>SilverStripe\ORM\Tests\ManyManyThroughListTest\Locale.argentina

0 comments on commit 8ae7f30

Please sign in to comment.