This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | namespace Narrowspark\Arr; |
||
4 | |||
5 | use ArrayAccess; |
||
6 | use Closure; |
||
7 | |||
8 | class Arr |
||
9 | { |
||
10 | /** |
||
11 | * Dotted array cache. |
||
12 | * |
||
13 | * @var array |
||
14 | */ |
||
15 | protected static $dotted = []; |
||
16 | |||
17 | /** |
||
18 | * Determine whether the given value is array accessible. |
||
19 | * |
||
20 | * @param mixed $value |
||
21 | * |
||
22 | * @return bool |
||
23 | */ |
||
24 | 8 | public static function accessible($value): bool |
|
25 | { |
||
26 | 8 | return is_array($value) || $value instanceof ArrayAccess; |
|
27 | } |
||
28 | |||
29 | /** |
||
30 | * Get a value from the array, and remove it. |
||
31 | * |
||
32 | * @param array $array |
||
33 | * @param string|int $key |
||
34 | * @param mixed $default |
||
35 | * |
||
36 | * @return mixed |
||
37 | */ |
||
38 | 3 | public static function pull(array &$array, $key, $default = null) |
|
39 | { |
||
40 | 3 | $value = static::get($array, $key, $default); |
|
41 | |||
42 | 3 | static::forget($array, $key); |
|
43 | |||
44 | 3 | return $value; |
|
45 | } |
||
46 | |||
47 | /** |
||
48 | * Set an array item to a given value using "dot" notation. |
||
49 | * If no key is given to the method, the entire array will be replaced. |
||
50 | * |
||
51 | * @param array $array |
||
52 | * @param string|null $key |
||
53 | * @param mixed $value |
||
54 | * |
||
55 | * @return array |
||
56 | */ |
||
57 | 9 | public static function set(array $array, $key, $value): array |
|
58 | { |
||
59 | 9 | if ($key === null) { |
|
60 | 1 | return $value; |
|
61 | } |
||
62 | |||
63 | 9 | $keys = explode('.', (string) $key); |
|
64 | 9 | $current = &$array; |
|
65 | |||
66 | 9 | while (count($keys) > 1) { |
|
67 | 7 | $key = array_shift($keys); |
|
68 | |||
69 | // If the key doesn't exist at this depth, we will just create an empty array |
||
70 | // to hold the next value, allowing us to create the arrays to hold final |
||
71 | // values at the correct depth. Then we'll keep digging into the array. |
||
72 | 7 | if (! isset($current[$key]) || ! is_array($current[$key])) { |
|
73 | 4 | $current[$key] = []; |
|
74 | } |
||
75 | |||
76 | 7 | $current = &$current[$key]; |
|
77 | } |
||
78 | |||
79 | 9 | $current[array_shift($keys)] = $value; |
|
80 | |||
81 | 9 | return $array; |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * Get an item from an array using "dot" notation. |
||
86 | * If key dont exist, you get a default value back. |
||
87 | * |
||
88 | * @param array $array |
||
89 | * @param string|int|null $key |
||
90 | * @param mixed $default |
||
91 | * |
||
92 | * @return mixed |
||
93 | */ |
||
94 | 8 | public static function get(array $array, $key = null, $default = null) |
|
95 | { |
||
96 | 8 | if ($key === null) { |
|
97 | 1 | return $array; |
|
98 | } |
||
99 | |||
100 | 8 | if (isset($array[$key])) { |
|
101 | 5 | return static::value($array[$key]); |
|
102 | } |
||
103 | |||
104 | 4 | View Code Duplication | foreach (explode('.', (string) $key) as $segment) { |
0 ignored issues
–
show
|
|||
105 | 4 | if (! array_key_exists($segment, $array)) { |
|
106 | 1 | return static::value($default); |
|
107 | } |
||
108 | |||
109 | 4 | $array = $array[$segment]; |
|
110 | } |
||
111 | |||
112 | 3 | return $array; |
|
113 | } |
||
114 | |||
115 | /** |
||
116 | * Add an element to the array at a specific location |
||
117 | * using the "dot" notation. |
||
118 | * |
||
119 | * @param array $array |
||
120 | * @param string[]|callable|null $key |
||
121 | * @param mixed $value |
||
122 | * |
||
123 | * @return array |
||
124 | */ |
||
125 | 4 | public static function add(array $array, $key, $value): array |
|
126 | { |
||
127 | 4 | $target = static::get($array, $key, []); |
|
128 | |||
129 | 4 | if (! is_array($target)) { |
|
130 | 2 | $target = [$target]; |
|
131 | } |
||
132 | |||
133 | 4 | $target[] = $value; |
|
134 | 4 | $array = static::set($array, $key, $target); |
|
135 | |||
136 | 4 | return $array; |
|
137 | } |
||
138 | |||
139 | /** |
||
140 | * Check if any item or items exist in an array using "dot" notation. |
||
141 | * |
||
142 | * @param array $array |
||
143 | * @param string|array $keys |
||
144 | * |
||
145 | * @return bool |
||
146 | */ |
||
147 | 1 | public static function any(array $array, $keys): bool |
|
148 | { |
||
149 | 1 | foreach ((array) $keys as $key) { |
|
150 | 1 | if (static::has($array, $key)) { |
|
151 | 1 | return true; |
|
152 | } |
||
153 | } |
||
154 | |||
155 | 1 | return false; |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * Determine if the given key exists in the provided array. |
||
160 | * |
||
161 | * @param \ArrayAccess|array $array |
||
162 | * @param string|int $key |
||
163 | * |
||
164 | * @return bool |
||
165 | */ |
||
166 | 20 | public static function exists($array, $key): bool |
|
167 | { |
||
168 | 20 | if ($array instanceof ArrayAccess) { |
|
169 | return $array->offsetExists($key); |
||
170 | } |
||
171 | |||
172 | 20 | return array_key_exists($key, $array); |
|
173 | } |
||
174 | |||
175 | /** |
||
176 | * Check if an item exists in an array using "dot" notation. |
||
177 | * |
||
178 | * @param \ArrayAccess|array $array |
||
179 | * @param string|int $keys |
||
180 | * |
||
181 | * @return bool |
||
182 | */ |
||
183 | 9 | public static function has($array, $keys): bool |
|
184 | { |
||
185 | 9 | if (is_null($keys)) { |
|
186 | 2 | return false; |
|
187 | } |
||
188 | |||
189 | 9 | $keys = (array) $keys; |
|
190 | |||
191 | 9 | if (! $array) { |
|
192 | 4 | return false; |
|
193 | } |
||
194 | |||
195 | 9 | if ($keys === []) { |
|
196 | return false; |
||
197 | } |
||
198 | |||
199 | 9 | foreach ($keys as $key) { |
|
200 | 9 | $subKeyArray = $array; |
|
201 | |||
202 | 9 | if (static::exists($array, $key)) { |
|
203 | 7 | continue; |
|
204 | } |
||
205 | |||
206 | 8 | View Code Duplication | foreach (explode('.', (string) $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...
|
|||
207 | 8 | if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { |
|
208 | 2 | $subKeyArray = $subKeyArray[$segment]; |
|
209 | } else { |
||
210 | 8 | return false; |
|
211 | } |
||
212 | } |
||
213 | } |
||
214 | |||
215 | 7 | return true; |
|
216 | } |
||
217 | |||
218 | /** |
||
219 | * Updates data at the given path. |
||
220 | * |
||
221 | * @param array $array |
||
222 | * @param sting $key |
||
223 | * @param callable $callback Callback to update the value. |
||
224 | * |
||
225 | * @return mixed Updated data. |
||
226 | */ |
||
227 | 1 | public static function update(array $array, string $key, callable $callback) |
|
228 | { |
||
229 | 1 | $keys = explode('.', $key); |
|
230 | 1 | $current = &$array; |
|
231 | |||
232 | 1 | foreach ($keys as $key) { |
|
233 | 1 | if (! isset($current[$key])) { |
|
234 | 1 | return $array; |
|
235 | } |
||
236 | |||
237 | 1 | $current = &$current[$key]; |
|
238 | } |
||
239 | |||
240 | 1 | $current = $callback($current); |
|
241 | |||
242 | 1 | return $array; |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * Remove one or many array items from a given array using "dot" notation. |
||
247 | * |
||
248 | * @param array $array |
||
249 | * @param array|string $keys |
||
250 | */ |
||
251 | 13 | public static function forget(array &$array, $keys) |
|
252 | { |
||
253 | 13 | $original = &$array; |
|
254 | 13 | $keys = (array) $keys; |
|
255 | |||
256 | 13 | if (count($keys) === 0) { |
|
257 | 2 | return; |
|
258 | } |
||
259 | |||
260 | 11 | foreach ($keys as $key) { |
|
261 | // if the exact key exists in the top-level, remove it |
||
262 | 11 | if (static::exists($array, $key)) { |
|
263 | 3 | unset($array[$key]); |
|
264 | 3 | continue; |
|
265 | } |
||
266 | |||
267 | 8 | $parts = explode('.', (string) $key); |
|
268 | // clean up before each pass |
||
269 | 8 | $array = &$original; |
|
270 | |||
271 | 8 | while (count($parts) > 1) { |
|
272 | 8 | $part = array_shift($parts); |
|
273 | 8 | if (isset($array[$part]) && is_array($array[$part])) { |
|
274 | 8 | $array = &$array[$part]; |
|
275 | } else { |
||
276 | 5 | continue 2; |
|
277 | } |
||
278 | } |
||
279 | |||
280 | 4 | unset($array[array_shift($parts)]); |
|
281 | } |
||
282 | 11 | } |
|
283 | |||
284 | /** |
||
285 | * Get a random element from the array supplied. |
||
286 | * |
||
287 | * @param array $array the source array |
||
288 | * |
||
289 | * @return mixed |
||
290 | */ |
||
291 | 1 | public static function random(array $array) |
|
292 | { |
||
293 | 1 | if (! count($array)) { |
|
294 | 1 | return; |
|
295 | } |
||
296 | |||
297 | 1 | $keys = array_rand($array, 1); |
|
298 | |||
299 | 1 | return static::value($array[$keys]); |
|
300 | } |
||
301 | |||
302 | /** |
||
303 | * Get a subset of the items from the given array. |
||
304 | * |
||
305 | * @param string[] $array |
||
306 | * @param string[] $keys |
||
307 | * |
||
308 | * @return string[] |
||
309 | */ |
||
310 | 1 | public static function only(array $array, array $keys) |
|
311 | { |
||
312 | 1 | return array_intersect_key($array, array_flip($keys)); |
|
313 | } |
||
314 | |||
315 | /** |
||
316 | * Determines if an array is associative. |
||
317 | * |
||
318 | * @param array $array |
||
319 | * |
||
320 | * @return bool |
||
321 | */ |
||
322 | 10 | public static function isAssoc(array $array): bool |
|
323 | { |
||
324 | 10 | if ($array === []) { |
|
325 | 1 | return true; |
|
326 | } |
||
327 | |||
328 | 9 | return array_keys($array) !== range(0, count($array) - 1); |
|
329 | } |
||
330 | |||
331 | /** |
||
332 | * Split an array in the given amount of pieces. |
||
333 | * |
||
334 | * @param array $array |
||
335 | * @param int $numberOfPieces |
||
336 | * @param bool $preserveKeys |
||
337 | * |
||
338 | * @return array |
||
339 | */ |
||
340 | 6 | public static function split(array $array, int $numberOfPieces = 2, bool $preserveKeys = false): array |
|
341 | { |
||
342 | 6 | if (count($array) === 0) { |
|
343 | 1 | return []; |
|
344 | } |
||
345 | |||
346 | 5 | $splitSize = ceil(count($array) / $numberOfPieces); |
|
347 | |||
348 | 5 | return array_chunk($array, (int) $splitSize, $preserveKeys); |
|
349 | } |
||
350 | |||
351 | /** |
||
352 | * Check if an array has a numeric index. |
||
353 | * |
||
354 | * @param array $array |
||
355 | * |
||
356 | * @return bool |
||
357 | */ |
||
358 | 1 | public static function isIndexed(array $array): bool |
|
359 | { |
||
360 | 1 | if ($array === []) { |
|
361 | 1 | return true; |
|
362 | } |
||
363 | |||
364 | 1 | return ! static::isAssoc($array); |
|
365 | } |
||
366 | |||
367 | /** |
||
368 | * Push an item onto the beginning of an array. |
||
369 | * |
||
370 | * @param array $array |
||
371 | * @param mixed $value |
||
372 | * @param mixed $key |
||
373 | * |
||
374 | * @return array |
||
375 | */ |
||
376 | 1 | public static function prepend(array $array, $value, $key = null): array |
|
377 | { |
||
378 | 1 | if (is_null($key)) { |
|
379 | 1 | array_unshift($array, $value); |
|
380 | } else { |
||
381 | 1 | $array = [$key => $value] + $array; |
|
382 | } |
||
383 | |||
384 | 1 | return $array; |
|
385 | } |
||
386 | |||
387 | /** |
||
388 | * Return the closest found value from array. |
||
389 | * |
||
390 | * @param array $array |
||
391 | * @param string $value |
||
392 | * |
||
393 | * @return mixed |
||
394 | */ |
||
395 | 1 | public static function closest(array $array, string $value) |
|
396 | { |
||
397 | 1 | sort($array); |
|
398 | 1 | $closest = $array[0]; |
|
399 | |||
400 | 1 | for ($i = 1, $j = count($array), $k = 0; $i < $j; $i++, $k++) { |
|
401 | 1 | $middleValue = ((int) $array[$i] - (int) $array[$k]) / 2 + (int) $array[$k]; |
|
402 | |||
403 | 1 | if ($value >= $middleValue) { |
|
404 | 1 | $closest = $array[$i]; |
|
405 | } |
||
406 | } |
||
407 | |||
408 | 1 | return static::value($closest); |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * Pop value from sub array. |
||
413 | * |
||
414 | * @param array $array |
||
415 | * @param string $key |
||
416 | * |
||
417 | * @return mixed |
||
418 | */ |
||
419 | 1 | public static function pop(array $array, string $key) |
|
420 | { |
||
421 | 1 | $keys = explode('.', $key); |
|
422 | |||
423 | 1 | foreach ($keys as $key) { |
|
424 | 1 | if (! isset($array[$key])) { |
|
425 | 1 | return; |
|
426 | } |
||
427 | |||
428 | 1 | $array = $array[$key]; |
|
429 | } |
||
430 | |||
431 | 1 | if (! is_array($array)) { |
|
432 | 1 | return; |
|
433 | } |
||
434 | |||
435 | 1 | return array_pop($array); |
|
436 | } |
||
437 | |||
438 | /** |
||
439 | * Swap two elements between positions. |
||
440 | * |
||
441 | * @param array $array array to swap |
||
442 | * @param string|int $swapA |
||
443 | * @param string|int $swapB |
||
444 | * |
||
445 | * @return array|null |
||
446 | */ |
||
447 | 1 | public static function swap(array $array, $swapA, $swapB) |
|
448 | { |
||
449 | 1 | list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]]; |
|
450 | |||
451 | 1 | return $array; |
|
452 | } |
||
453 | |||
454 | /** |
||
455 | * Create a new array consisting of every n-th element. |
||
456 | * |
||
457 | * @param array $array |
||
458 | * @param int $step |
||
459 | * @param int $offset |
||
460 | * |
||
461 | * @return array |
||
462 | */ |
||
463 | 1 | public static function every(array $array, int $step, int $offset = 0): array |
|
464 | { |
||
465 | 1 | $new = []; |
|
466 | |||
467 | 1 | $position = 0; |
|
468 | |||
469 | 1 | foreach ($array as $key => $item) { |
|
470 | 1 | if ($position % $step === $offset) { |
|
471 | 1 | $new[] = $item; |
|
472 | } |
||
473 | |||
474 | 1 | ++$position; |
|
475 | } |
||
476 | |||
477 | 1 | return $new; |
|
478 | } |
||
479 | |||
480 | /** |
||
481 | * Indexes an array depending on the values it contains. |
||
482 | * |
||
483 | * @param array $array |
||
484 | * @param callable $callback Function to combine values. |
||
485 | * @param bool $overwrite Should duplicate keys be overwritten? |
||
486 | * |
||
487 | * @return array Indexed values. |
||
488 | */ |
||
489 | 1 | public static function combine(array $array, callable $callback, bool $overwrite = true): array |
|
490 | { |
||
491 | 1 | $combined = []; |
|
492 | |||
493 | 1 | foreach ($array as $key => $value) { |
|
494 | 1 | $combinator = $callback($value, $key); |
|
495 | |||
496 | // fix for hhvm #1871 bug |
||
497 | 1 | if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.10.0', '<=')) { |
|
498 | $combinator->next(); |
||
499 | } |
||
500 | |||
501 | 1 | $index = $combinator->key(); |
|
502 | |||
503 | 1 | if ($overwrite || ! isset($combined[$index])) { |
|
504 | 1 | $combined[$index] = $combinator->current(); |
|
505 | } |
||
506 | } |
||
507 | |||
508 | 1 | return $combined; |
|
509 | } |
||
510 | |||
511 | /** |
||
512 | * Collapse a nested array down to an array of flat key=>value pairs. |
||
513 | * |
||
514 | * @param array $array |
||
515 | * |
||
516 | * @return array |
||
517 | */ |
||
518 | 3 | public static function collapse(array $array): array |
|
519 | { |
||
520 | 3 | $newArray = []; |
|
521 | |||
522 | 3 | foreach ($array as $key => $value) { |
|
523 | 3 | if (is_array($value)) { |
|
524 | // strip any manually added '.' |
||
525 | 3 | if (preg_match('/\./', (string) $key)) { |
|
526 | 2 | $key = substr($key, 0, -2); |
|
527 | } |
||
528 | |||
529 | 3 | self::recurseCollapse($value, $newArray, (array) $key); |
|
530 | } else { |
||
531 | 3 | $newArray[$key] = $value; |
|
532 | } |
||
533 | } |
||
534 | |||
535 | 3 | return $newArray; |
|
536 | } |
||
537 | |||
538 | /** |
||
539 | * Divide an array into two arrays. One with keys and the other with values. |
||
540 | * |
||
541 | * @param array $array |
||
542 | * |
||
543 | * @return array |
||
544 | */ |
||
545 | 1 | public static function divide(array $array): array |
|
546 | { |
||
547 | 1 | return [array_keys($array), array_values($array)]; |
|
548 | } |
||
549 | |||
550 | /** |
||
551 | * Stripe all empty items. |
||
552 | * |
||
553 | * @param array $array |
||
554 | * |
||
555 | * @return array |
||
556 | */ |
||
557 | 1 | public static function stripEmpty(array $array): array |
|
558 | { |
||
559 | return array_filter($array, function ($item) { |
||
560 | 1 | if (is_null($item)) { |
|
561 | 1 | return false; |
|
562 | } |
||
563 | |||
564 | 1 | return (bool) trim($item); |
|
565 | 1 | }); |
|
566 | } |
||
567 | |||
568 | /** |
||
569 | * Remove all instances of $ignore found in $elements (=== is used). |
||
570 | * |
||
571 | * @param array $array |
||
572 | * @param array $ignore |
||
573 | * |
||
574 | * @return array |
||
575 | */ |
||
576 | 1 | public static function without(array $array, array $ignore): array |
|
577 | { |
||
578 | 1 | foreach ($array as $key => $node) { |
|
579 | 1 | if (in_array($node, $ignore, true)) { |
|
580 | 1 | unset($array[$key]); |
|
581 | } |
||
582 | } |
||
583 | |||
584 | 1 | return array_values($array); |
|
585 | } |
||
586 | |||
587 | /** |
||
588 | * Reindexes a list of values. |
||
589 | * |
||
590 | * @param array $array |
||
591 | * @param array $map An map of correspondances of the form |
||
592 | * ['currentIndex' => 'newIndex']. |
||
593 | * @param bool $unmapped Whether or not to keep keys that are not |
||
594 | * remapped. |
||
595 | * |
||
596 | * @return array |
||
597 | */ |
||
598 | 1 | public static function reindex(array $array, array $map, bool $unmapped = true): array |
|
599 | { |
||
600 | 1 | $reindexed = $unmapped |
|
601 | 1 | ? $array |
|
602 | 1 | : []; |
|
603 | |||
604 | 1 | foreach ($map as $from => $to) { |
|
605 | 1 | if (isset($array[$from])) { |
|
606 | 1 | $reindexed[$to] = $array[$from]; |
|
607 | } |
||
608 | } |
||
609 | |||
610 | 1 | return $reindexed; |
|
611 | } |
||
612 | |||
613 | /** |
||
614 | * Merges two or more arrays into one recursively. |
||
615 | * |
||
616 | * @return array |
||
617 | */ |
||
618 | 4 | public static function merge(): array |
|
619 | { |
||
620 | 4 | $args = func_get_args(); |
|
621 | 4 | $array = array_shift($args); |
|
622 | |||
623 | 4 | while (! empty($args)) { |
|
624 | 4 | $next = array_shift($args); |
|
625 | |||
626 | 4 | foreach ($next as $key => $value) { |
|
627 | 4 | if (is_int($key)) { |
|
628 | 3 | if (isset($array[$key])) { |
|
629 | 2 | $array[] = $value; |
|
630 | } else { |
||
631 | 3 | $array[$key] = $value; |
|
632 | } |
||
633 | 2 | } elseif (is_array($value) && isset($array[$key]) && is_array($array[$key])) { |
|
634 | 1 | $array[$key] = static::merge($array[$key], $value); |
|
635 | } else { |
||
636 | 4 | $array[$key] = $value; |
|
637 | } |
||
638 | } |
||
639 | } |
||
640 | |||
641 | 4 | return $array; |
|
642 | } |
||
643 | |||
644 | /** |
||
645 | * Makes every value that is numerically indexed a key, given $default |
||
646 | * as value. |
||
647 | * |
||
648 | * @param array $array |
||
649 | * @param mixed $default |
||
650 | * |
||
651 | * @return array |
||
652 | */ |
||
653 | 1 | public static function normalize(array $array, $default): array |
|
654 | { |
||
655 | 1 | $normalized = []; |
|
656 | |||
657 | 1 | foreach ($array as $key => $value) { |
|
658 | 1 | if (is_numeric($key)) { |
|
659 | 1 | $key = $value; |
|
660 | 1 | $value = $default; |
|
661 | } |
||
662 | |||
663 | 1 | $normalized[$key] = $value; |
|
664 | } |
||
665 | |||
666 | 1 | return $normalized; |
|
667 | } |
||
668 | |||
669 | /** |
||
670 | * Extend one array with another. |
||
671 | * |
||
672 | * @return array |
||
673 | */ |
||
674 | 3 | public static function extend(): array |
|
675 | { |
||
676 | 3 | $merged = []; |
|
677 | |||
678 | 3 | foreach (func_get_args() as $array) { |
|
679 | 3 | foreach ($array as $key => $value) { |
|
680 | 3 | if (is_array($value) && static::has($merged, $key) && is_array($merged[$key])) { |
|
681 | 2 | $merged[$key] = static::extend($merged[$key], $value); |
|
682 | } else { |
||
683 | 3 | $merged[$key] = $value; |
|
684 | } |
||
685 | } |
||
686 | } |
||
687 | |||
688 | 3 | return $merged; |
|
689 | } |
||
690 | |||
691 | /** |
||
692 | * Transforms a 1-dimensional array into a multi-dimensional one, |
||
693 | * exploding keys according to a separator. |
||
694 | * |
||
695 | * @param array $array |
||
696 | * |
||
697 | * @return array |
||
698 | */ |
||
699 | 1 | public static function asHierarchy(array $array): array |
|
700 | { |
||
701 | 1 | $hierarchy = []; |
|
702 | |||
703 | 1 | foreach ($array as $key => $value) { |
|
704 | 1 | $segments = explode('.', (string) $key); |
|
705 | 1 | $valueSegment = array_pop($segments); |
|
706 | 1 | $branch = &$hierarchy; |
|
707 | |||
708 | 1 | foreach ($segments as $segment) { |
|
709 | 1 | if (! isset($branch[$segment])) { |
|
710 | 1 | $branch[$segment] = []; |
|
711 | } |
||
712 | |||
713 | 1 | $branch = &$branch[$segment]; |
|
714 | } |
||
715 | |||
716 | 1 | $branch[$valueSegment] = $value; |
|
717 | } |
||
718 | |||
719 | 1 | return $hierarchy; |
|
720 | } |
||
721 | |||
722 | /** |
||
723 | * Separates elements from an array into groups. |
||
724 | * The function maps an element to the key that will be used for grouping. |
||
725 | * If no function is passed, the element itself will be used as key. |
||
726 | * |
||
727 | * @param array $array |
||
728 | * @param callable|null $callback |
||
729 | * |
||
730 | * @return array |
||
731 | */ |
||
732 | 1 | public static function groupBy(array $array, callable $callback = null): array |
|
733 | { |
||
734 | $callback = $callback ?: function ($value) { |
||
735 | 1 | return $value; |
|
736 | 1 | }; |
|
737 | |||
738 | 1 | return array_reduce( |
|
739 | $array, |
||
740 | function ($buckets, $value) use ($callback) { |
||
741 | 1 | $key = $callback($value); |
|
742 | |||
743 | 1 | if (! array_key_exists($key, $buckets)) { |
|
744 | 1 | $buckets[$key] = []; |
|
745 | } |
||
746 | |||
747 | 1 | $buckets[$key][] = $value; |
|
748 | |||
749 | 1 | return $buckets; |
|
750 | 1 | }, |
|
751 | 1 | [] |
|
752 | ); |
||
753 | } |
||
754 | |||
755 | /** |
||
756 | * Flatten a multi-dimensional associative array with dots. |
||
757 | * |
||
758 | * @param array $array |
||
759 | * @param string $prepend |
||
760 | * |
||
761 | * @return array |
||
762 | */ |
||
763 | 4 | public static function dot(array $array, string $prepend = ''): array |
|
764 | { |
||
765 | 4 | $cache = serialize(['array' => $array, 'prepend' => $prepend]); |
|
766 | |||
767 | 4 | if (array_key_exists($cache, self::$dotted)) { |
|
768 | 1 | return self::$dotted[$cache]; |
|
769 | } |
||
770 | |||
771 | 3 | $results = []; |
|
772 | |||
773 | 3 | View Code Duplication | foreach ($array as $key => $value) { |
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...
|
|||
774 | 3 | if (is_array($value)) { |
|
775 | 2 | $results = array_merge($results, static::dot($value, $prepend . $key . '.')); |
|
776 | } else { |
||
777 | 3 | $results[$prepend . $key] = $value; |
|
778 | } |
||
779 | } |
||
780 | |||
781 | 3 | return self::$dotted[$cache] = $results; |
|
782 | } |
||
783 | |||
784 | /** |
||
785 | * Expand a dotted array. Acts the opposite way of Arr::dot(). |
||
786 | * |
||
787 | * @param array $array |
||
788 | * @param int|float $depth |
||
789 | * |
||
790 | * @return array |
||
791 | */ |
||
792 | 10 | public static function unDot(array $array, $depth = INF): array |
|
793 | { |
||
794 | 10 | $results = []; |
|
795 | |||
796 | 10 | foreach ($array as $key => $value) { |
|
797 | 9 | if (count($dottedKeys = explode('.', (string) $key, 2)) > 1) { |
|
798 | 9 | $results[$dottedKeys[0]][$dottedKeys[1]] = $value; |
|
799 | } else { |
||
800 | 9 | $results[$key] = $value; |
|
801 | } |
||
802 | } |
||
803 | |||
804 | 10 | foreach ($results as $key => $value) { |
|
805 | 9 | if (is_array($value) && ! empty($value) && $depth > 1) { |
|
806 | 9 | $results[$key] = static::unDot($value, $depth - 1); |
|
807 | } |
||
808 | } |
||
809 | |||
810 | 10 | return $results; |
|
811 | } |
||
812 | |||
813 | /** |
||
814 | * Flatten a nested array to a separated key. |
||
815 | * |
||
816 | * @param array $array |
||
817 | * @param string|null $separator |
||
818 | * @param string $prepend |
||
819 | * |
||
820 | * @return array |
||
821 | */ |
||
822 | 1 | public static function flatten(array $array, string $separator = null, string $prepend = ''): array |
|
823 | { |
||
824 | 1 | $flattened = []; |
|
825 | |||
826 | 1 | View Code Duplication | foreach ($array as $key => $value) { |
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...
|
|||
827 | 1 | if (is_array($value)) { |
|
828 | 1 | $flattened = array_merge($flattened, static::flatten($value, $separator, $prepend . $key . $separator)); |
|
829 | } else { |
||
830 | 1 | $flattened[$prepend . $key] = $value; |
|
831 | } |
||
832 | } |
||
833 | |||
834 | 1 | return $flattened; |
|
835 | } |
||
836 | |||
837 | /** |
||
838 | * Expand a flattened array with dots to a multi-dimensional associative array. |
||
839 | * |
||
840 | * @param array $array |
||
841 | * @param string $prepend |
||
842 | * |
||
843 | * @return array |
||
844 | */ |
||
845 | 4 | public static function expand(array $array, string $prepend = ''): array |
|
846 | { |
||
847 | 4 | $results = []; |
|
848 | |||
849 | 4 | if ($prepend) { |
|
850 | 2 | $prepend .= '.'; |
|
851 | } |
||
852 | |||
853 | 4 | foreach ($array as $key => $value) { |
|
854 | 4 | if ($prepend) { |
|
855 | 2 | $pos = strpos($key, $prepend); |
|
856 | |||
857 | 2 | if ($pos === 0) { |
|
858 | 1 | $key = substr($key, strlen($prepend)); |
|
859 | } |
||
860 | } |
||
861 | |||
862 | 4 | $results = static::set($results, $key, $value); |
|
863 | } |
||
864 | |||
865 | 4 | return $results; |
|
866 | } |
||
867 | |||
868 | /** |
||
869 | * Reset all numerical indexes of an array (start from zero). |
||
870 | * Non-numerical indexes will stay untouched. Returns a new array. |
||
871 | * |
||
872 | * @param array $array |
||
873 | * @param bool|false $deep |
||
874 | * |
||
875 | * @return array |
||
876 | */ |
||
877 | 3 | public static function reset(array $array, $deep = false) |
|
878 | { |
||
879 | 3 | $target = []; |
|
880 | |||
881 | 3 | foreach ($array as $key => $value) { |
|
882 | 3 | if ($deep && is_array($value)) { |
|
883 | 1 | $value = static::reset($value); |
|
884 | } |
||
885 | |||
886 | 3 | if (is_numeric($key)) { |
|
887 | 3 | $target[] = $value; |
|
888 | } else { |
||
889 | 3 | $target[$key] = $value; |
|
890 | } |
||
891 | } |
||
892 | |||
893 | 3 | return $target; |
|
894 | } |
||
895 | |||
896 | /** |
||
897 | * Extend one array with another. Non associative arrays will not be merged |
||
898 | * but rather replaced. |
||
899 | * |
||
900 | * @return array |
||
901 | */ |
||
902 | 4 | public static function extendDistinct() |
|
903 | { |
||
904 | 4 | $merged = []; |
|
905 | |||
906 | 4 | foreach (func_get_args() as $array) { |
|
907 | 4 | foreach ($array as $key => $value) { |
|
908 | 4 | if (is_array($value) && static::has($merged, $key) && is_array($merged[$key])) { |
|
909 | 3 | if (static::isAssoc($value) && static::isAssoc($merged[$key])) { |
|
910 | 2 | $merged[$key] = static::extendDistinct($merged[$key], $value); |
|
911 | |||
912 | 2 | continue; |
|
913 | } |
||
914 | } |
||
915 | |||
916 | 4 | $merged[$key] = $value; |
|
917 | } |
||
918 | } |
||
919 | |||
920 | 4 | return $merged; |
|
921 | } |
||
922 | |||
923 | /** |
||
924 | * Sort the array using the given callback. |
||
925 | * |
||
926 | * @param array $array |
||
927 | * @param callable $callback |
||
928 | * @param int $options |
||
929 | * @param bool $descending |
||
930 | * |
||
931 | * @return array |
||
932 | */ |
||
933 | 1 | public static function sort( |
|
934 | array $array, |
||
935 | callable $callback, |
||
936 | int $options = SORT_REGULAR, |
||
937 | bool $descending = false |
||
938 | ): array { |
||
939 | 1 | $results = []; |
|
940 | |||
941 | // First we will loop through the items and get the comparator from a callback |
||
942 | // function which we were given. Then, we will sort the returned values and |
||
943 | // and grab the corresponding values for the sorted keys from this array. |
||
944 | 1 | foreach ($array as $key => $value) { |
|
945 | 1 | $results[$key] = $callback($value, $key); |
|
946 | } |
||
947 | |||
948 | 1 | $descending ? arsort($results, $options) : asort($results, $options); |
|
949 | |||
950 | // Once we have sorted all of the keys in the array, we will loop through them |
||
951 | // and grab the corresponding model so we can set the underlying items list |
||
952 | // to the sorted version. Then we'll just return the collection instance. |
||
953 | 1 | foreach (array_keys($results) as $key) { |
|
954 | 1 | $results[$key] = $array[$key]; |
|
955 | } |
||
956 | |||
957 | 1 | return $results; |
|
958 | } |
||
959 | |||
960 | /** |
||
961 | * Recursively sort an array by keys and values. |
||
962 | * |
||
963 | * @param array $array |
||
964 | * |
||
965 | * @return array |
||
966 | */ |
||
967 | 1 | public static function sortRecursive(array $array) |
|
968 | { |
||
969 | 1 | foreach ($array as &$value) { |
|
970 | 1 | if (is_array($value)) { |
|
971 | 1 | $value = static::sortRecursive($value); |
|
972 | } |
||
973 | } |
||
974 | |||
975 | // sort associative array |
||
976 | 1 | if (static::isAssoc($array)) { |
|
977 | 1 | ksort($array); |
|
978 | // sort regular array |
||
979 | } else { |
||
980 | 1 | sort($array); |
|
981 | } |
||
982 | |||
983 | 1 | return $array; |
|
984 | } |
||
985 | |||
986 | /** |
||
987 | * Will turn each element in $arr into an array then appending |
||
988 | * the associated indexs from the other arrays into this array as well. |
||
989 | * |
||
990 | * @return array<*,array> |
||
991 | */ |
||
992 | 2 | public static function zip() |
|
993 | { |
||
994 | 2 | $args = func_get_args(); |
|
995 | 2 | $originalArr = $args[0]; |
|
996 | |||
997 | 2 | array_shift($args); |
|
998 | |||
999 | 2 | $array = []; |
|
1000 | |||
1001 | 2 | foreach ($originalArr as $key => $value) { |
|
1002 | 2 | $array[$key] = [$value]; |
|
1003 | |||
1004 | 2 | foreach ($args as $k => $v) { |
|
1005 | 2 | $array[$key][] = current($args[$k]); |
|
1006 | |||
1007 | 2 | if (next($args[$k]) === false && $args[$k] !== [null]) { |
|
1008 | 2 | $args[$k] = [null]; |
|
1009 | } |
||
1010 | } |
||
1011 | } |
||
1012 | |||
1013 | 2 | return $array; |
|
1014 | } |
||
1015 | |||
1016 | /** |
||
1017 | * Applies the callback to the elements of the given arrays |
||
1018 | * |
||
1019 | * @param array $array |
||
1020 | * @param callable $callback |
||
1021 | * |
||
1022 | * @return array |
||
1023 | */ |
||
1024 | 1 | public static function map(array $array, callable $callback) |
|
1025 | { |
||
1026 | 1 | $newArray = []; |
|
1027 | |||
1028 | 1 | foreach ($array as $key => $item) { |
|
1029 | 1 | $result = $callback($item, $key); |
|
1030 | |||
1031 | 1 | $newArray = is_array($result) ? |
|
1032 | 1 | array_replace_recursive($array, $result) : |
|
1033 | 1 | array_merge_recursive($array, (array) $result); |
|
1034 | } |
||
1035 | |||
1036 | 1 | return $newArray; |
|
1037 | } |
||
1038 | |||
1039 | /** |
||
1040 | * Filters each of the given values through a function. |
||
1041 | * |
||
1042 | * @param array $array |
||
1043 | * @param callable $callback |
||
1044 | * |
||
1045 | * @return array |
||
1046 | */ |
||
1047 | 2 | public static function filter(array $array, callable $callback) |
|
1048 | { |
||
1049 | 2 | return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); |
|
1050 | } |
||
1051 | |||
1052 | /** |
||
1053 | * Returns whether every element of the array satisfies the given predicate or not. |
||
1054 | * Works with Iterators too. |
||
1055 | * |
||
1056 | * @param array $array |
||
1057 | * @param callable $predicate |
||
1058 | * |
||
1059 | * @return bool |
||
1060 | */ |
||
1061 | 1 | public static function all(array $array, callable $predicate) |
|
1062 | { |
||
1063 | 1 | foreach ($array as $key => $value) { |
|
1064 | 1 | if (! $predicate($value, $key, $array)) { |
|
1065 | 1 | return false; |
|
1066 | } |
||
1067 | } |
||
1068 | |||
1069 | 1 | return true; |
|
1070 | } |
||
1071 | |||
1072 | /** |
||
1073 | * The opposite of filter(). |
||
1074 | * |
||
1075 | * @param array $array |
||
1076 | * @param callable $callback Function to filter values. |
||
1077 | * |
||
1078 | * @return array filtered array. |
||
1079 | */ |
||
1080 | public static function reject(array $array, callable $callback): array |
||
1081 | { |
||
1082 | 1 | return static::filter($array, function ($value, $key) use ($callback) { |
|
1083 | 1 | return ! $callback($value, $key); |
|
1084 | 1 | }); |
|
1085 | } |
||
1086 | |||
1087 | /** |
||
1088 | * Filter the array using the given Closure. |
||
1089 | * |
||
1090 | * @param array $array |
||
1091 | * @param callable $callback |
||
1092 | * |
||
1093 | * @return array |
||
1094 | */ |
||
1095 | 1 | public static function where(array $array, callable $callback): array |
|
1096 | { |
||
1097 | 1 | $filtered = []; |
|
1098 | |||
1099 | 1 | foreach ($array as $key => $value) { |
|
1100 | 1 | if ($callback($key, $value)) { |
|
1101 | 1 | $filtered[$key] = $value; |
|
1102 | } |
||
1103 | } |
||
1104 | |||
1105 | 1 | return $filtered; |
|
1106 | } |
||
1107 | |||
1108 | /** |
||
1109 | * Return the first element in an array passing a given truth test. |
||
1110 | * |
||
1111 | * @param array $array |
||
1112 | * @param callable|null $callback |
||
1113 | * @param mixed $default |
||
1114 | * |
||
1115 | * @return mixed |
||
1116 | */ |
||
1117 | 2 | public static function first(array $array, callable $callback = null, $default = null) |
|
1118 | { |
||
1119 | 2 | if (is_null($callback)) { |
|
1120 | 1 | if (empty($array)) { |
|
1121 | return static::value($default); |
||
1122 | } |
||
1123 | |||
1124 | 1 | foreach ($array as $item) { |
|
1125 | 1 | return $item; |
|
1126 | } |
||
1127 | } |
||
1128 | |||
1129 | 2 | foreach ($array as $key => $value) { |
|
1130 | 2 | if ($callback($key, $value)) { |
|
1131 | 2 | return $value; |
|
1132 | } |
||
1133 | } |
||
1134 | |||
1135 | 1 | return static::value($default); |
|
1136 | } |
||
1137 | |||
1138 | /** |
||
1139 | * Return the last element in an array passing a given truth test. |
||
1140 | * |
||
1141 | * @param array $array |
||
1142 | * @param callable|null $callback |
||
1143 | * @param mixed $default |
||
1144 | * |
||
1145 | * @return mixed |
||
1146 | */ |
||
1147 | 1 | public static function last(array $array, callable $callback = null, $default = null) |
|
1148 | { |
||
1149 | 1 | if ($callback === null) { |
|
1150 | 1 | return empty($array) ? static::value($default) : end($array); |
|
1151 | } |
||
1152 | |||
1153 | 1 | return static::first(array_reverse($array, true), $callback, $default); |
|
1154 | } |
||
1155 | |||
1156 | /** |
||
1157 | * Get all of the given array except for a specified array of items. |
||
1158 | * |
||
1159 | * @param array $array |
||
1160 | * @param array|string $keys |
||
1161 | * |
||
1162 | * @return array |
||
1163 | */ |
||
1164 | 1 | public static function except(array $array, $keys): array |
|
1165 | { |
||
1166 | 1 | static::forget($array, $keys); |
|
1167 | |||
1168 | 1 | return $array; |
|
1169 | } |
||
1170 | |||
1171 | /** |
||
1172 | * Return the default value of the given value. |
||
1173 | * |
||
1174 | * @param mixed $value |
||
1175 | * |
||
1176 | * @return mixed |
||
1177 | */ |
||
1178 | 10 | public static function value($value) |
|
1179 | { |
||
1180 | 10 | return $value instanceof Closure ? $value() : $value; |
|
1181 | } |
||
1182 | |||
1183 | /** |
||
1184 | * Recurse through an array, add the leaf items to the $newArray var |
||
1185 | * |
||
1186 | * @param array $subject |
||
1187 | * @param array &$newArray |
||
1188 | * @param array $stack |
||
1189 | * |
||
1190 | * @return string[]|null |
||
1191 | */ |
||
1192 | 3 | private static function recurseCollapse(array $subject, array &$newArray, $stack = []) |
|
1193 | { |
||
1194 | 3 | foreach ($subject as $key => $value) { |
|
1195 | 3 | $fstack = array_merge($stack, [$key]); |
|
1196 | |||
1197 | 3 | if (is_array($value)) { |
|
1198 | 3 | self::recurseCollapse($value, $newArray, $fstack); |
|
1199 | } else { |
||
1200 | 3 | $top = array_shift($fstack); |
|
1201 | 3 | $arrayPart = count($fstack) ? '.' . implode('.', $fstack) : ''; |
|
1202 | 3 | $newArray[$top . $arrayPart] = $value; |
|
1203 | } |
||
1204 | } |
||
1205 | 3 | } |
|
1206 | } |
||
1207 |
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.