ENHANCEMENT: Made it possible to sort by multiple fields in ArrayList::sort().

This commit is contained in:
ajshort 2011-05-06 00:24:33 +10:00
parent 462689a4e6
commit b3fc458101
2 changed files with 44 additions and 4 deletions

View File

@ -180,15 +180,35 @@ class ArrayList extends ViewableData implements SS_List {
return true;
}
/**
* Sorts this list by one or more fields. You can either pass in a single
* field name and direction, or a map of field names to sort directions.
*
* @param string|array $by
* @param string $dir
* @see SS_List::sort()
*/
public function sort($by, $dir = 'ASC') {
$sorts = array();
$dir = strtoupper($dir) == 'DESC' ? SORT_DESC : SORT_ASC;
foreach ($this->array as $item) {
$sorts[] = $this->extract($item, $by);
if (!is_array($by)) {
$by = array($by => $dir);
}
array_multisort($sorts, $dir, $this->array);
foreach ($by as $field => $dir) {
$dir = strtoupper($dir) == 'DESC' ? SORT_DESC : SORT_ASC;
$vals = array();
foreach ($this->array as $item) {
$vals[] = $this->extract($item, $field);
}
$sorts[] = $vals;
$sorts[] = $dir;
}
$sorts[] = &$this->array;
call_user_func_array('array_multisort', $sorts);
}
public function offsetExists($offset) {

View File

@ -208,6 +208,26 @@ class ArrayListTest extends SapphireTest {
));
}
public function testMultiSort() {
$list = new ArrayList(array(
(object) array('Name'=>'Object1', 'F1'=>1, 'F2'=>2, 'F3'=>3),
(object) array('Name'=>'Object2', 'F1'=>2, 'F2'=>1, 'F3'=>4),
(object) array('Name'=>'Object3', 'F1'=>5, 'F2'=>2, 'F3'=>2),
));
$list->sort('F3', 'ASC');
$this->assertEquals($list->first()->Name, 'Object3', 'Object3 should be first in the list');
$list->sort('F3', 'DESC');
$this->assertEquals($list->first()->Name, 'Object2', 'Object2 should be first in the list');
$list->sort(array('F2'=>'ASC', 'F1'=>'ASC'));
$this->assertEquals($list->last()->Name, 'Object3', 'Object3 should be last in the list');
$list->sort(array('F2'=>'ASC', 'F1'=>'DESC'));
$this->assertEquals($list->last()->Name, 'Object1', 'Object1 should be last in the list');
}
}
/**