Browse Source

Port case-insensitive sorting to 3.1

Refs #7217
Mark Story 10 years ago
parent
commit
4864980a8b
2 changed files with 69 additions and 1 deletions
  1. 22 1
      src/Utility/Hash.php
  2. 47 0
      tests/TestCase/Utility/HashTest.php

+ 22 - 1
src/Utility/Hash.php

@@ -901,10 +901,19 @@ class Hash
      * - `natural` Compare items as strings using "natural ordering" in a human friendly way.
      *   Will sort foo10 below foo2 as an example.
      *
+     * To do case insensitive sorting, pass the type as an array as follows:
+     *
+     * ```
+     * Hash::sort($data, 'some.attribute', 'asc', ['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/3.0/en/core-libraries/hash.html#Hash::sort
      */
@@ -932,7 +941,16 @@ class Hash
         $values = static::extract($result, '{n}.value');
 
         $dir = strtolower($dir);
+        $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'];
+        }
         $type = strtolower($type);
+
         if ($dir === 'asc') {
             $dir = SORT_ASC;
         } else {
@@ -947,6 +965,9 @@ class Hash
         } else {
             $type = SORT_REGULAR;
         }
+        if ($ignoreCase) {
+            $values = array_map('mb_strtolower', $values);
+        }
         array_multisort($values, $dir, $type, $keys, $dir, $type);
         $sorted = [];
         $keys = array_unique($keys);

+ 47 - 0
tests/TestCase/Utility/HashTest.php

@@ -1446,6 +1446,53 @@ class HashTest extends TestCase
         $this->assertEquals($expected, $result);
     }
 
+
+    /**
+     * test sorting with string ignoring case.
+     *
+     * @return void
+     */
+    public function testSortStringIgnoreCase()
+    {
+        $toSort = [
+            ['Item' => ['name' => 'bar']],
+            ['Item' => ['name' => 'Baby']],
+            ['Item' => ['name' => 'Baz']],
+            ['Item' => ['name' => 'bat']],
+        ];
+        $sorted = Hash::sort($toSort, '{n}.Item.name', 'asc', ['type' => 'string', 'ignoreCase' => true]);
+        $expected = [
+            ['Item' => ['name' => 'Baby']],
+            ['Item' => ['name' => 'bar']],
+            ['Item' => ['name' => 'bat']],
+            ['Item' => ['name' => 'Baz']],
+        ];
+        $this->assertEquals($expected, $sorted);
+    }
+
+    /**
+     * test regular sorting ignoring case.
+     *
+     * @return void
+     */
+    public function testSortRegularIgnoreCase()
+    {
+        $toSort = [
+            ['Item' => ['name' => 'bar']],
+            ['Item' => ['name' => 'Baby']],
+            ['Item' => ['name' => 'Baz']],
+            ['Item' => ['name' => 'bat']],
+        ];
+        $sorted = Hash::sort($toSort, '{n}.Item.name', 'asc', ['type' => 'regular', 'ignoreCase' => true]);
+        $expected = [
+            ['Item' => ['name' => 'Baby']],
+            ['Item' => ['name' => 'bar']],
+            ['Item' => ['name' => 'bat']],
+            ['Item' => ['name' => 'Baz']],
+        ];
+        $this->assertEquals($expected, $sorted);
+    }
+
     /**
      * Test insert()
      *