11
11
12
12
namespace CodeIgniter \Helpers \Array ;
13
13
14
+ use InvalidArgumentException ;
15
+
14
16
/**
15
17
* @interal This is internal implementation for the framework.
16
18
*
@@ -27,9 +29,21 @@ final class ArrayHelper
27
29
*
28
30
* @used-by dot_array_search()
29
31
*
32
+ * @param string $index The index as dot array syntax.
33
+ *
30
34
* @return array|bool|int|object|string|null
31
35
*/
32
36
public static function dotSearch (string $ index , array $ array )
37
+ {
38
+ return self ::arraySearchDot (self ::convertToArray ($ index ), $ array );
39
+ }
40
+
41
+ /**
42
+ * @param string $index The index as dot array syntax.
43
+ *
44
+ * @return list<string> The index as an array.
45
+ */
46
+ private static function convertToArray (string $ index ): array
33
47
{
34
48
// See https://regex101.com/r/44Ipql/1
35
49
$ segments = preg_split (
@@ -39,9 +53,10 @@ public static function dotSearch(string $index, array $array)
39
53
PREG_SPLIT_NO_EMPTY
40
54
);
41
55
42
- $ segments = array_map (static fn ($ key ) => str_replace ('\. ' , '. ' , $ key ), $ segments );
43
-
44
- return self ::arraySearchDot ($ segments , $ array );
56
+ return array_map (
57
+ static fn ($ key ) => str_replace ('\. ' , '. ' , $ key ),
58
+ $ segments
59
+ );
45
60
}
46
61
47
62
/**
@@ -106,6 +121,59 @@ private static function arraySearchDot(array $indexes, array $array)
106
121
return null ;
107
122
}
108
123
124
+ /**
125
+ * array_key_exists() with dot array syntax.
126
+ *
127
+ * If wildcard `*` is used, all items for the key after it must have the key.
128
+ */
129
+ public static function dotKeyExists (string $ index , array $ array ): bool
130
+ {
131
+ if (str_ends_with ($ index , '* ' ) || str_contains ($ index , '*.* ' )) {
132
+ throw new InvalidArgumentException (
133
+ 'You must set key right after "*". Invalid index: " ' . $ index . '" '
134
+ );
135
+ }
136
+
137
+ $ indexes = self ::convertToArray ($ index );
138
+
139
+ // If indexes is empty, returns false.
140
+ if ($ indexes === []) {
141
+ return false ;
142
+ }
143
+
144
+ $ currentArray = $ array ;
145
+
146
+ // Grab the current index
147
+ while ($ currentIndex = array_shift ($ indexes )) {
148
+ if ($ currentIndex === '* ' ) {
149
+ $ currentIndex = array_shift ($ indexes );
150
+
151
+ foreach ($ currentArray as $ item ) {
152
+ if (! array_key_exists ($ currentIndex , $ item )) {
153
+ return false ;
154
+ }
155
+ }
156
+
157
+ // If indexes is empty, all elements are checked.
158
+ if ($ indexes === []) {
159
+ return true ;
160
+ }
161
+
162
+ $ currentArray = self ::dotSearch ('*. ' . $ currentIndex , $ currentArray );
163
+
164
+ continue ;
165
+ }
166
+
167
+ if (! array_key_exists ($ currentIndex , $ currentArray )) {
168
+ return false ;
169
+ }
170
+
171
+ $ currentArray = $ currentArray [$ currentIndex ];
172
+ }
173
+
174
+ return true ;
175
+ }
176
+
109
177
/**
110
178
* Groups all rows by their index values. Result's depth equals number of indexes
111
179
*
0 commit comments