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

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