PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.35
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.35
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.35, at vendor/wpfluent/framework/src/WPFluent/Support/Arr.php

1,645 lines 41.3 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 * Pluck an array of values from an array.
631 *
632 * @param iterable $array
633 * @param string|array|int|null $value
634 * @param string|array|null $key
635 * @return array
636 */
637 public static function pluck($array, $value, $key = null)
638 {
639 $results = [];
640
641 [$value, $key] = static::explodePluckParameters($value, $key);
642
643 foreach ($array as $item) {
644 $itemValue = Helper::dataGet($item, $value);
645
646 // If the key is "null", we will just append the value to the array and keep
647 // looping. Otherwise we will key the array using the value of the key we
648 // received from the developer. Then we'll return the final array form.
649 if (is_null($key)) {
650 $results[] = $itemValue;
651 } else {
652 $itemKey = Helper::dataGet($item, $key);
653
654 if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
655 $itemKey = (string) $itemKey;
656 }
657
658 $results[$itemKey] = $itemValue;
659 }
660 }
661
662 return $results;
663 }
664
665 /**
666 * Explode the "value" and "key" arguments passed to "pluck".
667 *
668 * @param string|array $value
669 * @param string|array|null $key
670 * @return array
671 */
672 protected static function explodePluckParameters($value, $key)
673 {
674 $value = is_string($value) ? explode('.', $value) : $value;
675
676 $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
677
678 return [$value, $key];
679 }
680
681 /**
682 * Push an item onto the beginning of an array.
683 *
684 * @param array $array
685 * @param mixed $value
686 * @param mixed $key
687 * @return array
688 */
689 public static function prepend($array, $value, $key = null)
690 {
691 if (func_num_args() == 2) {
692 array_unshift($array, $value);
693 } else {
694 $array = [$key => $value] + $array;
695 }
696
697 return $array;
698 }
699
700 /**
701 * Get a value from the array, and remove it.
702 *
703 * @param array $array
704 * @param string|int $key
705 * @param mixed $default
706 * @return mixed
707 */
708 public static function pull(&$array, $key, $default = null)
709 {
710 $value = static::get($array, $key, $default);
711
712 static::forget($array, $key);
713
714 return $value;
715 }
716
717 /**
718 * Convert the array into a query string.
719 *
720 * @param array $array
721 * @return string
722 */
723 public static function query($array)
724 {
725 return http_build_query($array, '', '&', PHP_QUERY_RFC3986);
726 }
727
728 /**
729 * Get one or a specified number of random values from an array.
730 *
731 * @param array $array
732 * @param int|null $number
733 * @param bool|false $preserveKeys
734 * @return mixed
735 *
736 * @throws \InvalidArgumentException
737 */
738 public static function random($array, $number = null, $preserveKeys = false)
739 {
740 $requested = is_null($number) ? 1 : $number;
741
742 $count = count($array);
743
744 if ($requested > $count) {
745 throw new InvalidArgumentException(
746 "You requested {$requested} items, but there are only {$count} items available."
747 );
748 }
749
750 if (is_null($number)) {
751 return $array[array_rand($array)];
752 }
753
754 if ((int) $number === 0) {
755 return [];
756 }
757
758 $keys = array_rand($array, $number);
759
760 $results = [];
761
762 if ($preserveKeys) {
763 foreach ((array) $keys as $key) {
764 $results[$key] = $array[$key];
765 }
766 } else {
767 foreach ((array) $keys as $key) {
768 $results[] = $array[$key];
769 }
770 }
771
772 return $results;
773 }
774
775 /**
776 * Set an array item to a given value using "dot" notation.
777 *
778 * If no key is given to the method, the entire array will be replaced.
779 *
780 * @param array $array
781 * @param string|null $key
782 * @param mixed $value
783 * @return array
784 */
785 public static function set(&$array, $key, $value)
786 {
787 if (is_null($key)) {
788 return $array = $value;
789 }
790
791 $keys = explode('.', $key);
792
793 foreach ($keys as $i => $key) {
794 if (count($keys) === 1) {
795 break;
796 }
797
798 unset($keys[$i]);
799
800 // If the key doesn't exist at this depth, we will just create an empty array
801 // to hold the next value, allowing us to create the arrays to hold final
802 // values at the correct depth. Then we'll keep digging into the array.
803 if (! isset($array[$key]) || ! is_array($array[$key])) {
804 $array[$key] = [];
805 }
806
807 $array = &$array[$key];
808 }
809
810 $array[array_shift($keys)] = $value;
811
812 return $array;
813 }
814
815 /**
816 * Shuffle the given array and return the result.
817 *
818 * @param array $array
819 * @param int|null $seed
820 * @return array
821 */
822 public static function shuffle($array, $seed = null)
823 {
824 if (is_null($seed)) {
825 shuffle($array);
826 } else {
827 mt_srand($seed);
828 shuffle($array);
829 mt_srand();
830 }
831
832 return $array;
833 }
834
835 /**
836 * Sort the array using the given callback or "dot" notation.
837 *
838 * @param array $array
839 * @param callable|array|string|null $callback
840 * @return array
841 */
842 public static function sort($array, $callback = null)
843 {
844 return Collection::make($array)->sortBy($callback)->all();
845 }
846
847 /**
848 * Sort an array in descending order.
849 *
850 * @param array $array
851 * @param Flags
852 * @return array
853 * @see https://www.php.net/manual/en/function.rsort.php
854 */
855 public static function rsort($array, $flags = SORT_REGULAR)
856 {
857 rsort($array, $flags);
858 return $array;
859 }
860
861 /**
862 * Sort an array in ascending order and maintain index association.
863 *
864 * @param array $array
865 * @param Flags
866 * @return array
867 * @see https://www.php.net/manual/en/function.asort.php
868 */
869 public static function asort($array, $flags = SORT_REGULAR)
870 {
871 asort($array, $flags);
872 return $array;
873 }
874
875 /**
876 * Sort an array in descending order and maintain index association.
877 *
878 * @param array $array
879 * @param Flags
880 * @return array
881 * @see https://www.php.net/manual/en/function.arsort.php
882 */
883 public static function arsort($array, $flags = SORT_REGULAR)
884 {
885 arsort($array, $flags);
886 return $array;
887 }
888
889 /**
890 * Sort an array by key in ascending order.
891 *
892 * @param array $array
893 * @param Flags
894 * @return array
895 * @see https://www.php.net/manual/en/function.ksort.php
896 */
897 public static function ksort($array, $flags = SORT_REGULAR)
898 {
899 ksort($array, $flags);
900 return $array;
901 }
902
903 /**
904 * Sort an array by key in descending order.
905 *
906 * @param array $array
907 * @param Flags
908 * @return array
909 * @see https://www.php.net/manual/en/function.krsort.php
910 */
911 public static function krsort($array, $flags = SORT_REGULAR)
912 {
913 krsort($array, $flags);
914 return $array;
915 }
916
917 /**
918 * Sort an array using a "natural order" algorithm.
919 *
920 * @param array $array
921 * @return array
922 * @see https://www.php.net/manual/en/function.natsort.php
923 */
924 public static function natsort($array)
925 {
926 natsort($array);
927 return $array;
928 }
929
930 /**
931 * Sort an array using a case insensitive "natural order" algorithm.
932 *
933 * @param array $array
934 * @return array
935 * @see https://www.php.net/manual/en/function.natcasesort.php
936 */
937 public static function natcasesort($array)
938 {
939 natcasesort($array);
940 return $array;
941 }
942
943 /**
944 * Sort an array by values using a user-defined comparison function.
945 *
946 * @param array $array
947 * @return array
948 * @see https://www.php.net/manual/en/function.usort.php
949 */
950 public static function usort($array, callable $callback)
951 {
952 usort($array, $callback);
953 return $array;
954 }
955
956 /**
957 * Sort an array with a user-defined comparison
958 * function and maintain index association.
959 *
960 * @param array $array
961 * @return array
962 * @see https://www.php.net/manual/en/function.uasort.php
963 */
964 public static function uasort($array, callable $callback)
965 {
966 uasort($array, $callback);
967 return $array;
968 }
969
970 /**
971 * Sort an array by keys using a user-defined comparison function.
972 *
973 * @param array $array
974 * @return array
975 * @see https://www.php.net/manual/en/function.uksort.php
976 */
977 public static function uksort($array, callable $callback)
978 {
979 uksort($array, $callback);
980 return $array;
981 }
982
983 /**
984 * Recursively sort an array by keys and values.
985 *
986 * @param array $array
987 * @param int $options
988 * @param bool $desc
989 * @return array
990 */
991 public static function sortRecursive($array, $options = SORT_REGULAR, $desc = false)
992 {
993 foreach ($array as &$value) {
994 if (is_array($value)) {
995 $value = static::sortRecursive($value, $options, $desc);
996 }
997 }
998
999 if (static::isAssoc($array)) {
1000 $desc
1001 ? krsort($array, $options)
1002 : ksort($array, $options);
1003 } else {
1004 $desc
1005 ? rsort($array, $options)
1006 : sort($array, $options);
1007 }
1008
1009 return $array;
1010 }
1011
1012 /**
1013 * Conditionally compile classes from an array into a CSS class list.
1014 *
1015 * @param array $array
1016 * @return string
1017 */
1018 public static function toCssClasses($array)
1019 {
1020 $classList = static::wrap($array);
1021
1022 $classes = [];
1023
1024 foreach ($classList as $class => $constraint) {
1025 if (is_numeric($class)) {
1026 $classes[] = $constraint;
1027 } elseif ($constraint) {
1028 $classes[] = $class;
1029 }
1030 }
1031
1032 return implode(' ', $classes);
1033 }
1034
1035 /**
1036 * Transforms an array to \stdClass
1037 * @param array $array
1038 * @return \stdClass
1039 */
1040 public static function toObject($array)
1041 {
1042 return StdObject::create($array);
1043 }
1044
1045 /**
1046 * Filter the array using the given callback.
1047 *
1048 * @param array $array
1049 * @param callable $callback
1050 * @return array
1051 */
1052 public static function where($array, callable $callback)
1053 {
1054 return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
1055 }
1056
1057 /**
1058 * Filter items where the value is not null.
1059 *
1060 * @param array $array
1061 * @return array
1062 */
1063 public static function whereNotNull($array)
1064 {
1065 return static::where($array, function ($value) {
1066 return ! is_null($value);
1067 });
1068 }
1069
1070 /**
1071 * Filter items where the value is not null.
1072 *
1073 * @param array $array
1074 * @return array
1075 */
1076 public static function whereNotTrue($array, $strict = false)
1077 {
1078 return static::where($array, function ($value) use ($strict) {
1079 return $strict ? $value === false : !$value;
1080 });
1081 }
1082
1083 /**
1084 * If the given value is not an array and not null, wrap it in one.
1085 *
1086 * @param mixed $value
1087 * @return array
1088 */
1089 public static function wrap($value)
1090 {
1091 if (is_null($value)) {
1092 return [];
1093 }
1094
1095 return is_array($value) ? $value : [$value];
1096 }
1097
1098 /**
1099 * Maps a function to all non-iterable elements of an array or an object.
1100 *
1101 * This is similar to `array_walk_recursive()` but acts upon objects too.
1102 *
1103 * @param mixed $value The array, object, or scalar.
1104 * @param callable $callback The function to map onto $value.
1105 * @see https://developer.wordpress.org/reference/functions/map_deep/
1106 *
1107 * @return mixed The value with the callback applied to all non-arrays and non-objects inside it.
1108 */
1109 public static function map($value, $callback)
1110 {
1111 return map_deep($value, $callback);
1112 }
1113
1114 /**
1115 * Check if the value(s) exist in an array using "dot" notation.
1116 *
1117 * @param array $array
1118 * @param string|array $values
1119 * @return bool
1120 */
1121 public static function contains(array $array, $values)
1122 {
1123 $result = [];
1124
1125 $values = is_array($values) ? $values : [$values];
1126
1127 foreach ($values as $value) {
1128
1129 if (in_array($value, $array)) {
1130 $result[] = $value;
1131 continue;
1132 }
1133
1134 $segments = explode('.', $value);
1135
1136 $value = array_pop($segments);
1137
1138 $nested = (array) static::get($array, implode('.', $segments));
1139
1140 if ($nested && in_array($value, $nested)) {
1141 $result[] = $value;
1142 }
1143 }
1144
1145 return count($result) === count($values);
1146 }
1147
1148 /**
1149 * Check if the any value exist in an array using "dot" notation.
1150 *
1151 * @param array $array
1152 * @param string|array $values
1153 * @return bool
1154 */
1155 public static function containsAny(array $array, $values)
1156 {
1157 $result = [];
1158
1159 $values = is_array($values) ? $values : [$values];
1160
1161 foreach ($values as $value) {
1162
1163 if (in_array($value, $array)) {
1164 return true;
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 return true;
1175 }
1176 }
1177
1178 return false;
1179 }
1180
1181 /**
1182 * Compare two nested arrays side by side
1183 * @param array $array1
1184 * @param array $array2
1185 * @param array $path
1186 * @return array
1187 */
1188 public static function compare($array1, $array2, $path = [])
1189 {
1190 $differences = [];
1191
1192 foreach ($array1 as $key => $value1) {
1193 // Check if the key exists in the second array
1194 if (!array_key_exists($key, $array2)) {
1195 $differences[implode('.', array_merge($path, [$key]))] = [
1196 'array_1' => $value1,
1197 'array_2' => null,
1198 ];
1199 } else {
1200 // If the value is an array, recursively compare
1201 if (is_array($value1) && is_array($array2[$key])) {
1202 $differences = array_merge($differences, static::compare(
1203 $value1, $array2[$key], array_merge($path, [$key])
1204 ));
1205 } else {
1206 // Compare values
1207 if ($value1 !== $array2[$key]) {
1208 $differences[implode('.', array_merge($path, [$key]))] = [
1209 'array_1' => $value1,
1210 'array_2' => $array2[$key],
1211 ];
1212 }
1213 }
1214 }
1215 }
1216
1217 // Check for keys in the second array that are not in the first array
1218 foreach ($array2 as $key => $value2) {
1219 if (!array_key_exists($key, $array1)) {
1220 $differences[implode('.', array_merge($path, [$key]))] = [
1221 'array_1' => null,
1222 'array_2' => $value2,
1223 ];
1224 }
1225 }
1226
1227 return $differences;
1228 }
1229
1230 /**
1231 * Merge the items from the first array into the
1232 * second array if the second array is missing it.
1233 *
1234 * @param array &$array1
1235 * @param array &$array2
1236 * @return array
1237 */
1238 public static function mergeMissing(&$array1, &$array2)
1239 {
1240 foreach ($array1 as $key => $value1) {
1241 // If the key exists in the second array
1242 if (array_key_exists($key, $array2)) {
1243 // If the value is an array, recursively add missing items
1244 if (is_array($value1) && is_array($array2[$key])) {
1245 static::mergeMissing($value1, $array2[$key]);
1246 }
1247 } else {
1248 // If the key doesn't exist in the second array,
1249 // then add it with the corresponding value
1250 $array2[$key] = $value1;
1251 }
1252 }
1253
1254 return $array2;
1255 }
1256
1257 /**
1258 * Return matching items from array (similar to mysql's %LIKE%)
1259 *
1260 * @param string|regex $pattern
1261 * @param array $array
1262 * @return array|false
1263 */
1264 public static function like($array, $pattern)
1265 {
1266 if (@preg_match($pattern, '') === false) {
1267 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1268 }
1269
1270 return preg_grep($pattern, $array);
1271 }
1272
1273 /**
1274 * Return non-matching items from array (similar to mysql's NOT %LIKE%)
1275 *
1276 * @param string|regex $pattern
1277 * @param array $array
1278 * @return array|false
1279 */
1280 public static function notLike($array, $pattern)
1281 {
1282 if (@preg_match($pattern, '') === false) {
1283 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1284 }
1285
1286 return preg_grep($pattern, $array, PREG_GREP_INVERT);
1287 }
1288
1289 /**
1290 * Return matching starting of items from array (similar to mysql's %LIKE)
1291 *
1292 * @param string|regex $pattern
1293 * @param array $array
1294 * @return array|false
1295 */
1296 public static function startsLike($array, $pattern)
1297 {
1298 if (@preg_match($pattern, '') === false) {
1299 $pattern = '~^'. preg_quote($pattern, '~') . '~i';
1300 }
1301
1302 return preg_grep($pattern, $array);
1303 }
1304
1305 /**
1306 * Return non-matching starting of items from array (similar to mysql's NOT %LIKE)
1307 *
1308 * @param string|regex $pattern
1309 * @param array $array
1310 * @return array|false
1311 */
1312 public static function DoesNotStartLike($array, $pattern)
1313 {
1314 if (@preg_match($pattern, '') === false) {
1315 $pattern = '~^(?!' . preg_quote($pattern, '~') . ')~i';
1316 }
1317
1318 return preg_grep($pattern, $array);
1319 }
1320
1321 /**
1322 * Return matching ending of items from array (similar to mysql's LIKE%)
1323 *
1324 * @param string|regex $pattern
1325 * @param array $array
1326 * @return array|false
1327 */
1328 public static function endsLike($array, $pattern)
1329 {
1330 if (@preg_match($pattern, '') === false) {
1331 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1332 }
1333
1334 return preg_grep($pattern, $array);
1335 }
1336
1337 /**
1338 * Return non-matching ending of items from array (similar to mysql's NOT LIKE%)
1339 *
1340 * @param string|regex $pattern
1341 * @param array $array
1342 * @return array|false
1343 */
1344 public static function DoesNotEndLike($array, $pattern)
1345 {
1346 if (@preg_match($pattern, '') === false) {
1347 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1348 }
1349
1350 return preg_grep($pattern, $array, PREG_GREP_INVERT);
1351 }
1352
1353 /**
1354 * Return matching items from array by keys
1355 *
1356 * @param string|regex $pattern
1357 * @param array $array
1358 * @return array|false
1359 */
1360 public static function keysLike($array, $pattern)
1361 {
1362 if (@preg_match($pattern, '') === false) {
1363 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1364 }
1365
1366 $values = [];
1367
1368 $keys = preg_grep($pattern, array_keys($array));
1369
1370 foreach ($keys as $key) {
1371 $values[$key] = $array[$key];
1372 }
1373
1374 return $values;
1375 }
1376
1377 /**
1378 * Return non-matching items from array by keys
1379 *
1380 * @param string|regex $pattern
1381 * @param array $array
1382 * @return array|false
1383 */
1384 public static function keysNotLike($array, $pattern)
1385 {
1386 if (@preg_match($pattern, '') === false) {
1387 $pattern = '~'. preg_quote($pattern, '~') . '~i';
1388 }
1389
1390 $values = [];
1391
1392 $keys = preg_grep($pattern, array_keys($array), 1);
1393
1394 foreach ($keys as $key) {
1395 $values[$key] = $array[$key];
1396 }
1397
1398 return $values;
1399 }
1400
1401 /**
1402 * Return matching starting of items from array by keys
1403 *
1404 * @param string|regex $pattern
1405 * @param array $array
1406 * @return array|false
1407 */
1408 public static function keysStartLike($array, $pattern)
1409 {
1410 if (@preg_match($pattern, '') === false) {
1411 $pattern = '~^'. preg_quote($pattern, '~') . '~i';
1412 }
1413
1414 $values = [];
1415
1416 $keys = preg_grep($pattern, array_keys($array));
1417
1418 foreach ($keys as $key) {
1419 $values[$key] = $array[$key];
1420 }
1421
1422 return $values;
1423 }
1424
1425 /**
1426 * Return non-matching starting of items from array by keys
1427 *
1428 * @param string|regex $pattern
1429 * @param array $array
1430 * @return array|false
1431 */
1432 public static function keysDoesNotStartLike($array, $pattern)
1433 {
1434 if (@preg_match($pattern, '') === false) {
1435 $pattern = '~^(?!' . preg_quote($pattern, '~') . ')~i';
1436 }
1437
1438 $values = [];
1439
1440 $keys = preg_grep($pattern, array_keys($array));
1441
1442 foreach ($keys as $key) {
1443 $values[$key] = $array[$key];
1444 }
1445
1446 return $values;
1447 }
1448
1449 /**
1450 * Return matching ending of items from array by keys
1451 *
1452 * @param string|regex $pattern
1453 * @param array $array
1454 * @return array|false
1455 */
1456 public static function keysEndLike($array, $pattern)
1457 {
1458 if (@preg_match($pattern, '') === false) {
1459 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1460 }
1461
1462 $values = [];
1463
1464 $keys = preg_grep($pattern, array_keys($array));
1465
1466 foreach ($keys as $key) {
1467 $values[$key] = $array[$key];
1468 }
1469
1470 return $values;
1471 }
1472
1473 /**
1474 * Return non-matching ending of items from array by keys
1475 *
1476 * @param string|regex $pattern
1477 * @param array $array
1478 * @return array|false
1479 */
1480 public static function keysDoesNotEndLike($array, $pattern)
1481 {
1482 if (@preg_match($pattern, '') === false) {
1483 $pattern = '~'. preg_quote($pattern, '~') . '$~i';
1484 }
1485
1486 $values = [];
1487
1488 $keys = preg_grep($pattern, array_keys($array), PREG_GREP_INVERT);
1489
1490 foreach ($keys as $key) {
1491 $values[$key] = $array[$key];
1492 }
1493
1494 return $values;
1495 }
1496
1497 /**
1498 * Insert a new item in the array at the given position.
1499 *
1500 * @param array $array
1501 * @param int $pos
1502 * @param mixed $newItem
1503 * @return array
1504 */
1505 public static function insertAt($array, $pos, $newItem)
1506 {
1507 if (!isset($array[$pos])) {
1508 $array[] = $newItem;
1509 } else {
1510 $array = array_splice($array, $pos, 0, $newItem);
1511 }
1512
1513 return $array;
1514 }
1515
1516 /**
1517 * Inserts an item before the specified key in the given array. If the
1518 * key is not found, inserts the item at the beginning of the array.
1519 *
1520 * @param array $array
1521 * @param mixed $key
1522 * @param mixed $newKey
1523 * @param mixed $newValue
1524 * @return array $newArray
1525 */
1526 public static function insertBefore($array, $key, $newKey, $newValue)
1527 {
1528 $newArray = [];
1529 $keyFound = false;
1530
1531 foreach ($array as $k => $v) {
1532 if ($k === $key) {
1533 $newArray[$newKey] = $newValue;
1534 $keyFound = true;
1535 }
1536 $newArray[$k] = $v;
1537 }
1538
1539 if (!$keyFound) {
1540 $newArray = [$newKey => $newValue] + $newArray;
1541 }
1542
1543 return $newArray;
1544 }
1545
1546 /**
1547 * Inserts an item after the specified key in the given array. If the
1548 * key is not found, inserts the item at the end of the array.
1549 *
1550 * @param array $array
1551 * @param mixed $key
1552 * @param mixed $newKey
1553 * @param mixed $newValue
1554 * @return array $newArray
1555 */
1556 public static function insertAfter($array, $key, $newKey, $newValue): array {
1557 $newArray = [];
1558 $keyFound = false;
1559
1560 foreach ($array as $k => $v) {
1561 $newArray[$k] = $v;
1562 if ($k === $key) {
1563 $newArray[$newKey] = $newValue;
1564 $keyFound = true;
1565 }
1566 }
1567
1568 if (!$keyFound) {
1569 $newArray[$newKey] = $newValue;
1570 }
1571
1572 return $newArray;
1573 }
1574
1575 /**
1576 * Tests whether at least one element in the array passes
1577 * the test implemented by the provided callback.
1578 *
1579 * @param array $array
1580 * @param callable $callback
1581 * @return bool
1582 */
1583 public static function some($array, callable $callback)
1584 {
1585 foreach ($array as $k => $v) {
1586 if ($callback($v, $k, $array)) {
1587 return true;
1588 }
1589 }
1590
1591 return false;
1592 }
1593
1594 /**
1595 * Tests whether all elements in the array pass the
1596 * test implemented by the provided callback.
1597 *
1598 * @param array $array
1599 * @param callable $callback
1600 * @return bool
1601 */
1602 public static function every($array, callable $callback)
1603 {
1604 foreach ($array as $k => $v) {
1605 if (!$callback($v, $k, $array)) {
1606 return false;
1607 }
1608 }
1609
1610 return true;
1611 }
1612
1613 /**
1614 * Finds the first element in the array that satisfies the
1615 * condition implemented by the callback function.
1616 *
1617 * @param array $array
1618 * @param callable $callback
1619 * @return mixed
1620 */
1621 public static function find($array, callable $callback, $findKey = false)
1622 {
1623 foreach ($array as $k => $v) {
1624 if ($callback($v, $k, $array)) {
1625 return $findKey ? $k : $v;
1626 }
1627 }
1628
1629 return null;
1630 }
1631
1632 /**
1633 * Finds the first key in the array that satisfies the
1634 * condition implemented by the callback function.
1635 *
1636 * @param array $array
1637 * @param callable $callback
1638 * @return mixed
1639 */
1640 public static function findKey($array, callable $callback)
1641 {
1642 return static::find($array, $callback, true);
1643 }
1644 }
1645