Browse Source

Throw exception on invalid invalid key for Collection::combine()

Backport #17340 to 4.x
Corey Taylor 2 years ago
parent
commit
cfc5bf42fd
2 changed files with 64 additions and 2 deletions
  1. 25 2
      src/Collection/CollectionTrait.php
  2. 39 0
      tests/TestCase/Collection/CollectionTest.php

+ 25 - 2
src/Collection/CollectionTrait.php

@@ -591,14 +591,37 @@ trait CollectionTrait
             $rowVal = $options['valuePath'];
 
             if (!$options['groupPath']) {
-                $mapReduce->emit($rowVal($value, $key), $rowKey($value, $key));
+                $mapKey = $rowKey($value, $key);
+                if ($mapKey === null) {
+                    throw new InvalidArgumentException(
+                        'Cannot index by path that does not exist or contains a null value. ' .
+                        'Use a callback to return a default value for that path.'
+                    );
+                }
+
+                $mapReduce->emit($rowVal($value, $key), $mapKey);
 
                 return null;
             }
 
             $key = $options['groupPath']($value, $key);
+            if ($key === null) {
+                throw new InvalidArgumentException(
+                    'Cannot group by path that does not exist or contains a null value. ' .
+                    'Use a callback to return a default value for that path.'
+                );
+            }
+
+            $mapKey = $rowKey($value, $key);
+            if ($mapKey === null) {
+                throw new InvalidArgumentException(
+                    'Cannot index by path that does not exist or contains a null value. ' .
+                    'Use a callback to return a default value for that path.'
+                );
+            }
+
             $mapReduce->emitIntermediate(
-                [$rowKey($value, $key) => $rowVal($value, $key)],
+                [$mapKey => $rowVal($value, $key)],
                 $key
             );
         };

+ 39 - 0
tests/TestCase/Collection/CollectionTest.php

@@ -1241,6 +1241,45 @@ class CollectionTest extends TestCase
         $this->assertEquals([1 => null, 2 => null, 3 => null], $collection->toArray());
     }
 
+    public function testCombineNullKey(): void
+    {
+        $items = [
+            ['id' => 1, 'name' => 'foo', 'parent' => 'a'],
+            ['id' => null, 'name' => 'bar', 'parent' => 'b'],
+            ['id' => 3, 'name' => 'baz', 'parent' => 'a'],
+        ];
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Cannot index by path that does not exist or contains a null value');
+        (new Collection($items))->combine('id', 'name');
+    }
+
+    public function testCombineNullGroup(): void
+    {
+        $items = [
+            ['id' => 1, 'name' => 'foo', 'parent' => 'a'],
+            ['id' => 2, 'name' => 'bar', 'parent' => 'b'],
+            ['id' => 3, 'name' => 'baz', 'parent' => null],
+        ];
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Cannot group by path that does not exist or contains a null value');
+        (new Collection($items))->combine('id', 'name', 'parent');
+    }
+
+    public function testCombineGroupNullKey(): void
+    {
+        $items = [
+            ['id' => 1, 'name' => 'foo', 'parent' => 'a'],
+            ['id' => 2, 'name' => 'bar', 'parent' => 'b'],
+            ['id' => null, 'name' => 'baz', 'parent' => 'a'],
+        ];
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Cannot index by path that does not exist or contains a null value');
+        (new Collection($items))->combine('id', 'name', 'parent');
+    }
+
     /**
      * Tests the nest method with only one level
      */