Add additional sort flag support.

Add natural, numeric, and string sorting to Hash.
Fixes #1700
This commit is contained in:
mark_story 2012-04-01 23:09:15 -04:00
parent 432d00de19
commit e5ca80b711
2 changed files with 96 additions and 6 deletions

View file

@ -976,7 +976,7 @@ class HashTest extends CakeTestCase {
0 => array('Shirt' => array('color' => 'black')), 0 => array('Shirt' => array('color' => 'black')),
1 => array('Person' => array('name' => 'Jeff')), 1 => array('Person' => array('name' => 'Jeff')),
); );
$a = Hash::sort($a, '{n}.Person.name', 'ASC'); $a = Hash::sort($a, '{n}.Person.name', 'ASC', 'STRING');
$this->assertEquals($a, $b); $this->assertEquals($a, $b);
$names = array( $names = array(
@ -989,7 +989,7 @@ class HashTest extends CakeTestCase {
array('employees' => array(array('name' => array()))), array('employees' => array(array('name' => array()))),
array('employees' => array(array('name' => array()))) array('employees' => array(array('name' => array())))
); );
$result = Hash::sort($names, '{n}.employees.0.name', 'asc', 1); $result = Hash::sort($names, '{n}.employees.0.name', 'asc');
$expected = array( $expected = array(
array('employees' => array( array('employees' => array(
array('name' => array('first' => 'John', 'last' => 'Doe'))) array('name' => array('first' => 'John', 'last' => 'Doe')))
@ -1003,6 +1003,74 @@ class HashTest extends CakeTestCase {
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result);
} }
/**
* Test sort() with numeric option.
*
* @return void
*/
public function testSortNumeric() {
$items = array(
array('Item' => array('price' => '155,000')),
array('Item' => array('price' => '139,000')),
array('Item' => array('price' => '275,622')),
array('Item' => array('price' => '230,888')),
array('Item' => array('price' => '66,000')),
);
$result = Hash::sort($items, '{n}.Item.price', 'asc', 'numeric');
$expected = array(
array('Item' => array('price' => '66,000')),
array('Item' => array('price' => '139,000')),
array('Item' => array('price' => '155,000')),
array('Item' => array('price' => '230,888')),
array('Item' => array('price' => '275,622')),
);
$this->assertEquals($expected, $result);
$result = Hash::sort($items, '{n}.Item.price', 'desc', 'numeric');
$expected = array(
array('Item' => array('price' => '275,622')),
array('Item' => array('price' => '230,888')),
array('Item' => array('price' => '155,000')),
array('Item' => array('price' => '139,000')),
array('Item' => array('price' => '66,000')),
);
$this->assertEquals($expected, $result);
}
/**
* Test natural sorting.
*
* @return void
*/
public function testSortNatural() {
$items = array(
array('Item' => array('image' => 'img1.jpg')),
array('Item' => array('image' => 'img99.jpg')),
array('Item' => array('image' => 'img12.jpg')),
array('Item' => array('image' => 'img10.jpg')),
array('Item' => array('image' => 'img2.jpg')),
);
$result = Hash::sort($items, '{n}.Item.image', 'desc', 'natural');
$expected = array(
array('Item' => array('image' => 'img99.jpg')),
array('Item' => array('image' => 'img12.jpg')),
array('Item' => array('image' => 'img10.jpg')),
array('Item' => array('image' => 'img2.jpg')),
array('Item' => array('image' => 'img1.jpg')),
);
$this->assertEquals($expected, $result);
$result = Hash::sort($items, '{n}.Item.image', 'asc', 'natural');
$expected = array(
array('Item' => array('image' => 'img1.jpg')),
array('Item' => array('image' => 'img2.jpg')),
array('Item' => array('image' => 'img10.jpg')),
array('Item' => array('image' => 'img12.jpg')),
array('Item' => array('image' => 'img99.jpg')),
);
$this->assertEquals($expected, $result);
}
/** /**
* test sorting with out of order keys. * test sorting with out of order keys.
* *

View file

@ -717,13 +717,25 @@ class Hash {
/** /**
* Sorts an array by any value, determined by a Set-compatible path * Sorts an array by any value, determined by a Set-compatible path
* *
* ### Sort directions
*
* - `asc` Sort ascending.
* - `desc` Sort descending.
*
* ## Sort types
*
* - `numeric` Sort by numeric value.
* - `regular` Sort by numeric value.
* - `string` Sort by numeric value.
*
* @param array $data An array of data to sort * @param array $data An array of data to sort
* @param string $path A Set-compatible path to the array value * @param string $path A Set-compatible path to the array value
* @param string $dir Direction of sorting - either ascending (ASC), or descending (DESC) * @param string $dir See directions above.
* @param string $type See direction types above. Defaults to 'regular'.
* @return array Sorted array of data * @return array Sorted array of data
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::sort * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::sort
*/ */
public static function sort(array $data, $path, $dir) { public static function sort(array $data, $path, $dir, $type = 'regular') {
$originalKeys = array_keys($data); $originalKeys = array_keys($data);
$numeric = is_numeric(implode('', $originalKeys)); $numeric = is_numeric(implode('', $originalKeys));
if ($numeric) { if ($numeric) {
@ -743,12 +755,22 @@ class Hash {
$values = self::extract($result, '{n}.value'); $values = self::extract($result, '{n}.value');
$dir = strtolower($dir); $dir = strtolower($dir);
$type = strtolower($type);
if ($dir === 'asc') { if ($dir === 'asc') {
$dir = SORT_ASC; $dir = SORT_ASC;
} elseif ($dir === 'desc') { } else {
$dir = SORT_DESC; $dir = SORT_DESC;
} }
array_multisort($values, $dir, $keys, $dir); if ($type === 'numeric') {
$type = SORT_NUMERIC;
} elseif ($type === 'string') {
$type = SORT_STRING;
} elseif ($type === 'natural') {
$type = SORT_NATURAL;
} else {
$type = SORT_REGULAR;
}
array_multisort($values, $dir, $type, $keys, $dir, $type);
$sorted = array(); $sorted = array();
$keys = array_unique($keys); $keys = array_unique($keys);