Adding Set::sort(), for sorting model results by association keys, tests included

git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@6412 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
nate 2008-01-27 20:22:45 +00:00
parent 39940856b8
commit 4e56b06f66
2 changed files with 142 additions and 2 deletions

View file

@ -355,8 +355,10 @@ class Set extends Object {
return $out;
}
/**
* Gets a value from an array or object that maps a given path.
* The special {n}, as seen in the Model::generateList method, is taken care of here.
* Gets a value from an array or object that is contained in a given path using an array path syntax, i.e.:
* "{n}.Person.{[a-z]+}" - Where "{n}" represents a numeric key, "Person" represents a string literal,
* and "{[a-z]+}" (i.e. any string literal enclosed in brackets besides {n} and {s}) is interpreted as
* a regular expression.
*
* @param array $data Array from where to extract
* @param mixed $path As an array, or as a dot-separated string.
@ -852,5 +854,53 @@ class Set extends Object {
}
return $out;
}
/**
* Flattens an array for sorting
*
* @param array $results
* @param string $key
* @return array
* @access private
*/
function __flatten($results, $key = null) {
$stack = array();
foreach ($results as $k => $r) {
if (is_array($r)) {
$stack = am($stack, Set::__flatten($r, $k));
} else {
if (!$key) {
$key = $k;
}
$stack[] = array('id' => $key, 'value' => $r);
}
}
return $stack;
}
/**
* Sorts an array by any value, determined by a Set-compatible path
*
* @param array $data
* @param string $path A Set-compatible path to the array value
* @param string $dir asc/desc
* @return array
*/
function sort($data, $path, $dir) {
$result = Set::__flatten(Set::extract($data, $path));
list($keys, $values) = array(Set::extract($result, '{n}.id'), Set::extract($result, '{n}.value'));
if ($dir == 'asc') {
$dir = SORT_ASC;
} elseif ($dir == 'desc') {
$dir = SORT_DESC;
}
array_multisort($values, $dir, $keys, $dir);
$sorted = array();
foreach ($keys as $k) {
$sorted[] = $data[$k];
}
return $sorted;
}
}
?>

View file

@ -131,6 +131,46 @@ class SetTest extends UnitTestCase {
$this->assertIdentical(Set::normalize(Set::merge($a, $b)), $expected);
}
function testSort() {
// ascending
$a = array(
0 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate'))),
1 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay')))
);
$b = array(
0 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay'))),
1 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate')))
);
$a = Set::sort($a, '{n}.Friend.{n}.name', 'asc');
$this->assertIdentical($a, $b);
// descending
$b = array(
0 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate'))),
1 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay')))
);
$a = array(
0 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay'))),
1 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate')))
);
$a = Set::sort($a, '{n}.Friend.{n}.name', 'desc');
$this->assertIdentical($a, $b);
// if every element doesn't have the matching key, the one without is compared as empty
$a = array(
0 => array('Person' => array('name' => 'Jeff')),
1 => array('Shirt' => array('color' => 'black'))
);
$b = array(
0 => array('Shirt' => array('color' => 'black')),
1 => array('Person' => array('name' => 'Jeff')),
);
$a = Set::sort($a, '{n}.Person.name', 'asc');
$this->assertIdentical($a, $b);
}
function testExtract() {
$a = array(
@ -978,5 +1018,55 @@ class SetTest extends UnitTestCase {
$expected = array('Data' => array('Post' => array('title' => 'Title of this post', 'description' => 'cool')));
$this->assertEqual($result, $expected);
}
function __flatten($results, $key = null) {
$stack = array();
foreach ($results as $k => $r) {
if (is_array($r)) {
$stack = am($stack, Set::__flatten($r, $k));
} else {
if (!$key) {
$key = $k;
}
$stack[] = array(
'id' => $key,
'value' => $r
);
}
}
return $stack;
}
/**
* Sorts an array by any value, determined by a Set-compatible path
*
* @param array $data
* @param string $path A Set-compatible path to the array value
* @param string $dir asc/desc
* @return unknown
*/
function sort($data, $path, $dir) {
$result = Set::extract($data, $path);
$result = Set::__flatten($result);
$keys = Set::extract($result, '{n}.id');
$values = Set::extract($result, '{n}.value');
if ($dir == 'asc') {
$dir = SORT_ASC;
}
if ($dir == 'desc') {
$dir = SORT_DESC;
}
array_multisort($values, $dir, $keys, $dir);
$sorted = array();
foreach ($keys as $k) {
$sorted[] = $data[$k];
}
return $sorted;
}
}
?>