diff --git a/lib/Cake/Test/Case/Utility/HashTest.php b/lib/Cake/Test/Case/Utility/HashTest.php index 0f8b8b540..cb97f60e2 100644 --- a/lib/Cake/Test/Case/Utility/HashTest.php +++ b/lib/Cake/Test/Case/Utility/HashTest.php @@ -1301,6 +1301,43 @@ class HashTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * Test natural sorting ignoring case. + * + * @return void + */ + public function testSortNaturalIgnoreCase() { + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + $this->markTestSkipped('SORT_NATURAL is available since PHP 5.4.'); + } + $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', array('type' => 'natural', 'ignoreCase' => true)); + $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', array('type' => 'natural', 'ignoreCase' => true)); + $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 that sort() with 'natural' type will fallback to 'regular' as SORT_NATURAL is introduced in PHP 5.4 * @@ -1355,7 +1392,7 @@ class HashTest extends CakeTestCase { * * @return void */ - public function testSortString() { + public function testSortStringKeys() { $toSort = array( 'four' => array('number' => 4, 'some' => 'foursome'), 'six' => array('number' => 6, 'some' => 'sixsome'), @@ -1387,6 +1424,50 @@ class HashTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * test sorting with string ignoring case. + * + * @return void + */ + public function testSortStringIgnoreCase() { + $toSort = array( + array('Item' => array('name' => 'bar')), + array('Item' => array('name' => 'Baby')), + array('Item' => array('name' => 'Baz')), + array('Item' => array('name' => 'bat')), + ); + $sorted = Hash::sort($toSort, '{n}.Item.name', 'asc', array('type' => 'string', 'ignoreCase' => true)); + $expected = array( + array('Item' => array('name' => 'Baby')), + array('Item' => array('name' => 'bar')), + array('Item' => array('name' => 'bat')), + array('Item' => array('name' => 'Baz')), + ); + $this->assertEquals($expected, $sorted); + } + +/** + * test regular sorting ignoring case. + * + * @return void + */ + public function testSortRegularIgnoreCase() { + $toSort = array( + array('Item' => array('name' => 'bar')), + array('Item' => array('name' => 'Baby')), + array('Item' => array('name' => 'Baz')), + array('Item' => array('name' => 'bat')), + ); + $sorted = Hash::sort($toSort, '{n}.Item.name', 'asc', array('type' => 'regular', 'ignoreCase' => true)); + $expected = array( + array('Item' => array('name' => 'Baby')), + array('Item' => array('name' => 'bar')), + array('Item' => array('name' => 'bat')), + array('Item' => array('name' => 'Baz')), + ); + $this->assertEquals($expected, $sorted); + } + /** * Test insert() * diff --git a/lib/Cake/Utility/Hash.php b/lib/Cake/Utility/Hash.php index ad06cf95b..a5ccf0ab2 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -839,10 +839,19 @@ class Hash { * - `natural` Compare items as strings using "natural ordering" in a human friendly way. * Will sort foo10 below foo2 as an example. Requires PHP 5.4 or greater or it will fallback to 'regular' * + * To do case insensitive sorting, pass the type as an array as follows: + * + * ``` + * array('type' => 'regular', 'ignoreCase' => true) + * ``` + * + * When using the array form, `type` defaults to 'regular'. The `ignoreCase` option + * defaults to `false`. + * * @param array $data An array of data to sort * @param string $path A Set-compatible path to the array value * @param string $dir See directions above. Defaults to 'asc'. - * @param string $type See direction types above. Defaults to 'regular'. + * @param array|string $type See direction types above. Defaults to 'regular'. * @return array Sorted array of data * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::sort */ @@ -869,10 +878,21 @@ class Hash { $values = static::extract($result, '{n}.value'); $dir = strtolower($dir); - $type = strtolower($type); + $ignoreCase = false; + + // $type can be overloaded for case insensitive sort + if (is_array($type)) { + $type += array('ignoreCase' => false, 'type' => 'regular'); + $ignoreCase = $type['ignoreCase']; + $type = $type['type']; + } else { + $type = strtolower($type); + } + if ($type === 'natural' && version_compare(PHP_VERSION, '5.4.0', '<')) { $type = 'regular'; } + if ($dir === 'asc') { $dir = SORT_ASC; } else { @@ -887,7 +907,12 @@ class Hash { } else { $type = SORT_REGULAR; } - array_multisort($values, $dir, $type, $keys, $dir, $type); + + if ($ignoreCase) { + $values = array_map('strtolower', $values); + } + array_multisort($values, $dir, $type, $keys, $dir); + $sorted = array(); $keys = array_unique($keys);