These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace IlluminateAgnostic\Arr\Support; |
||
4 | |||
5 | use ArrayAccess; |
||
6 | use InvalidArgumentException; |
||
7 | use IlluminateAgnostic\Arr\Support\Traits\Macroable; |
||
8 | |||
9 | class Arr |
||
10 | { |
||
11 | use Macroable; |
||
12 | |||
13 | /** |
||
14 | * Determine whether the given value is array accessible. |
||
15 | * |
||
16 | * @param mixed $value |
||
17 | * @return bool |
||
18 | */ |
||
19 | 47 | public static function accessible($value) |
|
20 | { |
||
21 | 47 | return is_array($value) || $value instanceof ArrayAccess; |
|
22 | } |
||
23 | |||
24 | /** |
||
25 | * Add an element to an array using "dot" notation if it doesn't exist. |
||
26 | * |
||
27 | * @param array $array |
||
28 | * @param string $key |
||
29 | * @param mixed $value |
||
30 | * @return array |
||
31 | */ |
||
32 | 1 | public static function add($array, $key, $value) |
|
33 | { |
||
34 | 1 | if (is_null(static::get($array, $key))) { |
|
35 | 1 | static::set($array, $key, $value); |
|
36 | } |
||
37 | |||
38 | 1 | return $array; |
|
39 | } |
||
40 | |||
41 | /** |
||
42 | * Collapse an array of arrays into a single array. |
||
43 | * |
||
44 | * @param array $array |
||
45 | * @return array |
||
46 | */ |
||
47 | 5 | public static function collapse($array) |
|
48 | { |
||
49 | 5 | $results = []; |
|
50 | |||
51 | 5 | foreach ($array as $values) { |
|
52 | 5 | if ($values instanceof Collection) { |
|
53 | 1 | $values = $values->all(); |
|
54 | 4 | } elseif (! is_array($values)) { |
|
55 | 1 | continue; |
|
56 | } |
||
57 | |||
58 | 5 | $results = array_merge($results, $values); |
|
59 | } |
||
60 | |||
61 | 5 | return $results; |
|
62 | } |
||
63 | |||
64 | /** |
||
65 | * Cross join the given arrays, returning all possible permutations. |
||
66 | * |
||
67 | * @param array ...$arrays |
||
68 | * @return array |
||
69 | */ |
||
70 | 2 | public static function crossJoin(...$arrays) |
|
71 | { |
||
72 | 2 | $results = [[]]; |
|
73 | |||
74 | 2 | foreach ($arrays as $index => $array) { |
|
75 | 2 | $append = []; |
|
76 | |||
77 | 2 | foreach ($results as $product) { |
|
78 | 2 | foreach ($array as $item) { |
|
79 | 2 | $product[$index] = $item; |
|
80 | |||
81 | 2 | $append[] = $product; |
|
82 | } |
||
83 | } |
||
84 | |||
85 | 2 | $results = $append; |
|
86 | } |
||
87 | |||
88 | 2 | return $results; |
|
89 | } |
||
90 | |||
91 | /** |
||
92 | * Divide an array into two arrays. One with keys and the other with values. |
||
93 | * |
||
94 | * @param array $array |
||
95 | * @return array |
||
96 | */ |
||
97 | 1 | public static function divide($array) |
|
98 | { |
||
99 | 1 | return [array_keys($array), array_values($array)]; |
|
100 | } |
||
101 | |||
102 | /** |
||
103 | * Flatten a multi-dimensional associative array with dots. |
||
104 | * |
||
105 | * @param array $array |
||
106 | * @param string $prepend |
||
107 | * @return array |
||
108 | */ |
||
109 | 1 | public static function dot($array, $prepend = '') |
|
110 | { |
||
111 | 1 | $results = []; |
|
112 | |||
113 | 1 | foreach ($array as $key => $value) { |
|
114 | 1 | if (is_array($value) && ! empty($value)) { |
|
115 | 1 | $results = array_merge($results, static::dot($value, $prepend.$key.'.')); |
|
116 | } else { |
||
117 | 1 | $results[$prepend.$key] = $value; |
|
118 | } |
||
119 | } |
||
120 | |||
121 | 1 | return $results; |
|
122 | } |
||
123 | |||
124 | /** |
||
125 | * Get all of the given array except for a specified array of keys. |
||
126 | * |
||
127 | * @param array $array |
||
128 | * @param array|string $keys |
||
129 | * @return array |
||
130 | */ |
||
131 | 3 | public static function except($array, $keys) |
|
132 | { |
||
133 | 3 | static::forget($array, $keys); |
|
134 | |||
135 | 3 | return $array; |
|
136 | } |
||
137 | |||
138 | /** |
||
139 | * Determine if the given key exists in the provided array. |
||
140 | * |
||
141 | * @param \ArrayAccess|array $array |
||
142 | * @param string|int $key |
||
143 | * @return bool |
||
144 | */ |
||
145 | 45 | public static function exists($array, $key) |
|
146 | { |
||
147 | 45 | if ($array instanceof ArrayAccess) { |
|
148 | 4 | return $array->offsetExists($key); |
|
149 | } |
||
150 | |||
151 | 44 | return array_key_exists($key, $array); |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * Return the first element in an array passing a given truth test. |
||
156 | * |
||
157 | * @param array $array |
||
158 | * @param callable|null $callback |
||
159 | * @param mixed $default |
||
160 | * @return mixed |
||
161 | */ |
||
162 | 15 | public static function first($array, callable $callback = null, $default = null) |
|
163 | { |
||
164 | 15 | if (is_null($callback)) { |
|
165 | 6 | if (empty($array)) { |
|
166 | 1 | return value($default); |
|
167 | } |
||
168 | |||
169 | 5 | foreach ($array as $item) { |
|
170 | 5 | return $item; |
|
171 | } |
||
172 | } |
||
173 | |||
174 | 10 | foreach ($array as $key => $value) { |
|
175 | 10 | if (call_user_func($callback, $value, $key)) { |
|
176 | 10 | return $value; |
|
177 | } |
||
178 | } |
||
179 | |||
180 | 6 | return value($default); |
|
181 | } |
||
182 | |||
183 | /** |
||
184 | * Return the last element in an array passing a given truth test. |
||
185 | * |
||
186 | * @param array $array |
||
187 | * @param callable|null $callback |
||
188 | * @param mixed $default |
||
189 | * @return mixed |
||
190 | */ |
||
191 | 8 | public static function last($array, callable $callback = null, $default = null) |
|
192 | { |
||
193 | 8 | if (is_null($callback)) { |
|
194 | 6 | return empty($array) ? value($default) : end($array); |
|
195 | } |
||
196 | |||
197 | 3 | return static::first(array_reverse($array, true), $callback, $default); |
|
198 | } |
||
199 | |||
200 | /** |
||
201 | * Flatten a multi-dimensional array into a single level. |
||
202 | * |
||
203 | * @param array $array |
||
204 | * @param int $depth |
||
205 | * @return array |
||
206 | */ |
||
207 | 5 | public static function flatten($array, $depth = INF) |
|
208 | { |
||
209 | 5 | $result = []; |
|
210 | |||
211 | 5 | foreach ($array as $item) { |
|
212 | 5 | $item = $item instanceof Collection ? $item->all() : $item; |
|
213 | |||
214 | 5 | if (! is_array($item)) { |
|
215 | 5 | $result[] = $item; |
|
216 | 5 | } elseif ($depth === 1) { |
|
217 | 3 | $result = array_merge($result, array_values($item)); |
|
218 | } else { |
||
219 | 5 | $result = array_merge($result, static::flatten($item, $depth - 1)); |
|
220 | } |
||
221 | } |
||
222 | |||
223 | 5 | return $result; |
|
224 | } |
||
225 | |||
226 | /** |
||
227 | * Remove one or many array items from a given array using "dot" notation. |
||
228 | * |
||
229 | * @param array $array |
||
230 | * @param array|string $keys |
||
231 | * @return void |
||
232 | */ |
||
233 | 8 | public static function forget(&$array, $keys) |
|
234 | { |
||
235 | 8 | $original = &$array; |
|
236 | |||
237 | 8 | $keys = (array) $keys; |
|
238 | |||
239 | 8 | if (count($keys) === 0) { |
|
240 | 1 | return; |
|
241 | } |
||
242 | |||
243 | 8 | foreach ($keys as $key) { |
|
244 | // if the exact key exists in the top-level, remove it |
||
245 | 8 | if (static::exists($array, $key)) { |
|
246 | 6 | unset($array[$key]); |
|
247 | |||
248 | 6 | continue; |
|
249 | } |
||
250 | |||
251 | 5 | $parts = explode('.', $key); |
|
252 | |||
253 | // clean up before each pass |
||
254 | 5 | $array = &$original; |
|
255 | |||
256 | 5 | while (count($parts) > 1) { |
|
257 | 2 | $part = array_shift($parts); |
|
258 | |||
259 | 2 | if (isset($array[$part]) && is_array($array[$part])) { |
|
260 | 2 | $array = &$array[$part]; |
|
261 | } else { |
||
262 | 2 | continue 2; |
|
263 | } |
||
264 | } |
||
265 | |||
266 | 4 | unset($array[array_shift($parts)]); |
|
267 | } |
||
268 | 8 | } |
|
269 | |||
270 | /** |
||
271 | * Get an item from an array using "dot" notation. |
||
272 | * |
||
273 | * @param \ArrayAccess|array $array |
||
274 | * @param string $key |
||
275 | * @param mixed $default |
||
276 | * @return mixed |
||
277 | */ |
||
278 | 6 | public static function get($array, $key, $default = null) |
|
279 | { |
||
280 | 6 | if (! static::accessible($array)) { |
|
281 | 1 | return value($default); |
|
282 | } |
||
283 | |||
284 | 6 | if (is_null($key)) { |
|
285 | 1 | return $array; |
|
286 | } |
||
287 | |||
288 | 6 | if (static::exists($array, $key)) { |
|
289 | 4 | return $array[$key]; |
|
290 | } |
||
291 | |||
292 | 4 | if (strpos($key, '.') === false) { |
|
293 | 2 | return $array[$key] ?? value($default); |
|
294 | } |
||
295 | |||
296 | 2 | View Code Duplication | foreach (explode('.', $key) as $segment) { |
0 ignored issues
–
show
|
|||
297 | 2 | if (static::accessible($array) && static::exists($array, $segment)) { |
|
298 | 2 | $array = $array[$segment]; |
|
299 | } else { |
||
300 | 2 | return value($default); |
|
301 | } |
||
302 | } |
||
303 | |||
304 | 1 | return $array; |
|
305 | } |
||
306 | |||
307 | /** |
||
308 | * Check if an item or items exist in an array using "dot" notation. |
||
309 | * |
||
310 | * @param \ArrayAccess|array $array |
||
311 | * @param string|array $keys |
||
312 | * @return bool |
||
313 | */ |
||
314 | 1 | public static function has($array, $keys) |
|
315 | { |
||
316 | 1 | if (is_null($keys)) { |
|
317 | 1 | return false; |
|
318 | } |
||
319 | |||
320 | 1 | $keys = (array) $keys; |
|
321 | |||
322 | 1 | if (! $array) { |
|
323 | 1 | return false; |
|
324 | } |
||
325 | |||
326 | 1 | if ($keys === []) { |
|
327 | 1 | return false; |
|
328 | } |
||
329 | |||
330 | 1 | foreach ($keys as $key) { |
|
331 | 1 | $subKeyArray = $array; |
|
332 | |||
333 | 1 | if (static::exists($array, $key)) { |
|
334 | 1 | continue; |
|
335 | } |
||
336 | |||
337 | 1 | View Code Duplication | foreach (explode('.', $key) as $segment) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
338 | 1 | if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { |
|
339 | 1 | $subKeyArray = $subKeyArray[$segment]; |
|
340 | } else { |
||
341 | 1 | return false; |
|
342 | } |
||
343 | } |
||
344 | } |
||
345 | |||
346 | 1 | return true; |
|
347 | } |
||
348 | |||
349 | /** |
||
350 | * Determines if an array is associative. |
||
351 | * |
||
352 | * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. |
||
353 | * |
||
354 | * @param array $array |
||
355 | * @return bool |
||
356 | */ |
||
357 | 2 | public static function isAssoc(array $array) |
|
358 | { |
||
359 | 2 | $keys = array_keys($array); |
|
360 | |||
361 | 2 | return array_keys($keys) !== $keys; |
|
362 | } |
||
363 | |||
364 | /** |
||
365 | * Get a subset of the items from the given array. |
||
366 | * |
||
367 | * @param array $array |
||
368 | * @param array|string $keys |
||
369 | * @return array |
||
370 | */ |
||
371 | 2 | public static function only($array, $keys) |
|
372 | { |
||
373 | 2 | return array_intersect_key($array, array_flip((array) $keys)); |
|
374 | } |
||
375 | |||
376 | /** |
||
377 | * Pluck an array of values from an array. |
||
378 | * |
||
379 | * @param array $array |
||
380 | * @param string|array $value |
||
381 | * @param string|array|null $key |
||
382 | * @return array |
||
383 | */ |
||
384 | 13 | public static function pluck($array, $value, $key = null) |
|
385 | { |
||
386 | 13 | $results = []; |
|
387 | |||
388 | 13 | list($value, $key) = static::explodePluckParameters($value, $key); |
|
389 | |||
390 | 13 | foreach ($array as $item) { |
|
391 | 13 | $itemValue = data_get($item, $value); |
|
392 | |||
393 | // If the key is "null", we will just append the value to the array and keep |
||
394 | // looping. Otherwise we will key the array using the value of the key we |
||
395 | // received from the developer. Then we'll return the final array form. |
||
396 | 13 | if (is_null($key)) { |
|
397 | 11 | $results[] = $itemValue; |
|
398 | } else { |
||
399 | 4 | $itemKey = data_get($item, $key); |
|
400 | |||
401 | 4 | if (is_object($itemKey) && method_exists($itemKey, '__toString')) { |
|
402 | 1 | $itemKey = (string) $itemKey; |
|
403 | } |
||
404 | |||
405 | 13 | $results[$itemKey] = $itemValue; |
|
406 | } |
||
407 | } |
||
408 | |||
409 | 13 | return $results; |
|
410 | } |
||
411 | |||
412 | /** |
||
413 | * Explode the "value" and "key" arguments passed to "pluck". |
||
414 | * |
||
415 | * @param string|array $value |
||
416 | * @param string|array|null $key |
||
417 | * @return array |
||
418 | */ |
||
419 | 13 | protected static function explodePluckParameters($value, $key) |
|
420 | { |
||
421 | 13 | $value = is_string($value) ? explode('.', $value) : $value; |
|
422 | |||
423 | 13 | $key = is_null($key) || is_array($key) ? $key : explode('.', $key); |
|
424 | |||
425 | 13 | return [$value, $key]; |
|
426 | } |
||
427 | |||
428 | /** |
||
429 | * Push an item onto the beginning of an array. |
||
430 | * |
||
431 | * @param array $array |
||
432 | * @param mixed $value |
||
433 | * @param mixed $key |
||
434 | * @return array |
||
435 | */ |
||
436 | 2 | public static function prepend($array, $value, $key = null) |
|
437 | { |
||
438 | 2 | if (is_null($key)) { |
|
439 | 2 | array_unshift($array, $value); |
|
440 | } else { |
||
441 | 2 | $array = [$key => $value] + $array; |
|
442 | } |
||
443 | |||
444 | 2 | return $array; |
|
445 | } |
||
446 | |||
447 | /** |
||
448 | * Get a value from the array, and remove it. |
||
449 | * |
||
450 | * @param array $array |
||
451 | * @param string $key |
||
452 | * @param mixed $default |
||
453 | * @return mixed |
||
454 | */ |
||
455 | 4 | public static function pull(&$array, $key, $default = null) |
|
456 | { |
||
457 | 4 | $value = static::get($array, $key, $default); |
|
458 | |||
459 | 4 | static::forget($array, $key); |
|
460 | |||
461 | 4 | return $value; |
|
462 | } |
||
463 | |||
464 | /** |
||
465 | * Get one or a specified number of random values from an array. |
||
466 | * |
||
467 | * @param array $array |
||
468 | * @param int|null $number |
||
469 | * @return mixed |
||
470 | * |
||
471 | * @throws \InvalidArgumentException |
||
472 | */ |
||
473 | 6 | public static function random($array, $number = null) |
|
474 | { |
||
475 | 6 | $requested = is_null($number) ? 1 : $number; |
|
476 | |||
477 | 6 | $count = count($array); |
|
478 | |||
479 | 6 | if ($requested > $count) { |
|
480 | 2 | throw new InvalidArgumentException( |
|
481 | 2 | "You requested {$requested} items, but there are only {$count} items available." |
|
482 | ); |
||
483 | } |
||
484 | |||
485 | 4 | if (is_null($number)) { |
|
486 | 2 | return $array[array_rand($array)]; |
|
487 | } |
||
488 | |||
489 | 4 | if ((int) $number === 0) { |
|
490 | 4 | return []; |
|
491 | } |
||
492 | |||
493 | 2 | $keys = array_rand($array, $number); |
|
494 | |||
495 | 2 | $results = []; |
|
496 | |||
497 | 2 | foreach ((array) $keys as $key) { |
|
498 | 2 | $results[] = $array[$key]; |
|
499 | } |
||
500 | |||
501 | 2 | return $results; |
|
502 | } |
||
503 | |||
504 | /** |
||
505 | * Set an array item to a given value using "dot" notation. |
||
506 | * |
||
507 | * If no key is given to the method, the entire array will be replaced. |
||
508 | * |
||
509 | * @param array $array |
||
510 | * @param string $key |
||
511 | * @param mixed $value |
||
512 | * @return array |
||
513 | */ |
||
514 | 3 | public static function set(&$array, $key, $value) |
|
515 | { |
||
516 | 3 | if (is_null($key)) { |
|
517 | 1 | return $array = $value; |
|
518 | } |
||
519 | |||
520 | 3 | $keys = explode('.', $key); |
|
521 | |||
522 | 3 | while (count($keys) > 1) { |
|
523 | 2 | $key = array_shift($keys); |
|
524 | |||
525 | // If the key doesn't exist at this depth, we will just create an empty array |
||
526 | // to hold the next value, allowing us to create the arrays to hold final |
||
527 | // values at the correct depth. Then we'll keep digging into the array. |
||
528 | 2 | if (! isset($array[$key]) || ! is_array($array[$key])) { |
|
529 | 1 | $array[$key] = []; |
|
530 | } |
||
531 | |||
532 | 2 | $array = &$array[$key]; |
|
533 | } |
||
534 | |||
535 | 3 | $array[array_shift($keys)] = $value; |
|
536 | |||
537 | 3 | return $array; |
|
538 | } |
||
539 | |||
540 | /** |
||
541 | * Shuffle the given array and return the result. |
||
542 | * |
||
543 | * @param array $array |
||
544 | * @return array |
||
545 | */ |
||
546 | 1 | public static function shuffle($array) |
|
547 | { |
||
548 | 1 | shuffle($array); |
|
549 | |||
550 | 1 | return $array; |
|
551 | } |
||
552 | |||
553 | /** |
||
554 | * Sort the array using the given callback or "dot" notation. |
||
555 | * |
||
556 | * @param array $array |
||
557 | * @param callable|string|null $callback |
||
558 | * @return array |
||
559 | */ |
||
560 | 1 | public static function sort($array, $callback = null) |
|
561 | { |
||
562 | 1 | return Collection::make($array)->sortBy($callback)->all(); |
|
563 | } |
||
564 | |||
565 | /** |
||
566 | * Recursively sort an array by keys and values. |
||
567 | * |
||
568 | * @param array $array |
||
569 | * @return array |
||
570 | */ |
||
571 | 1 | public static function sortRecursive($array) |
|
572 | { |
||
573 | 1 | foreach ($array as &$value) { |
|
574 | 1 | if (is_array($value)) { |
|
575 | 1 | $value = static::sortRecursive($value); |
|
576 | } |
||
577 | } |
||
578 | |||
579 | 1 | if (static::isAssoc($array)) { |
|
580 | 1 | ksort($array); |
|
581 | } else { |
||
582 | 1 | sort($array); |
|
583 | } |
||
584 | |||
585 | 1 | return $array; |
|
586 | } |
||
587 | |||
588 | /** |
||
589 | * Filter the array using the given callback. |
||
590 | * |
||
591 | * @param array $array |
||
592 | * @param callable $callback |
||
593 | * @return array |
||
594 | */ |
||
595 | 23 | public static function where($array, callable $callback) |
|
596 | { |
||
597 | 23 | return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); |
|
598 | } |
||
599 | |||
600 | /** |
||
601 | * If the given value is not an array and not null, wrap it in one. |
||
602 | * |
||
603 | * @param mixed $value |
||
604 | * @return array |
||
605 | */ |
||
606 | 6 | public static function wrap($value) |
|
607 | { |
||
608 | 6 | if (is_null($value)) { |
|
609 | 1 | return []; |
|
610 | } |
||
611 | |||
612 | 6 | return ! is_array($value) ? [$value] : $value; |
|
613 | } |
||
614 | } |
||
615 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.