Browse Source

Correctly sort sparse data that uses numeric keys.

When numeric keyed results are sorted, and the sort key is sparse we
should attempt to sort the data as best we can.

Refs #8177
Mark Story 10 years ago
parent
commit
312637db79
2 changed files with 60 additions and 2 deletions
  1. 7 2
      src/Utility/Hash.php
  2. 53 0
      tests/TestCase/Utility/HashTest.php

+ 7 - 2
src/Utility/Hash.php

@@ -933,12 +933,17 @@ class Hash
             $data = array_values($data);
         }
         $sortValues = static::extract($data, $path);
-        $sortCount = count($sortValues);
         $dataCount = count($data);
 
         // Make sortValues match the data length, as some keys could be missing
         // the sorted value path.
-        if ($sortCount < $dataCount) {
+        $missingData = count($sortValues) < $dataCount;
+        if ($missingData && $numeric) {
+            foreach ($data as $key => $value) {
+                // Get the value without the leading '{n}'.
+                $sortValues[$key] = static::get($value, substr($path, 4));
+            }
+        } elseif ($missingData) {
             $sortValues = array_pad($sortValues, $dataCount, null);
         }
         $result = static::_squash($sortValues);

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

@@ -1775,6 +1775,59 @@ class HashTest extends TestCase
     }
 
     /**
+     * Test sorting on a nested key that is sometimes undefined.
+     *
+     * @return void
+     */
+    public function testSortSparse()
+    {
+        $data = [
+            [
+                'id' => 1,
+                'title' => 'element 1',
+                'extra' => 1,
+            ],
+            [
+                'id' => 2,
+                'title' => 'element 2',
+                'extra' => 2,
+            ],
+            [
+                'id' => 3,
+                'title' => 'element 3',
+            ],
+            [
+                'id' => 4,
+                'title' => 'element 4',
+                'extra' => 4,
+            ]
+        ];
+        $result = Hash::sort($data, '{n}.extra', 'desc', 'natural');
+        $expected = [
+            [
+                'id' => 4,
+                'title' => 'element 4',
+                'extra' => 4,
+            ],
+            [
+                'id' => 2,
+                'title' => 'element 2',
+                'extra' => 2,
+            ],
+            [
+                'id' => 1,
+                'title' => 'element 1',
+                'extra' => 1,
+            ],
+            [
+                'id' => 3,
+                'title' => 'element 3',
+            ],
+        ];
+        $this->assertSame($expected, $result);
+    }
+
+    /**
      * Test insert()
      *
      * @return void