Browse Source

#13681 - Allow null $keyPath on Hash::combine and use numbered array if it is (#13848)

Allow $keyPath to be null which results in a numerically indexed output.
victoreassis 6 years ago
parent
commit
a64a040be1
2 changed files with 114 additions and 8 deletions
  1. 14 8
      src/Utility/Hash.php
  2. 100 0
      tests/TestCase/Utility/HashTest.php

+ 14 - 8
src/Utility/Hash.php

@@ -452,12 +452,12 @@ class Hash
      * following the path specified in `$groupPath`.
      *
      * @param array $data Array from where to extract keys and values
-     * @param string $keyPath A dot-separated string.
+     * @param string|null $keyPath A dot-separated string. If null it will create a numbered array.
      * @param string|null $valuePath A dot-separated string.
      * @param string|null $groupPath A dot-separated string.
      * @return array Combined array
      * @link https://book.cakephp.org/3/en/core-libraries/hash.html#Cake\Utility\Hash::combine
-     * @throws \RuntimeException When keys and values count is unequal.
+     * @throws \RuntimeException When keys is an array, and keys and values count is unequal.
      */
     public static function combine(array $data, $keyPath, $valuePath = null, $groupPath = null)
     {
@@ -468,10 +468,12 @@ class Hash
         if (is_array($keyPath)) {
             $format = array_shift($keyPath);
             $keys = static::format($data, $keyPath, $format);
+        } elseif ($keyPath === null) {
+            $keys = $keyPath;
         } else {
             $keys = static::extract($data, $keyPath);
         }
-        if (empty($keys)) {
+        if ($keyPath !== null && empty($keys)) {
             return [];
         }
 
@@ -483,10 +485,10 @@ class Hash
             $vals = static::extract($data, $valuePath);
         }
         if (empty($vals)) {
-            $vals = array_fill(0, count($keys), null);
+            $vals = array_fill(0, $keys === null ? count($data) : count($keys), null);
         }
 
-        if (count($keys) !== count($vals)) {
+        if (is_array($keys) && count($keys) !== count($vals)) {
             throw new RuntimeException(
                 'Hash::combine() needs an equal number of keys + values.'
             );
@@ -495,7 +497,7 @@ class Hash
         if ($groupPath !== null) {
             $group = static::extract($data, $groupPath);
             if (!empty($group)) {
-                $c = count($keys);
+                $c = is_array($keys) ? count($keys) : count($vals);
                 $out = [];
                 for ($i = 0; $i < $c; $i++) {
                     if (!isset($group[$i])) {
@@ -504,7 +506,11 @@ class Hash
                     if (!isset($out[$group[$i]])) {
                         $out[$group[$i]] = [];
                     }
-                    $out[$group[$i]][$keys[$i]] = $vals[$i];
+                    if ($keys === null) {
+                        $out[$group[$i]][] = $vals[$i];
+                    } else {
+                        $out[$group[$i]][$keys[$i]] = $vals[$i];
+                    }
                 }
 
                 return $out;
@@ -514,7 +520,7 @@ class Hash
             return [];
         }
 
-        return array_combine($keys, $vals);
+        return array_combine($keys === null ? range(0, count($vals) - 1) : $keys, $vals);
     }
 
     /**

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

@@ -2309,6 +2309,41 @@ class HashTest extends TestCase
     }
 
     /**
+     * test combine() with null key path.
+     *
+     * @return void
+     */
+    public function testCombineWithNullKeyPath()
+    {
+        $result = Hash::combine([], null, '{n}.User.Data');
+        $this->assertEmpty($result);
+
+        $a = static::userData();
+
+        $result = Hash::combine($a, null);
+        $expected = [0 => null, 1 => null, 2 => null];
+        $this->assertEquals($expected, $result);
+
+        $result = Hash::combine($a, null, '{n}.User.non-existant');
+        $expected = [0 => null, 1 => null, 2 => null];
+        $this->assertEquals($expected, $result);
+
+        $result = Hash::combine($a, null, '{n}.User.Data');
+        $expected = [
+            0 => ['user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'],
+            1 => ['user' => 'phpnut', 'name' => 'Larry E. Masters'],
+            2 => ['user' => 'gwoo', 'name' => 'The Gwoo']];
+        $this->assertEquals($expected, $result);
+
+        $result = Hash::combine($a, null, '{n}.User.Data.name');
+        $expected = [
+            0 => 'Mariano Iglesias',
+            1 => 'Larry E. Masters',
+            2 => 'The Gwoo'];
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
      * test combine() giving errors on key/value length mismatches.
      *
      * @return void
@@ -2359,6 +2394,18 @@ class HashTest extends TestCase
         ];
         $this->assertEquals($expected, $result);
 
+        $result = Hash::combine($a, null, '{n}.User.Data', '{n}.User.group_id');
+        $expected = [
+            1 => [
+                0 => ['user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'],
+                1 => ['user' => 'gwoo', 'name' => 'The Gwoo']
+            ],
+            2 => [
+                0 => ['user' => 'phpnut', 'name' => 'Larry E. Masters']
+            ]
+        ];
+        $this->assertEquals($expected, $result);
+
         $result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
         $expected = [
             1 => [
@@ -2371,6 +2418,18 @@ class HashTest extends TestCase
         ];
         $this->assertEquals($expected, $result);
 
+        $result = Hash::combine($a, null, '{n}.User.Data.name', '{n}.User.group_id');
+        $expected = [
+            1 => [
+                0 => 'Mariano Iglesias',
+                1 => 'The Gwoo'
+            ],
+            2 => [
+                0 => 'Larry E. Masters'
+            ]
+        ];
+        $this->assertEquals($expected, $result);
+
         $result = Hash::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
         $expected = [
             1 => [
@@ -2383,6 +2442,18 @@ class HashTest extends TestCase
         ];
         $this->assertEquals($expected, $result);
 
+        $result = Hash::combine($a, null, '{n}.User.Data', '{n}.User.group_id');
+        $expected = [
+            1 => [
+                0 => ['user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'],
+                1 => ['user' => 'gwoo', 'name' => 'The Gwoo']
+            ],
+            2 => [
+                0 => ['user' => 'phpnut', 'name' => 'Larry E. Masters']
+            ]
+        ];
+        $this->assertEquals($expected, $result);
+
         $result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
         $expected = [
             1 => [
@@ -2394,6 +2465,18 @@ class HashTest extends TestCase
             ],
         ];
         $this->assertEquals($expected, $result);
+
+        $result = Hash::combine($a, null, '{n}.User.Data.name', '{n}.User.group_id');
+        $expected = [
+            1 => [
+                0 => 'Mariano Iglesias',
+                1 => 'The Gwoo'
+            ],
+            2 => [
+                0 => 'Larry E. Masters'
+            ]
+        ];
+        $this->assertEquals($expected, $result);
     }
 
     /**
@@ -2424,6 +2507,23 @@ class HashTest extends TestCase
 
         $result = Hash::combine(
             $a,
+            null,
+            ['%1$s: %2$s', '{n}.User.Data.user', '{n}.User.Data.name'],
+            '{n}.User.group_id'
+        );
+        $expected = [
+            1 => [
+                0 => 'mariano.iglesias: Mariano Iglesias',
+                1 => 'gwoo: The Gwoo'
+            ],
+            2 => [
+                0 => 'phpnut: Larry E. Masters'
+            ]
+        ];
+        $this->assertEquals($expected, $result);
+
+        $result = Hash::combine(
+            $a,
             [
                 '%s: %s',
                 '{n}.User.Data.user',