Merge pull request #4549 from kinglozzer/pulls/recursion-arraylist-sort

FIX: Recursion errors when sorting objects with circular dependencies (fixes #4464)
This commit is contained in:
Will Morgan 2015-09-01 16:42:17 +01:00
commit 17e97babf1
2 changed files with 32 additions and 1 deletions

View File

@ -422,10 +422,15 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
throw new InvalidArgumentException("Bad arguments passed to sort()");
}
// Store the original keys of the items as a sort fallback, so we can preserve the original order in the event
// that array_multisort is unable to work out a sort order for them. This also prevents array_multisort trying
// to inspect object properties which can result in errors with circular dependencies
$originalKeys = array_keys($this->items);
// This the main sorting algorithm that supports infinite sorting params
$multisortArgs = array();
$values = array();
foreach($columnsToSort as $column => $direction ) {
foreach($columnsToSort as $column => $direction) {
// The reason these are added to columns is of the references, otherwise when the foreach
// is done, all $values and $direction look the same
$values[$column] = array();
@ -442,6 +447,8 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
$multisortArgs[] = &$sortDirection[$column];
}
$multisortArgs[] = &$originalKeys;
$list = clone $this;
// As the last argument we pass in a reference to the items that all the sorting will be applied upon
$multisortArgs[] = &$list->items;

View File

@ -424,6 +424,30 @@ class ArrayListTest extends SapphireTest {
$this->assertEquals($list->first()->ID, 1, 'Aron.2 should be first in the list');
$this->assertEquals($list->last()->ID, 3, 'Bert.3 should be last in the list');
}
/**
* Check that we don't cause recursion errors with array_multisort() and circular dependencies
*/
public function testSortWithCircularDependencies() {
$itemA = new stdClass;
$childA = new stdClass;
$itemA->child = $childA;
$childA->parent = $itemA;
$itemA->Sort = 1;
$itemB = new stdClass;
$childB = new stdClass;
$itemB->child = $childB;
$childB->parent = $itemB;
$itemB->Sort = 1;
$items = new ArrayList;
$items->add($itemA);
$items->add($itemB);
// This call will trigger a fatal error if there are issues with circular dependencies
$items->sort('Sort');
}
/**
* $list->filter('Name', 'bob'); // only bob in the list