diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index 51bd12c743ec..cf76b3a56235 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -63,11 +63,26 @@ public static function add($array, $key, $value) /** * Get an array item from an array using "dot" notation. + * + * @param \ArrayAccess|array $array + * @param string|int|null $key + * @param array|null $default + * @param bool $throwOnNotFound + * @return array + * + * @throws \InvalidArgumentException + * @throws \Illuminate\Support\ItemNotFoundException */ - public static function array(ArrayAccess|array $array, string|int|null $key, ?array $default = null): array + public static function array(ArrayAccess|array $array, string|int|null $key, array $default = [], bool $throwOnNotFound = false): array { $value = Arr::get($array, $key, $default); + if ($throwOnNotFound && ! Arr::has($array, $key)) { + throw new ItemNotFoundException( + sprintf('Array key [%s] not found.', $key) + ); + } + if (! is_array($value)) { throw new InvalidArgumentException( sprintf('Array value for key [%s] must be an array, %s found.', $key, gettype($value)) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index ab5c2f2150a7..bfcbce5deb72 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -664,6 +664,66 @@ public function testItGetsAnArray() Arr::array($test_array, 'string'); } + public function testItReturnsEmptyArrayForMissingKeyByDefault() + { + $data = ['name' => 'Taylor']; + + $this->assertSame([], Arr::array($data, 'missing_key')); + } + + public function test_it_throws_item_not_found_exception_when_array_is_empty_and_throw_on_not_found_is_true() + { + $this->expectException(ItemNotFoundException::class); + $this->expectExceptionMessage('Array key [roles] not found.'); + + $data = []; + + Arr::array($data, 'roles', [], true); + } + + public function test_it_throws_item_not_found_exception_when_key_is_missing_and_throw_on_not_found_is_true() + { + $this->expectException(ItemNotFoundException::class); + $this->expectExceptionMessage('Array key [roles] not found.'); + + $data = ['name' => 'Taylor']; + + Arr::array($data, 'roles', [], true); + } + + public function test_it_supports_nested_keys_with_dot_notation() + { + $data = ['user' => ['roles' => ['admin']]]; + + $result = Arr::array($data, 'user.roles'); + + $this->assertSame(['admin'], $result); + } + + public function test_it_throws_for_nested_non_array_value() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches( + '#^Array value for key \[user.name\] must be an array, string found.#' + ); + + $data = ['user' => ['name' => 'Taylor']]; + + Arr::array($data, 'user.name'); + } + + public function test_it_should_not_throw_when_key_exists_even_if_equal_to_default() + { + $data = ['roles' => []]; + + // In the current (buggy) version without Arr::has(), + // this will wrongly throw ItemNotFoundException + // because $value === $default ([] === []). + $result = Arr::array($data, 'roles', [], true); + + $this->assertSame([], $result); // expected to return the actual empty array + } + public function testHas() { $array = ['products.desk' => ['price' => 100]];