Skip to content

Commit

Permalink
Add additional sort flag support.
Browse files Browse the repository at this point in the history
Add natural, numeric, and string sorting to Hash.
Fixes #1700
  • Loading branch information
markstory committed Apr 2, 2012
1 parent 432d00d commit e5ca80b
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 6 deletions.
72 changes: 70 additions & 2 deletions lib/Cake/Test/Case/Utility/HashTest.php
Expand Up @@ -976,7 +976,7 @@ public function testSort() {
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(
Expand All @@ -989,7 +989,7 @@ public function testSort() {
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')))
Expand All @@ -1003,6 +1003,74 @@ public function testSort() {
$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.
* *
Expand Down
30 changes: 26 additions & 4 deletions lib/Cake/Utility/Hash.php
Expand Up @@ -717,13 +717,25 @@ public static function apply(array $data, $path, $function) {
/** /**
* 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) {
Expand All @@ -743,12 +755,22 @@ public static function sort(array $data, $path, $dir) {
$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;

This comment has been minimized.

Copy link
@ceeram

ceeram Apr 4, 2012

Contributor

Use of undefined constant SORT_NATURAL - assumed 'SORT_NATURAL'
This doesnt seem to be a valid sort parameter:
http://php.net/manual/en/function.array-multisort.php

Edit:
seems to be added in 5.4:
http://www.php.net/manual/en/function.sort.php

This comment has been minimized.

Copy link
@markstory

markstory Apr 5, 2012

Author Member

Yeah you have to run the newest fanciest PHP to use everything. I'll add a note to the comments about that.

} else {
$type = SORT_REGULAR;
}
array_multisort($values, $dir, $type, $keys, $dir, $type);
$sorted = array(); $sorted = array();
$keys = array_unique($keys); $keys = array_unique($keys);


Expand Down

0 comments on commit e5ca80b

Please sign in to comment.