Skip to content

Commit 3c4b238

Browse files
committed
feat: add ArrayHelper::dotKeyExists()
1 parent 3dedf9b commit 3c4b238

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

system/Helpers/Array/ArrayHelper.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace CodeIgniter\Helpers\Array;
1313

14+
use InvalidArgumentException;
15+
1416
/**
1517
* @interal This is internal implementation for the framework.
1618
*
@@ -112,6 +114,59 @@ private static function arraySearchDot(array $indexes, array $array)
112114
return null;
113115
}
114116

117+
/**
118+
* array_key_exists() with dot array syntax.
119+
*
120+
* If wildcard `*` is used, all items for the key after it must have the key.
121+
*/
122+
public static function dotKeyExists(string $index, array $array): bool
123+
{
124+
if (str_ends_with($index, '*') || str_contains($index, '*.*')) {
125+
throw new InvalidArgumentException(
126+
'You must set key right after "*". Invalid index: "' . $index . '"'
127+
);
128+
}
129+
130+
$indexes = self::convertToArray($index);
131+
132+
// If indexes is empty, returns false.
133+
if ($indexes === []) {
134+
return false;
135+
}
136+
137+
$currentArray = $array;
138+
139+
// Grab the current index
140+
while ($currentIndex = array_shift($indexes)) {
141+
if ($currentIndex === '*') {
142+
$currentIndex = array_shift($indexes);
143+
144+
foreach ($currentArray as $item) {
145+
if (! array_key_exists($currentIndex, $item)) {
146+
return false;
147+
}
148+
}
149+
150+
// If indexes is empty, all elements are checked.
151+
if ($indexes === []) {
152+
return true;
153+
}
154+
155+
$currentArray = self::dotSearch('*.' . $currentIndex, $currentArray);
156+
157+
continue;
158+
}
159+
160+
if (! array_key_exists($currentIndex, $currentArray)) {
161+
return false;
162+
}
163+
164+
$currentArray = $currentArray[$currentIndex];
165+
}
166+
167+
return true;
168+
}
169+
115170
/**
116171
* Groups all rows by their index values. Result's depth equals number of indexes
117172
*
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Helpers\Array;
13+
14+
use CodeIgniter\Test\CIUnitTestCase;
15+
use InvalidArgumentException;
16+
17+
/**
18+
* @group Others
19+
*
20+
* @internal
21+
*/
22+
final class ArrayHelperDotKeyExistsTest extends CIUnitTestCase
23+
{
24+
private array $array = [
25+
'contacts' => [
26+
'friends' => [
27+
['name' => 'Fred Flinstone', 'age' => 20],
28+
['age' => 21], // 'name' key does not exist
29+
],
30+
],
31+
];
32+
33+
public function testDotKeyExists(): void
34+
{
35+
$this->assertFalse(ArrayHelper::dotKeyExists('', $this->array));
36+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts', $this->array));
37+
$this->assertFalse(ArrayHelper::dotKeyExists('not', $this->array));
38+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends', $this->array));
39+
$this->assertFalse(ArrayHelper::dotKeyExists('not.friends', $this->array));
40+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends.0.name', $this->array));
41+
$this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.1.name', $this->array));
42+
}
43+
44+
public function testDotKeyExistsWithEndingWildCard(): void
45+
{
46+
$this->expectException(InvalidArgumentException::class);
47+
$this->expectExceptionMessage('You must set key right after "*". Invalid index: "contacts.*"');
48+
49+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*', $this->array));
50+
}
51+
52+
public function testDotKeyExistsWithDoubleWildCard(): void
53+
{
54+
$this->expectException(InvalidArgumentException::class);
55+
$this->expectExceptionMessage('You must set key right after "*". Invalid index: "contacts.*.*.age"');
56+
57+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.*.age', $this->array));
58+
}
59+
60+
public function testDotKeyExistsWithWildCard(): void
61+
{
62+
$this->assertTrue(ArrayHelper::dotKeyExists('*.friends', $this->array));
63+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends.*.age', $this->array));
64+
$this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.*.name', $this->array));
65+
$this->assertTrue(ArrayHelper::dotKeyExists('*.friends.*.age', $this->array));
66+
$this->assertFalse(ArrayHelper::dotKeyExists('*.friends.*.name', $this->array));
67+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.0.age', $this->array));
68+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.1.age', $this->array));
69+
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.0.name', $this->array));
70+
$this->assertFalse(ArrayHelper::dotKeyExists('contacts.*.1.name', $this->array));
71+
}
72+
}

0 commit comments

Comments
 (0)