PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.21
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.21
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / vendor / wpfluent / framework / src / WPFluent / Support / Arr.php

Arr.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.21, at vendor/wpfluent/framework/src/WPFluent/Support/Arr.php

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