PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.40
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.40
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
fluent-boards / vendor / wpfluent / framework / src / WPFluent / Support / Arr.php

Arr.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.40, at vendor/wpfluent/framework/src/WPFluent/Support/Arr.php

1,713 lines 43.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\Framework\Support;
4
5 use Closure;
6 use ArrayAccess;
7 use InvalidArgumentException;
8 use FluentBoards\Framework\Support\Helper;
9 use FluentBoards\Framework\Support\Collection;
10 use FluentBoards\Framework\Support\MacroableTrait;
11
12 class Arr
13 {
14 use MacroableTrait;
15
16 /**
17 * Makes a collection from array
18 *
19 * @param array $array
20 * @return FluentBoards\Framework\Support\Collection
21 */
22 public static function of(array $array)
23 {
24 return Helper::collect($array);
25 }
26
27 /**
28 * Determine whether the given value is array accessible.
29 *
30 * @param mixed $value
31 * @return bool
32 */
33 public static function accessible($value)
34 {
35 return is_array($value) || $value instanceof ArrayAccess;
36 }
37
38 /**
39 * Add an element to an array using "dot" notation if it doesn't exist.
40 *
41 * @param array $array
42 * @param string $key
43 * @param mixed $value
44 * @return array
45 */
46 public static function add($array, $key, $value)
47 {
48 if (is_null(static::get($array, $key))) {
49 static::set($array, $key, $value);
50 }
51
52 return $array;
53 }
54
55 /**
56 * Collapse an array of arrays into a single array.
57 *
58 * @param iterable $array
59 * @return array
60 */
61 public static function collapse($array)
62 {
63 $results = [];
64
65 foreach ($array as $values) {
66 if ($values instanceof Collection) {
67 $values = $values->all();
68 } elseif (! is_array($values)) {
69 continue;
70 }
71
72 $results[] = $values;
73 }
74
75 return array_merge([], ...$results);
76 }
77
78 /**
79 * Cross join the given arrays, returning all possible permutations.
80 *
81 * @param iterable ...$arrays
82 * @return array
83 */
84 public static function crossJoin(...$arrays)
85 {
86 $results = [[]];
87
88 foreach ($arrays as $index => $array) {
89 $append = [];
90
91 foreach ($results as $product) {
92 foreach ($array as $item) {
93 $product[$index] = $item;
94
95 $append[] = $product;
96 }
97 }
98
99 $results = $append;
100 }
101
102 return $results;
103 }
104
105 /**
106 * Divide an array into two arrays. One with keys and the other with values.
107 *
108 * @param array $array
109 * @return array
110 */
111 public static function divide($array)
112 {
113 return [array_keys($array), array_values($array)];
114 }
115
116 /**
117 * Flatten a multi-dimensional associative array with dots.
118 *
119 * @param iterable $array
120 * @param string $prepend
121 * @return array
122 */
123 public static function dot($array, $prepend = '')
124 {
125 $results = [];
126
127 foreach ($array as $key => $value) {
128 if (is_array($value) && ! empty($value)) {
129 $results = array_merge($results, static::dot($value, $prepend.$key.'.'));
130 } else {
131 $results[$prepend.$key] = $value;
132 }
133 }
134
135 return $results;
136 }
137
138 /**
139 * Convert a flatten "dot" notation array into an expanded array.
140 *
141 * @param iterable $array
142 * @return array
143 */
144 public static function undot($array)
145 {
146 $results = [];
147
148 foreach ($array as $key => $value) {
149 static::set($results, $key, $value);
150 }
151
152 return $results;
153 }
154
155 /**
156 * Get all of the given array except for a specified array of keys.
157 *
158 * @param array $array
159 * @param array|string $keys
160 * @return array
161 */
162 public static function except($array, $keys)
163 {
164 static::forget($array, $keys);
165
166 return $array;
167 }
168
169 /**
170 * Determine if the given key exists in the provided array.
171 *
172 * @param \ArrayAccess|array $array
173 * @param string|int $key
174 * @return bool
175 */
176 public static function exists($array, $key)
177 {
178 if ($array instanceof Enumerable) {
179 return $array->has($key);
180 }
181
182 if ($array instanceof ArrayAccess) {
183 return $array->offsetExists($key);
184 }
185
186 return array_key_exists($key, $array);
187 }
188
189 /**
190 * Alias of exists.
191 * @param \ArrayAccess|array $array
192 * @param string|int $key
193 * @return bool
194 */
195 public static function keyExists($array, $key)
196 {
197 return static::exists($array, $key);
198 }
199
200 /**
201 * Alias of exists.
202 * @param \ArrayAccess|array $array
203 * @param string|int $key
204 * @return bool
205 */
206 public static function arrayKeyExists($array, $key)
207 {
208 return static::exists($array, $key);
209 }
210
211 /**
212 * Return the first element in an array passing a given truth test.
213 *
214 * @param iterable $array
215 * @param callable|null $callback
216 * @param mixed $default
217 * @return mixed
218 */
219 public static function first($array, ?callable $callback = null, $default = null)
220 {
221 if (is_null($callback)) {
222 if (empty($array)) {
223 return Helper::value($default);
224 }
225
226 foreach ($array as $item) {
227 return $item;
228 }
229 }
230
231 foreach ($array as $key => $value) {
232 if ($callback($value, $key)) {
233 return $value;
234 }
235 }
236
237 return Helper::value($default);
238 }
239
240 /**
241 * Returns the key of the first item (matching the specified
242 * callback if given) or null if there is no such item.
243 *
244 * @param array $array
245 * @param callable|null $callback
246 * @return mixed
247 */
248 public static function firstKey($array, ?callable $callback = null)
249 {
250 if (!$callback) {
251 return array_key_first($array);
252 }
253
254 foreach ($array as $k => $v) {
255 if ($callback($v, $k, $array)) {
256 return $k;
257 }
258 }
259
260 return null;
261 }
262
263 /**
264 * Recursively filter an array like array_filter.
265 *
266 * @param array $array
267 * @param callable|null $cb
268 * @param integer $mode (ARRAY_FILTER_USE_BOTH = 1 | ARRAY_FILTER_USE_KEY = 2)
269 * @return array
270 */
271 public static function filterRecursive($array, ?callable $cb = null, $mode = 0)
272 {
273 $result = [];
274
275 foreach ($array as $key => $value) {
276 if (is_array($value)) {
277 if (is_int($key)) {
278 $result[] = static::filterRecursive($value, $cb, $mode);
279 } else {
280 $result[$key] = static::filterRecursive($value, $cb, $mode);
281 }
282 } else {
283 if (is_null($cb)) {
284 if ($value) {
285 if (is_int($key)) {
286 $result[] = $value;
287 } else {
288 $result[$key] = $value;
289 }
290 }
291 } else {
292 if ($mode && call_user_func($cb, $value, $key)) {
293 if (is_int($key)) {
294 $result[] = $value;
295 } else {
296 $result[$key] = $value;
297 }
298 } elseif (!$mode && call_user_func($cb, $value)) {
299 if (is_int($key)) {
300 $result[] = $value;
301 } else {
302 $result[$key] = $value;
303 }
304 }
305 }
306 }
307 }
308
309 return $result;
310 }
311
312 /**
313 * Recursively search the value and return the path of first match.
314 *
315 * @param array $array
316 * @param mixed $value
317 * @param bool $ci (false for case insensitive search, true otherwise)
318 * @return array|null
319 */
320 public static function findPath($array, $value, $ci = false)
321 {
322 if (!$ci) {
323 $value = strtolower($value);
324 $array = static::map($array, 'strtolower');
325 }
326
327 foreach ($array as $key => $val) {
328 if ($val === $value) {
329 return $key;
330 } elseif (is_array($val) && $path = static::findPath($val, $value, $ci)) {
331 return $key.'.'.$path;
332 }
333 }
334 }
335
336 /**
337 * Return the last element in an array passing a given truth test.
338 *
339 * @param array $array
340 * @param callable|null $callback
341 * @param mixed $default
342 * @return mixed
343 */
344 public static function last($array, ?callable $callback = null, $default = null)
345 {
346 if (is_null($callback)) {
347 return empty($array) ? Helper::value($default) : end($array);
348 }
349
350 return static::first(array_reverse($array, true), $callback, $default);
351 }
352
353 /**
354 * Returns the key of the last item (matching the specified
355 * callback if given) or null if there is no such item.
356 *
357 * @param array $array
358 * @param callable|null $callback
359 * @return mixed
360 */
361 public static function lastKey($array, ?callable $callback = null)
362 {
363 if (!$callback) {
364 return array_key_last($array);
365 }
366
367 $lastKey = null;
368
369 foreach ($array as $k => $v) {
370 if ($callback($v, $k, $array)) {
371 $lastKey = $k;
372 }
373 }
374
375 return $lastKey;
376 }
377
378 /**
379 * Flatten a multi-dimensional array into a single level.
380 *
381 * @param iterable $array
382 * @param int $depth
383 * @return array
384 */
385 public static function flatten($array, $depth = INF)
386 {
387 $result = [];
388
389 foreach ($array as $item) {
390 $item = $item instanceof Collection ? $item->all() : $item;
391
392 if (! is_array($item)) {
393 $result[] = $item;
394 } else {
395 $values = $depth === 1
396 ? array_values($item)
397 : static::flatten($item, $depth - 1);
398
399 foreach ($values as $value) {
400 $result[] = $value;
401 }
402 }
403 }
404
405 return $result;
406 }
407
408 /**
409 * Remove one or many array items from a given array using "dot" notation.
410 *
411 * @param array $array
412 * @param array|string $keys
413 * @return void
414 */
415 public static function forget(&$array, $keys)
416 {
417 $original = &$array;
418
419 $keys = (array) $keys;
420
421 if (count($keys) === 0) {
422 return;
423 }
424
425 foreach ($keys as $key) {
426 // if the exact key exists in the top-level, remove it
427 if (static::exists($array, $key)) {
428 unset($array[$key]);
429
430 continue;
431 }
432
433 $parts = explode('.', $key);
434
435 // clean up before each pass
436 $array = &$original;
437
438 while (count($parts) > 1) {
439 $part = array_shift($parts);
440
441 if (isset($array[$part]) && is_array($array[$part])) {
442 $array = &$array[$part];
443 } else {
444 continue 2;
445 }
446 }
447
448 unset($array[array_shift($parts)]);
449 }
450 }
451
452 /**
453 * Get an item from an array using "dot" notation.
454 *
455 * @param \ArrayAccess|array $array
456 * @param string|int|null $key
457 * @param mixed $default
458 * @return mixed
459 */
460 public static function get($array, $key, $default = null)
461 {
462 if (! static::accessible($array)) {
463 return Helper::value($default);
464 }
465
466 if (is_null($key)) {
467 return $array;
468 }
469
470 if (static::exists($array, $key)) {
471 return $array[$key];
472 }
473
474 if (strpos($key, '.') === false) {
475 return $array[$key] ?? Helper::value($default);
476 }
477
478 foreach (explode('.', $key) as $segment) {
479 if (static::accessible($array) && static::exists($array, $segment)) {
480 $array = $array[$segment];
481 } else {
482 return Helper::value($default);
483 }
484 }
485
486 return $array;
487 }
488
489 /**
490 * Check if an item or items (using key) exist in an array using "dot" notation.
491 *
492 * @param \ArrayAccess|array $array
493 * @param string|array $keys
494 * @return bool
495 */
496 public static function has($array, $keys)
497 {
498 $keys = (array) $keys;
499
500 if (! $array || $keys === []) {
501 return false;
502 }
503
504 foreach ($keys as $key) {
505 $subKeyArray = $array;
506
507 if (static::exists($array, $key)) {
508 continue;
509 }
510
511 foreach (explode('.', $key) as $segment) {
512 if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {
513 $subKeyArray = $subKeyArray[$segment];
514 } else {
515 return false;
516 }
517 }
518 }
519
520 return true;
521 }
522
523 /**
524 * Determine if any of the keys exist in an array using "dot" notation.
525 *
526 * @param \ArrayAccess|array $array
527 * @param string|array $keys
528 * @return bool
529 */
530 public static function hasAny($array, $keys)
531 {
532 if (is_null($keys)) {
533 return false;
534 }
535
536 $keys = (array) $keys;
537
538 if (! $array) {
539 return false;
540 }
541
542 if ($keys === []) {
543 return false;
544 }
545
546 foreach ($keys as $key) {
547 if (static::has($array, $key)) {
548 return true;
549 }
550 }
551
552 return false;
553 }
554
555 /**
556 * Alias of contains.
557 *
558 * @param array $array
559 * @param string|array $values
560 * @return bool
561 */
562 public static function inArray($array, $value)
563 {
564 return static::contains($array, $value);
565 }
566
567 /**
568 * Determines if an array is associative.
569 *
570 * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
571 *
572 * @param array $array
573 * @return bool
574 */
575 public static function isAssoc(array $array)
576 {
577 $keys = array_keys($array);
578
579 return array_keys($keys) !== $keys;
580 }
581
582 /**
583 * Determines if an array is a list.
584 *
585 * An array is a "list" if all array keys are sequential integers starting from 0 with no gaps in between.
586 *
587 * @param array $array
588 * @return bool
589 */
590 public static function isList($array)
591 {
592 return ! self::isAssoc($array);
593 }
594
595 /**
596 * Determines if the given key contains a boolean value.
597 *
598 * Returns true for true, 1, "1", "true", "on" and "yes"
599 * Returns false for false, "0", "false", "off", "no", and ""
600 * Returns for all non-boolean values.
601 *
602 * @param array $array
603 * @param string $key
604 *
605 * @return bool|null
606 * @see https://www.php.net/manual/en/filter.filters.validate.php
607 */
608 public static function isTrue($array, $key)
609 {
610 return filter_var(
611 static::get($array, $key),
612 FILTER_VALIDATE_BOOLEAN,
613 FILTER_NULL_ON_FAILURE
614 );
615 }
616
617 /**
618 * Get a subset of the items from the given array.
619 *
620 * @param array $array
621 * @param array|string $keys
622 * @return array
623 */
624 public static function only($array, $keys)
625 {
626 return array_intersect_key($array, array_flip((array) $keys));
627 }
628
629 /**
630 * Select an array of values from an array.
631 *
632 * @param array $array
633 * @param array|string $keys
634 * @return array
635 */
636 public static function select($array, $keys)
637 {
638 $keys = static::wrap($keys);
639
640 return array_map(function ($item) use ($keys) {
641 $result = [];
642
643 $item = (array) $item;
644
645 foreach ($keys as $key) {
646
647 if (static::accessible($item) && static::has($item, $key)) {
648
649 [$first] = explode('.', $key);
650
651 $result[$first] = static::get($item, $first);
652 }
653 }
654
655 return $result;
656
657 }, (array) $array);
658 }
659
660 /**
661 * Pluck an array of values from an array.
662 *
663 * @param iterable $array
664 * @param string|array|int|null $value
665 * @param string|array|null $key
666 * @return array
667 */
668 public static function pluck($array, $value, $key = null)
669 {
670 $results = [];
671
672 [$value, $key] = static::explodePluckParameters($value, $key);
673
674 foreach ($array as $item) {
675 $itemValue = Helper::dataGet($item, $value);
676
677 // If the key is "null", we will just append the value to the array and keep
678 // looping. Otherwise we will key the array using the value of the key we
679 // received from the developer. Then we'll return the final array form.
680 if (is_null($key)) {
681 $results[] = $itemValue;
682 } else {
683 $itemKey = Helper::dataGet($item, $key);
684
685 if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
686 $itemKey = (string) $itemKey;
687 }
688
689 $results[$itemKey] = $itemValue;
690 }
691 }
692
693 return $results;
694 }
695
696 /**
697 * Explode the "value" and "key" arguments passed to "pluck".
698 *
699 * @param string|array $value
700 * @param string|array|null $key
701 * @return array
702 */
703 protected static function explodePluckParameters($value, $key)
704 {
705 $value = is_string($value) ? explode('.', $value) : $value;
706
707 $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
708
709 return [$value, $key];
710 }
711
712 /**
713 * Push an item onto the beginning of an array.
714 *
715 * @param array $array
716 * @param mixed $value
717 * @param mixed $key
718 * @return array
719 */
720 public static function prepend($array, $value, $key = null)
721 {
722 if (func_num_args() == 2) {
723 array_unshift($array, $value);
724 } else {
725 $array = [$key => $value] + $array;
726 }
727
728 return $array;
729 }
730
731 /**
732 * Get a value from the array, and remove it.
733 *
734 * @param array $array
735 * @param string|int $key
736 * @param mixed $default
737 * @return mixed
738 */
739 public static function pull(&$array, $key, $default = null)
740 {
741 $value = static::get($array, $key, $default);
742
743 static::forget($array, $key);
744
745 return $value;
746 }
747
748 /**
749 * Convert the array into a query string.
750 *
751 * @param array $array
752 * @return string
753 */
754 public static function query($array)
755 {
756 return http_build_query($array, '', '&', PHP_QUERY_RFC3986);
757 }
758
759 /**
760 * Get one or a specified number of random values from an array.
761 *
762 * @param array $array
763 * @param int|null $number
764 * @param bool|false $preserveKeys
765 * @return mixed
766 *
767 * @throws \InvalidArgumentException
768 */
769 public static function random($array, $number = null, $preserveKeys = false)
770 {
771 $requested = is_null($number) ? 1 : $number;
772
773 $count = count($array);
774
775 if ($requested > $count) {
776 throw new InvalidArgumentException(
777 "You requested {$requested} items, but there are only {$count} items available."
778 );
779 }
780
781 if (is_null($number)) {
782 return $array[array_rand($array)];
783 }
784
785 if ((int) $number === 0) {
786 return [];
787 }
788
789 $keys = array_rand($array, $number);
790
791 $results = [];
792
793 if ($preserveKeys) {
794 foreach ((array) $keys as $key) {
795 $results[$key] = $array[$key];
796 }
797 } else {
798 foreach ((array) $keys as $key) {
799 $results[] = $array[$key];
800 }
801 }
802
803 return $results;
804 }
805
806 /**
807 * Set an array item to a given value using "dot" notation.
808 *
809 * If no key is given to the method, the entire array will be replaced.
810 *
811 * @param array $array
812 * @param string|null $key
813 * @param mixed $value
814 * @return array
815 */
816 public static function set(&$array, $key, $value)
817 {
818 if (is_null($key)) {
819 return $array = $value;
820 }
821
822 $keys = explode('.', $key);
823
824 foreach ($keys as $i => $key) {
825 if (count($keys) === 1) {
826 break;
827 }
828
829 unset($keys[$i]);
830
831 // If the key doesn't exist at this depth, we will just create an empty array
832 // to hold the next value, allowing us to create the arrays to hold final
833 // values at the correct depth. Then we'll keep digging into the array.
834 if (! isset($array[$key]) || ! is_array($array[$key])) {
835 $array[$key] = [];
836 }
837
838 $array = &$array[$key];
839 }
840
841 $array[array_shift($keys)] = $value;
842
843 return $array;
844 }
845
846 /**
847 * Shuffle the given array and return the result.
848 *
849 * @param array $array
850 * @param int|null $seed
851 * @return array
852 */
853 public static function shuffle($array, $seed = null)
854 {
855 if (!is_null($seed)) {
856 mt_srand($seed);
857 usort($array, function () {
858 return mt_rand(-1, 1);
859 });
860 mt_srand();
861 } else {
862 shuffle($array);
863 }
864
865 return $array;
866 }
867
868 /**
869 * Sort the array using the given callback or "dot" notation.
870 *
871 * @param array $array
872 * @param callable|array|string|null $callback
873 * @return array
874 */
875 public static function sort($array, $callback = null)
876 {
877 return Collection::make($array)->sortBy($callback)->all();
878 }
879
880 /**
881 * Sort an array in descending order.
882 *
883 * @param array $array
884 * @param Flags
885 * @return array
886 * @see https://www.php.net/manual/en/function.rsort.php
887 */
888 public static function rsort($array, $flags = SORT_REGULAR)
889 {
890 rsort($array, $flags);
891 return $array;
892 }
893
894 /**
895 * Sort an array in ascending order and maintain index association.
896 *
897 * @param array $array
898 * @param Flags
899 * @return array
900 * @see https://www.php.net/manual/en/function.asort.php
901 */
902 public static function asort($array, $flags = SORT_REGULAR)
903 {
904 asort($array, $flags);
905 return $array;
906 }
907
908 /**
909 * Sort an array in descending order and maintain index association.
910 *
911 * @param array $array
912 * @param Flags
913 * @return array
914 * @see https://www.php.net/manual/en/function.arsort.php
915 */
916 public static function arsort($array, $flags = SORT_REGULAR)
917 {
918 arsort($array, $flags);
919 return $array;
920 }
921
922 /**
923 * Sort an array by key in ascending order.
924 *
925 * @param array $array
926 * @param Flags
927 * @return array
928 * @see https://www.php.net/manual/en/function.ksort.php
929 */
930 public static function ksort($array, $flags = SORT_REGULAR)
931 {
932 ksort($array, $flags);
933 return $array;
934 }
935
936 /**
937 * Sort an array by key in descending order.
938 *
939 * @param array $array
940 * @param Flags
941 * @return array
942 * @see https://www.php.net/manual/en/function.krsort.php
943 */
944 public static function krsort($array, $flags = SORT_REGULAR)
945 {
946 krsort($array, $flags);
947 return $array;
948 }
949
950 /**
951 * Sort an array using a "natural order" algorithm.
952 *
953 * @param array $array
954 * @return array
955 * @see https://www.php.net/manual/en/function.natsort.php
956 */
957 public static function natsort($array)
958 {
959 natsort($array);
960 return $array;
961 }
962
963 /**
964 * Sort an array using a case insensitive "natural order" algorithm.
965 *
966 * @param array $array
967 * @return array
968 * @see https://www.php.net/manual/en/function.natcasesort.php
969 */
970 public static function natcasesort($array)
971 {
972 natcasesort($array);
973 return $array;
974 }
975
976 /**
977 * Sort an array by values using a user-defined comparison function.
978 *
979 * @param array $array
980 * @return array
981 * @see https://www.php.net/manual/en/function.usort.php
982 */
983 public static function usort($array, callable $callback)
984 {
985 usort($array, $callback);
986 return $array;
987 }
988
989 /**
990 * Sort an array with a user-defined comparison
991 * function and maintain index association.
992 *
993 * @param array $array
994 * @return array
995 * @see https://www.php.net/manual/en/function.uasort.php
996 */
997 public static function uasort($array, callable $callback)
998 {
999 uasort($array, $callback);
1000 return $array;
1001 }
1002
1003 /**
1004 * Sort an array by keys using a user-defined comparison function.
1005 *
1006 * @param array $array
1007 * @return array
1008 * @see https://www.php.net/manual/en/function.uksort.php
1009 */
1010 public static function uksort($array, callable $callback)
1011 {
1012 uksort($array, $callback);
1013 return $array;
1014 }
1015
1016 /**
1017 * Recursively sort an array by keys and values.
1018 *
1019 * @param array $array
1020 * @param int $options
1021 * @param bool $desc
1022 * @return array
1023 */
1024 public static function sortRecursive($array, $options = SORT_REGULAR, $desc = false)
1025 {
1026 foreach ($array as &$value) {
1027 if (is_array($value)) {
1028 $value = static::sortRecursive($value, $options, $desc);
1029 }
1030 }
1031
1032 if (static::isAssoc($array)) {
1033 $desc
1034 ? krsort($array, $options)
1035 : ksort($array, $options);
1036 } else {
1037 $desc
1038 ? rsort($array, $options)
1039 : sort($array, $options);
1040 }
1041
1042 return $array;
1043 }
1044
1045 /**
1046 * Conditionally compile classes from an array into a CSS class list.
1047 *
1048 * @param array $array
1049 * @return string
1050 */
1051 public static function toCssClasses($array)
1052 {
1053 $classList = static::wrap($array);
1054
1055 $classes = [];
1056
1057 foreach ($classList as $class => $constraint) {
1058 if (is_numeric($class)) {
1059 $classes[] = $constraint;
1060 } elseif ($constraint) {
1061 $classes[] = $class;
1062 }
1063 }
1064
1065 return implode(' ', $classes);
1066 }
1067
1068 /**
1069 * Transforms an array to \stdClass
1070 * @param array $array
1071 * @return \stdClass
1072 */
1073 public static function toObject($array)
1074 {
1075 return StdObject::create($array);
1076 }
1077
1078 /**
1079 * Filter the array using the given callback.
1080 *
1081 * @param array $array
1082 * @param callable $callback
1083 * @return array
1084 */
1085 public static function where($array, callable $callback)
1086 {
1087 return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
1088 }
1089
1090 /**
1091 * Filter items where the value is not null.
1092 *
1093 * @param array $array
1094 * @return array
1095 */
1096 public static function whereNotNull($array)
1097 {
1098 return static::where($array, function ($value) {
1099 return ! is_null($value);
1100 });
1101 }
1102
1103 /**
1104 * Filter items where the value is not null.
1105 *
1106 * @param array $array
1107 * @return array
1108 */
1109 public static function whereNotTrue($array, $strict = false)
1110 {
1111 return static::where($array, function ($value) use ($strict) {
1112 return $strict ? $value === false : !$value;
1113 });
1114 }
1115
1116 /**
1117 * If the given value is not an array and not null, wrap it in one.
1118 *
1119 * @param mixed $value
1120 * @return array
1121 */
1122 public static function wrap($value)
1123 {
1124 if (is_null($value)) {
1125 return [];
1126 }
1127
1128 return is_array($value) ? $value : [$value];
1129 }
1130
1131 /**
1132 * Maps a function to all non-iterable elements of an array or an object.
1133 *
1134 * This is similar to `array_walk_recursive()` but acts upon objects too.
1135 *
1136 * @param mixed $value The array, object, or scalar.
1137 * @param callable $callback The function to map onto $value.
1138 * @see https://developer.wordpress.org/reference/functions/map_deep/
1139 *
1140 * @return mixed The value with the callback applied to all non-arrays and non-objects inside it.
1141 */
1142 public static function map($value, $callback)
1143 {
1144 return map_deep($value, $callback);
1145 }
1146
1147 /**
1148 * Check if the value(s) exist in an array using "dot" notation.
1149 *
1150 * @param array $array
1151 * @param string|array $values
1152 * @return bool
1153 */
1154 public static function contains(array $array, $values)
1155 {
1156 $result = [];
1157
1158 $values = is_array($values) ? $values : [$values];
1159
1160 foreach ($values as $value) {
1161
1162 if (in_array($value, $array)) {
1163 $result[] = $value;
1164 continue;
1165 }
1166
1167 $segments = explode('.', $value);
1168
1169 $value = array_pop($segments);
1170
1171 $nested = (array) static::get($array, implode('.', $segments));
1172
1173 if ($nested && in_array($value, $nested)) {
1174 $result[] = $value;
1175 }
1176 }
1177
1178 return count($result) === count($values);
1179 }
1180
1181 /**
1182 * Check if the any value exist in an array using "dot" notation.
1183 *
1184 * @param array $array
1185 * @param string|array $values
1186 * @return bool
1187 */
1188 public static function containsAny(array $array, $values)
1189 {
1190 $result = [];
1191
1192 $values = is_array($values) ? $values : [$values];
1193
1194 foreach ($values as $value) {
1195
1196 if (in_array($value, $array)) {
1197 return true;
1198 }
1199
1200 $segments = explode('.', $value);
1201
1202 $value = array_pop($segments);
1203
1204 $nested = (array) static::get($array, implode('.', $segments));
1205
1206 if ($nested && in_array($value, $nested)) {
1207 return true;
1208 }
1209 }
1210
1211 return false;
1212 }
1213
1214 /**
1215 * Compare two nested arrays side by side
1216 * @param array $array1
1217 * @param array $array2
1218 * @param array $path
1219 * @return array
1220 */
1221 public static function compare($array1, $array2, $path = [])
1222 {
1223 $differences = [];
1224
1225 foreach ($array1 as $key => $value1) {
1226 // Check if the key exists in the second array
1227 if (!array_key_exists($key, $array2)) {
1228 $differences[implode('.', array_merge($path, [$key]))] = [
1229 'array_1' => $value1,
1230 'array_2' => null,
1231 ];
1232 } else {
1233 // If the value is an array, recursively compare
1234 if (is_array($value1) && is_array($array2[$key])) {
1235 $differences = array_merge($differences, static::compare(
1236 $value1, $array2[$key], array_merge($path, [$key])
1237 ));
1238 } else {
1239 // Compare values
1240 if ($value1 !== $array2[$key]) {
1241 $differences[implode('.', array_merge($path, [$key]))] = [
1242 'array_1' => $value1,
1243 'array_2' => $array2[$key],
1244 ];
1245 }
1246 }
1247 }
1248 }
1249
1250 // Check for keys in the second array that are not in the first array
1251 foreach ($array2 as $key => $value2) {
1252 if (!array_key_exists($key, $array1)) {
1253 $differences[implode('.', array_merge($path, [$key]))] = [
1254 'array_1' => null,
1255 'array_2' => $value2,
1256 ];
1257 }
1258 }
1259
1260 return $differences;
1261 }
1262
1263 /**
1264 * Merge the items from the first array into the
1265 * second array if the second array is missing it.
1266 *
1267 * @param array &$array1
1268 * @param array &$array2
1269 * @return array
1270 */
1271 public static function mergeMissing(&$array1, &$array2)
1272 {
1273 foreach ($array1 as $key => $value1) {
1274 // If the key exists in the second array
1275 if (array_key_exists($key, $array2)) {
1276 // If the value is an array, recursively add missing items
1277 if (is_array($value1) && is_array($array2[$key])) {
1278 static::mergeMissing($value1, $array2[$key]);
1279 }
1280 } else {
1281 // If the key doesn't exist in the second array,
1282 // then add it with the corresponding value
1283 $array2[$key] = $value1;
1284 }
1285 }
1286
1287 return $array2;
1288 }
1289
1290 /**
1291 * Recursively merge the given array with defaults.
1292 * Overwrite $array with $defaults if only $array
1293 * contains null or empty values or doesn't exist.
1294 *
1295 * @param array $array
1296 * @param array $defaults
1297 * @return array
1298 */
1299 public static function mergeMissingValues(array $array, array $defaults)
1300 {
1301 $merged = array_merge($defaults, $array);
1302
1303 foreach ($merged as $key => $value) {
1304 if (
1305 is_array($value) &&
1306 isset($defaults[$key]) &&
1307 is_array($defaults[$key])
1308 ) {
1309 // Recursively merge arrays
1310 $merged[$key] = static::mergeMissingValues(
1311 $value, $defaults[$key]
1312 );
1313 } elseif (
1314 isset($defaults[$key]) &&
1315 (is_null($value) || $value === '')
1316 ) {
1317 // Replace null or empty values
1318 $merged[$key] = $defaults[$key];
1319 }
1320 }
1321
1322 return $merged;
1323 }
1324
1325 /**
1326 * Return matching items from array (similar to mysql's %LIKE%)
1327 *
1328 * @param string|regex $pattern
1329 * @param array $array
1330 * @return array|false
1331 */
1332 public static function like($array, $pattern)
1333 {
1334 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1335 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1336 }
1337
1338 return preg_grep($pattern, $array);
1339 }
1340
1341 /**
1342 * Return non-matching items from array (similar to mysql's NOT %LIKE%)
1343 *
1344 * @param string|regex $pattern
1345 * @param array $array
1346 * @return array|false
1347 */
1348 public static function notLike($array, $pattern)
1349 {
1350 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1351 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1352 }
1353
1354 return preg_grep($pattern, $array, PREG_GREP_INVERT);
1355 }
1356
1357 /**
1358 * Return matching starting of items from array (similar to mysql's %LIKE)
1359 *
1360 * @param string|regex $pattern
1361 * @param array $array
1362 * @return array|false
1363 */
1364 public static function startsLike($array, $pattern)
1365 {
1366 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1367 $pattern = '~^'. preg_quote($pattern, '~') . '~i';
1368 }
1369
1370 return preg_grep($pattern, $array);
1371 }
1372
1373 /**
1374 * Return non-matching starting of items from array (similar to mysql's NOT %LIKE)
1375 *
1376 * @param string|regex $pattern
1377 * @param array $array
1378 * @return array|false
1379 */
1380 public static function DoesNotStartLike($array, $pattern)
1381 {
1382 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1383 $pattern = '~^(?!' . preg_quote($pattern, '~') . ')~i';
1384 }
1385
1386 return preg_grep($pattern, $array);
1387 }
1388
1389 /**
1390 * Return matching ending of items from array (similar to mysql's LIKE%)
1391 *
1392 * @param string|regex $pattern
1393 * @param array $array
1394 * @return array|false
1395 */
1396 public static function endsLike($array, $pattern)
1397 {
1398 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1399 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1400 }
1401
1402 return preg_grep($pattern, $array);
1403 }
1404
1405 /**
1406 * Return non-matching ending of items from array (similar to mysql's NOT LIKE%)
1407 *
1408 * @param string|regex $pattern
1409 * @param array $array
1410 * @return array|false
1411 */
1412 public static function DoesNotEndLike($array, $pattern)
1413 {
1414 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1415 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1416 }
1417
1418 return preg_grep($pattern, $array, PREG_GREP_INVERT);
1419 }
1420
1421 /**
1422 * Return matching items from array by keys
1423 *
1424 * @param string|regex $pattern
1425 * @param array $array
1426 * @return array|false
1427 */
1428 public static function keysLike($array, $pattern)
1429 {
1430 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1431 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1432 }
1433
1434 $values = [];
1435
1436 $keys = preg_grep($pattern, array_keys($array));
1437
1438 foreach ($keys as $key) {
1439 $values[$key] = $array[$key];
1440 }
1441
1442 return $values;
1443 }
1444
1445 /**
1446 * Return non-matching items from array by keys
1447 *
1448 * @param string|regex $pattern
1449 * @param array $array
1450 * @return array|false
1451 */
1452 public static function keysNotLike($array, $pattern)
1453 {
1454 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1455 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1456 }
1457
1458 $values = [];
1459
1460 $keys = preg_grep($pattern, array_keys($array), 1);
1461
1462 foreach ($keys as $key) {
1463 $values[$key] = $array[$key];
1464 }
1465
1466 return $values;
1467 }
1468
1469 /**
1470 * Return matching starting of items from array by keys
1471 *
1472 * @param string|regex $pattern
1473 * @param array $array
1474 * @return array|false
1475 */
1476 public static function keysStartLike($array, $pattern)
1477 {
1478 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1479 $pattern = '~^'. preg_quote($pattern, '~') . '~i';
1480 }
1481
1482 $values = [];
1483
1484 $keys = preg_grep($pattern, array_keys($array));
1485
1486 foreach ($keys as $key) {
1487 $values[$key] = $array[$key];
1488 }
1489
1490 return $values;
1491 }
1492
1493 /**
1494 * Return non-matching starting of items from array by keys
1495 *
1496 * @param string|regex $pattern
1497 * @param array $array
1498 * @return array|false
1499 */
1500 public static function keysDoesNotStartLike($array, $pattern)
1501 {
1502 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1503 $pattern = '~^(?!' . preg_quote($pattern, '~') . ')~i';
1504 }
1505
1506 $values = [];
1507
1508 $keys = preg_grep($pattern, array_keys($array));
1509
1510 foreach ($keys as $key) {
1511 $values[$key] = $array[$key];
1512 }
1513
1514 return $values;
1515 }
1516
1517 /**
1518 * Return matching ending of items from array by keys
1519 *
1520 * @param string|regex $pattern
1521 * @param array $array
1522 * @return array|false
1523 */
1524 public static function keysEndLike($array, $pattern)
1525 {
1526 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1527 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1528 }
1529
1530 $values = [];
1531
1532 $keys = preg_grep($pattern, array_keys($array));
1533
1534 foreach ($keys as $key) {
1535 $values[$key] = $array[$key];
1536 }
1537
1538 return $values;
1539 }
1540
1541 /**
1542 * Return non-matching ending of items from array by keys
1543 *
1544 * @param string|regex $pattern
1545 * @param array $array
1546 * @return array|false
1547 */
1548 public static function keysDoesNotEndLike($array, $pattern)
1549 {
1550 if (!preg_match('/^([\/#~]).*\1$/', $pattern)) {
1551 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1552 }
1553
1554 $values = [];
1555
1556 $keys = preg_grep($pattern, array_keys($array), PREG_GREP_INVERT);
1557
1558 foreach ($keys as $key) {
1559 $values[$key] = $array[$key];
1560 }
1561
1562 return $values;
1563 }
1564
1565 /**
1566 * Insert a new item in the array at the given position.
1567 *
1568 * @param array $array
1569 * @param int $pos
1570 * @param mixed $newItem
1571 * @return array
1572 */
1573 public static function insertAt($array, $pos, $newItem)
1574 {
1575 if (!isset($array[$pos])) {
1576 $array[] = $newItem;
1577 } else {
1578 $array = array_splice($array, $pos, 0, $newItem);
1579 }
1580
1581 return $array;
1582 }
1583
1584 /**
1585 * Inserts an item before the specified key in the given array. If the
1586 * key is not found, inserts the item at the beginning of the array.
1587 *
1588 * @param array $array
1589 * @param mixed $key
1590 * @param mixed $newKey
1591 * @param mixed $newValue
1592 * @return array $newArray
1593 */
1594 public static function insertBefore($array, $key, $newKey, $newValue)
1595 {
1596 $newArray = [];
1597 $keyFound = false;
1598
1599 foreach ($array as $k => $v) {
1600 if ($k === $key) {
1601 $newArray[$newKey] = $newValue;
1602 $keyFound = true;
1603 }
1604 $newArray[$k] = $v;
1605 }
1606
1607 if (!$keyFound) {
1608 $newArray = [$newKey => $newValue] + $newArray;
1609 }
1610
1611 return $newArray;
1612 }
1613
1614 /**
1615 * Inserts an item after the specified key in the given array. If the
1616 * key is not found, inserts the item at the end of the array.
1617 *
1618 * @param array $array
1619 * @param mixed $key
1620 * @param mixed $newKey
1621 * @param mixed $newValue
1622 * @return array $newArray
1623 */
1624 public static function insertAfter($array, $key, $newKey, $newValue): array {
1625 $newArray = [];
1626 $keyFound = false;
1627
1628 foreach ($array as $k => $v) {
1629 $newArray[$k] = $v;
1630 if ($k === $key) {
1631 $newArray[$newKey] = $newValue;
1632 $keyFound = true;
1633 }
1634 }
1635
1636 if (!$keyFound) {
1637 $newArray[$newKey] = $newValue;
1638 }
1639
1640 return $newArray;
1641 }
1642
1643 /**
1644 * Tests whether at least one element in the array passes
1645 * the test implemented by the provided callback.
1646 *
1647 * @param array $array
1648 * @param callable $callback
1649 * @return bool
1650 */
1651 public static function some($array, callable $callback)
1652 {
1653 foreach ($array as $k => $v) {
1654 if ($callback($v, $k, $array)) {
1655 return true;
1656 }
1657 }
1658
1659 return false;
1660 }
1661
1662 /**
1663 * Tests whether all elements in the array pass the
1664 * test implemented by the provided callback.
1665 *
1666 * @param array $array
1667 * @param callable $callback
1668 * @return bool
1669 */
1670 public static function every($array, callable $callback)
1671 {
1672 foreach ($array as $k => $v) {
1673 if (!$callback($v, $k, $array)) {
1674 return false;
1675 }
1676 }
1677
1678 return true;
1679 }
1680
1681 /**
1682 * Finds the first element in the array that satisfies the
1683 * condition implemented by the callback function.
1684 *
1685 * @param array $array
1686 * @param callable $callback
1687 * @return mixed
1688 */
1689 public static function find($array, callable $callback, $findKey = false)
1690 {
1691 foreach ($array as $k => $v) {
1692 if ($callback($v, $k, $array)) {
1693 return $findKey ? $k : $v;
1694 }
1695 }
1696
1697 return null;
1698 }
1699
1700 /**
1701 * Finds the first key in the array that satisfies the
1702 * condition implemented by the callback function.
1703 *
1704 * @param array $array
1705 * @param callable $callback
1706 * @return mixed
1707 */
1708 public static function findKey($array, callable $callback)
1709 {
1710 return static::find($array, $callback, true);
1711 }
1712 }
1713