Skip to content

Commit 8795381

Browse files
committed
feat: support objects in remaining dot array helpers
1 parent 12888fb commit 8795381

5 files changed

Lines changed: 254 additions & 48 deletions

File tree

system/Helpers/Array/ArrayHelper.php

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ private static function arraySearchDot(array $indexes, array|object $array)
146146
*
147147
* If wildcard `*` is used, all items for the key after it must have the key.
148148
*
149-
* @param array<array-key, mixed> $array
149+
* @param array<array-key, mixed>|object $array
150150
*/
151-
public static function dotHas(string $index, array $array): bool
151+
public static function dotHas(string $index, array|object $array): bool
152152
{
153153
self::ensureValidWildcardPattern($index);
154154

@@ -164,10 +164,10 @@ public static function dotHas(string $index, array $array): bool
164164
/**
165165
* Recursively check key existence by dot path, including wildcard support.
166166
*
167-
* @param array<array-key, mixed> $array
168-
* @param list<string> $indexes
167+
* @param array<array-key, mixed>|object $array
168+
* @param list<string> $indexes
169169
*/
170-
private static function hasByDotPath(array $array, array $indexes): bool
170+
private static function hasByDotPath(array|object $array, array $indexes): bool
171171
{
172172
if ($indexes === []) {
173173
return true;
@@ -176,28 +176,32 @@ private static function hasByDotPath(array $array, array $indexes): bool
176176
$currentIndex = array_shift($indexes);
177177

178178
if ($currentIndex === '*') {
179-
foreach ($array as $item) {
180-
if (! is_array($item) || ! self::hasByDotPath($item, $indexes)) {
179+
$iterable = is_object($array) ? self::toIterable($array) : $array;
180+
181+
foreach ($iterable as $item) {
182+
if ((! is_array($item) && ! is_object($item)) || ! self::hasByDotPath($item, $indexes)) {
181183
return false;
182184
}
183185
}
184186

185187
return true;
186188
}
187189

188-
if (! array_key_exists($currentIndex, $array)) {
190+
if (! self::valueExists($array, $currentIndex)) {
189191
return false;
190192
}
191193

192194
if ($indexes === []) {
193195
return true;
194196
}
195197

196-
if (! is_array($array[$currentIndex])) {
198+
$value = self::value($array, $currentIndex);
199+
200+
if (! is_array($value) && ! is_object($value)) {
197201
return false;
198202
}
199203

200-
return self::hasByDotPath($array[$currentIndex], $indexes);
204+
return self::hasByDotPath($value, $indexes);
201205
}
202206

203207
/**
@@ -247,12 +251,12 @@ public static function dotUnset(array &$array, string $index): bool
247251
/**
248252
* Gets only the specified keys using dot syntax.
249253
*
250-
* @param array<array-key, mixed> $array
251-
* @param list<string>|string $indexes
254+
* @param array<array-key, mixed>|object $array
255+
* @param list<string>|string $indexes
252256
*
253257
* @return array<array-key, mixed>
254258
*/
255-
public static function dotOnly(array $array, array|string $indexes): array
259+
public static function dotOnly(array|object $array, array|string $indexes): array
256260
{
257261
$indexes = is_string($indexes) ? [$indexes] : $indexes;
258262
$result = [];
@@ -261,7 +265,7 @@ public static function dotOnly(array $array, array|string $indexes): array
261265
self::ensureValidWildcardPattern($index, true);
262266

263267
if ($index === '*') {
264-
$result = [...$result, ...$array];
268+
$result = [...$result, ...(is_object($array) ? self::toIterable($array) : $array)];
265269

266270
continue;
267271
}
@@ -280,15 +284,15 @@ public static function dotOnly(array $array, array|string $indexes): array
280284
/**
281285
* Gets all keys except the specified ones using dot syntax.
282286
*
283-
* @param array<array-key, mixed> $array
284-
* @param list<string>|string $indexes
287+
* @param array<array-key, mixed>|object $array
288+
* @param list<string>|string $indexes
285289
*
286290
* @return array<array-key, mixed>
287291
*/
288-
public static function dotExcept(array $array, array|string $indexes): array
292+
public static function dotExcept(array|object $array, array|string $indexes): array
289293
{
290294
$indexes = is_string($indexes) ? [$indexes] : $indexes;
291-
$result = $array;
295+
$result = self::toArrayView($array);
292296

293297
foreach ($indexes as $index) {
294298
self::ensureValidWildcardPattern($index, true);
@@ -466,20 +470,20 @@ public static function sortValuesByNatural(array &$array, $sortByIndex = null):
466470
private static function valueExists(array|object $data, string $key): bool
467471
{
468472
if (is_array($data)) {
469-
return isset($data[$key]);
473+
return array_key_exists($key, $data);
470474
}
471475

472476
$array = self::entityToArray($data);
473477

474478
if ($array !== null) {
475-
return isset($array[$key]);
479+
return array_key_exists($key, $array);
476480
}
477481

478482
if ($data instanceof ArrayAccess && $data->offsetExists($key)) {
479483
return true;
480484
}
481485

482-
if (isset(get_object_vars($data)[$key])) {
486+
if (array_key_exists($key, get_object_vars($data))) {
483487
return true;
484488
}
485489

@@ -550,6 +554,26 @@ private static function toIterable(object $data): array
550554
return get_object_vars($data);
551555
}
552556

557+
/**
558+
* Normalize arrays or objects to an array view safe for dotExcept().
559+
*
560+
* @param array<array-key, mixed>|object $data
561+
*
562+
* @return array<array-key, mixed>
563+
*/
564+
private static function toArrayView(array|object $data): array
565+
{
566+
$array = is_object($data) ? self::toIterable($data) : $data;
567+
568+
foreach ($array as $key => $value) {
569+
if (is_array($value) || is_object($value)) {
570+
$array[$key] = self::toArrayView($value);
571+
}
572+
}
573+
574+
return $array;
575+
}
576+
553577
/**
554578
* Throws exception for invalid wildcard patterns.
555579
*/
@@ -688,14 +712,15 @@ private static function clearByDotPath(array &$array, array $indexes): int
688712
}
689713

690714
/**
691-
* Projects matching paths from source array into result with preserved structure.
715+
* Projects matching paths from source into result with preserved structure.
692716
*
693-
* @param list<string> $indexes
694-
* @param list<string> $prefix
695-
* @param array<array-key, mixed> $result
717+
* @param array<array-key, mixed>|object $source
718+
* @param list<string> $indexes
719+
* @param list<string> $prefix
720+
* @param array<array-key, mixed> $result
696721
*/
697722
private static function projectByDotPath(
698-
mixed $source,
723+
array|object $source,
699724
array $indexes,
700725
array &$result,
701726
array $prefix = [],
@@ -709,21 +734,37 @@ private static function projectByDotPath(
709734
$currentIndex = array_shift($indexes);
710735

711736
if ($currentIndex === '*') {
712-
if (! is_array($source)) {
713-
return;
714-
}
737+
$iterable = is_object($source) ? self::toIterable($source) : $source;
738+
739+
foreach ($iterable as $key => $value) {
740+
if (! is_array($value) && ! is_object($value)) {
741+
if ($indexes === []) {
742+
self::setByDotPath($result, [...$prefix, (string) $key], $value);
743+
}
744+
745+
continue;
746+
}
715747

716-
foreach ($source as $key => $value) {
717748
self::projectByDotPath($value, $indexes, $result, [...$prefix, (string) $key]);
718749
}
719750

720751
return;
721752
}
722753

723-
if (! is_array($source) || ! array_key_exists($currentIndex, $source)) {
754+
if (! self::valueExists($source, $currentIndex)) {
755+
return;
756+
}
757+
758+
$value = self::value($source, $currentIndex);
759+
760+
if (! is_array($value) && ! is_object($value)) {
761+
if ($indexes === []) {
762+
self::setByDotPath($result, [...$prefix, $currentIndex], $value);
763+
}
764+
724765
return;
725766
}
726767

727-
self::projectByDotPath($source[$currentIndex], $indexes, $result, [...$prefix, $currentIndex]);
768+
self::projectByDotPath($value, $indexes, $result, [...$prefix, $currentIndex]);
728769
}
729770
}

system/Helpers/array_helper.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ function dot_array_search(string $index, array|object $array)
3434
/**
3535
* Checks if an array key exists using dot syntax.
3636
*
37-
* @param array<array-key, mixed> $array
37+
* @param array<array-key, mixed>|object $array
3838
*/
39-
function dot_array_has(string $index, array $array): bool
39+
function dot_array_has(string $index, array|object $array): bool
4040
{
4141
return ArrayHelper::dotHas($index, $array);
4242
}
@@ -70,12 +70,12 @@ function dot_array_unset(array &$array, string $index): bool
7070
/**
7171
* Gets only the specified keys using dot syntax.
7272
*
73-
* @param array<array-key, mixed> $array
74-
* @param list<string>|string $indexes
73+
* @param array<array-key, mixed>|object $array
74+
* @param list<string>|string $indexes
7575
*
7676
* @return array<array-key, mixed>
7777
*/
78-
function dot_array_only(array $array, array|string $indexes): array
78+
function dot_array_only(array|object $array, array|string $indexes): array
7979
{
8080
return ArrayHelper::dotOnly($array, $indexes);
8181
}
@@ -85,12 +85,12 @@ function dot_array_only(array $array, array|string $indexes): array
8585
/**
8686
* Gets all keys except the specified ones using dot syntax.
8787
*
88-
* @param array<array-key, mixed> $array
89-
* @param list<string>|string $indexes
88+
* @param array<array-key, mixed>|object $array
89+
* @param list<string>|string $indexes
9090
*
9191
* @return array<array-key, mixed>
9292
*/
93-
function dot_array_except(array $array, array|string $indexes): array
93+
function dot_array_except(array|object $array, array|string $indexes): array
9494
{
9595
return ArrayHelper::dotExcept($array, $indexes);
9696
}

0 commit comments

Comments
 (0)