Passed
Push — master ( 82e9fe...cecb4c )
by Sheldon
04:44
created

Arr::get()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 8
nop 3
dl 0
loc 27
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
namespace MiotApi\Util\Collection;
4
5
use ArrayAccess;
6
use InvalidArgumentException;
7
8
class Arr
9
{
10
    use Macroable;
0 ignored issues
show
Bug introduced by
The trait MiotApi\Util\Collection\Macroable requires the property $name which is not provided by MiotApi\Util\Collection\Arr.
Loading history...
11
12
    /**
13
     * Determine whether the given value is array accessible.
14
     *
15
     * @param mixed $value
16
     *
17
     * @return bool
18
     */
19
    public static function accessible($value)
20
    {
21
        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
     *
31
     * @return array
32
     */
33
    public static function add($array, $key, $value)
34
    {
35
        if (is_null(static::get($array, $key))) {
36
            static::set($array, $key, $value);
37
        }
38
39
        return $array;
40
    }
41
42
    /**
43
     * Collapse an array of arrays into a single array.
44
     *
45
     * @param array $array
46
     *
47
     * @return array
48
     */
49
    public static function collapse($array)
50
    {
51
        $results = [];
52
53
        foreach ($array as $values) {
54
            if ($values instanceof Collection) {
55
                $values = $values->all();
56
            } elseif (!is_array($values)) {
57
                continue;
58
            }
59
60
            $results = array_merge($results, $values);
61
        }
62
63
        return $results;
64
    }
65
66
    /**
67
     * Cross join the given arrays, returning all possible permutations.
68
     *
69
     * @param array ...$arrays
70
     *
71
     * @return array
72
     */
73
    public static function crossJoin(...$arrays)
74
    {
75
        $results = [[]];
76
77
        foreach ($arrays as $index => $array) {
78
            $append = [];
79
80
            foreach ($results as $product) {
81
                foreach ($array as $item) {
82
                    $product[$index] = $item;
83
84
                    $append[] = $product;
85
                }
86
            }
87
88
            $results = $append;
89
        }
90
91
        return $results;
92
    }
93
94
    /**
95
     * Divide an array into two arrays. One with keys and the other with values.
96
     *
97
     * @param array $array
98
     *
99
     * @return array
100
     */
101
    public static function divide($array)
102
    {
103
        return [array_keys($array), array_values($array)];
104
    }
105
106
    /**
107
     * Flatten a multi-dimensional associative array with dots.
108
     *
109
     * @param array  $array
110
     * @param string $prepend
111
     *
112
     * @return array
113
     */
114
    public static function dot($array, $prepend = '')
115
    {
116
        $results = [];
117
118
        foreach ($array as $key => $value) {
119
            if (is_array($value) && !empty($value)) {
120
                $results = array_merge($results, static::dot($value, $prepend . $key . '.'));
121
            } else {
122
                $results[$prepend . $key] = $value;
123
            }
124
        }
125
126
        return $results;
127
    }
128
129
    /**
130
     * Get all of the given array except for a specified array of keys.
131
     *
132
     * @param array        $array
133
     * @param array|string $keys
134
     *
135
     * @return array
136
     */
137
    public static function except($array, $keys)
138
    {
139
        static::forget($array, $keys);
140
141
        return $array;
142
    }
143
144
    /**
145
     * Determine if the given key exists in the provided array.
146
     *
147
     * @param \ArrayAccess|array $array
148
     * @param string|int         $key
149
     *
150
     * @return bool
151
     */
152
    public static function exists($array, $key)
153
    {
154
        if ($array instanceof ArrayAccess) {
155
            return $array->offsetExists($key);
156
        }
157
158
        return array_key_exists($key, $array);
159
    }
160
161
    /**
162
     * Return the first element in an array passing a given truth test.
163
     *
164
     * @param array         $array
165
     * @param callable|null $callback
166
     * @param mixed         $default
167
     *
168
     * @return mixed
169
     */
170
    public static function first($array, callable $callback = null, $default = null)
171
    {
172
        if (is_null($callback)) {
173
            if (empty($array)) {
174
                return static::value($default);
175
            }
176
177
            foreach ($array as $item) {
178
                return $item;
179
            }
180
        }
181
182
        foreach ($array as $key => $value) {
183
            if (call_user_func($callback, $value, $key)) {
184
                return $value;
185
            }
186
        }
187
188
        return static::value($default);
189
    }
190
191
    /**
192
     * Return the last element in an array passing a given truth test.
193
     *
194
     * @param array         $array
195
     * @param callable|null $callback
196
     * @param mixed         $default
197
     *
198
     * @return mixed
199
     */
200
    public static function last($array, callable $callback = null, $default = null)
201
    {
202
        if (is_null($callback)) {
203
            return empty($array) ? static::value($default) : end($array);
204
        }
205
206
        return static::first(array_reverse($array, true), $callback, $default);
207
    }
208
209
    public static function value($value)
210
    {
211
        return $value instanceof \Closure ? $value() : $value;
212
    }
213
214
    /**
215
     * Flatten a multi-dimensional array into a single level.
216
     *
217
     * @param array $array
218
     * @param int   $depth
219
     *
220
     * @return array
221
     */
222
    public static function flatten($array, $depth = INF)
223
    {
224
        $result = [];
225
226
        foreach ($array as $item) {
227
            $item = $item instanceof Collection ? $item->all() : $item;
228
229
            if (!is_array($item)) {
230
                $result[] = $item;
231
            } elseif ($depth === 1) {
232
                $result = array_merge($result, array_values($item));
233
            } else {
234
                $result = array_merge($result, static::flatten($item, $depth - 1));
0 ignored issues
show
Bug introduced by
$depth - 1 of type double is incompatible with the type integer expected by parameter $depth of MiotApi\Util\Collection\Arr::flatten(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

234
                $result = array_merge($result, static::flatten($item, /** @scrutinizer ignore-type */ $depth - 1));
Loading history...
235
            }
236
        }
237
238
        return $result;
239
    }
240
241
    /**
242
     * Remove one or many array items from a given array using "dot" notation.
243
     *
244
     * @param array        $array
245
     * @param array|string $keys
246
     *
247
     * @return void
248
     */
249
    public static function forget(&$array, $keys)
250
    {
251
        $original = &$array;
252
253
        $keys = (array) $keys;
254
255
        if (count($keys) === 0) {
256
            return;
257
        }
258
259
        foreach ($keys as $key) {
260
            // if the exact key exists in the top-level, remove it
261
            if (static::exists($array, $key)) {
262
                unset($array[$key]);
263
264
                continue;
265
            }
266
267
            $parts = explode('.', $key);
268
269
            // clean up before each pass
270
            $array = &$original;
271
272
            while (count($parts) > 1) {
273
                $part = array_shift($parts);
274
275
                if (isset($array[$part]) && is_array($array[$part])) {
276
                    $array = &$array[$part];
277
                } else {
278
                    continue 2;
279
                }
280
            }
281
282
            unset($array[array_shift($parts)]);
283
        }
284
    }
285
286
    /**
287
     * Get an item from an array using "dot" notation.
288
     *
289
     * @param \ArrayAccess|array $array
290
     * @param string             $key
291
     * @param mixed              $default
292
     *
293
     * @return mixed
294
     */
295
    public static function get($array, $key, $default = null)
296
    {
297
        if (!static::accessible($array)) {
298
            return static::value($default);
299
        }
300
301
        if (is_null($key)) {
0 ignored issues
show
introduced by
The condition is_null($key) is always false.
Loading history...
302
            return $array;
303
        }
304
305
        if (static::exists($array, $key)) {
306
            return $array[$key];
307
        }
308
309
        if (strpos($key, '.') === false) {
310
            return $array[$key] ? $array[$key] : static::value($default);
311
        }
312
313
        foreach (explode('.', $key) as $segment) {
314
            if (static::accessible($array) && static::exists($array, $segment)) {
315
                $array = $array[$segment];
316
            } else {
317
                return static::value($default);
318
            }
319
        }
320
321
        return $array;
322
    }
323
324
    /**
325
     * Check if an item or items exist in an array using "dot" notation.
326
     *
327
     * @param \ArrayAccess|array $array
328
     * @param string|array       $keys
329
     *
330
     * @return bool
331
     */
332
    public static function has($array, $keys)
333
    {
334
        if (is_null($keys)) {
0 ignored issues
show
introduced by
The condition is_null($keys) is always false.
Loading history...
335
            return false;
336
        }
337
338
        $keys = (array) $keys;
339
340
        if (!$array) {
341
            return false;
342
        }
343
344
        if ($keys === []) {
345
            return false;
346
        }
347
348
        foreach ($keys as $key) {
349
            $subKeyArray = $array;
350
351
            if (static::exists($array, $key)) {
352
                continue;
353
            }
354
355
            foreach (explode('.', $key) as $segment) {
356
                if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {
357
                    $subKeyArray = $subKeyArray[$segment];
358
                } else {
359
                    return false;
360
                }
361
            }
362
        }
363
364
        return true;
365
    }
366
367
    /**
368
     * Determines if an array is associative.
369
     *
370
     * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
371
     *
372
     * @param array $array
373
     *
374
     * @return bool
375
     */
376
    public static function isAssoc(array $array)
377
    {
378
        $keys = array_keys($array);
379
380
        return array_keys($keys) !== $keys;
381
    }
382
383
    /**
384
     * Get a subset of the items from the given array.
385
     *
386
     * @param array        $array
387
     * @param array|string $keys
388
     *
389
     * @return array
390
     */
391
    public static function only($array, $keys)
392
    {
393
        return array_intersect_key($array, array_flip((array) $keys));
394
    }
395
396
    /**
397
     * Get an item from an array or object using "dot" notation.
398
     *
399
     * @param mixed        $target
400
     * @param string|array $key
401
     * @param mixed        $default
402
     *
403
     * @return mixed
404
     */
405
    public static function data_get($target, $key, $default = null)
406
    {
407
        if (is_null($key)) {
0 ignored issues
show
introduced by
The condition is_null($key) is always false.
Loading history...
408
            return $target;
409
        }
410
411
        $key = is_array($key) ? $key : explode('.', $key);
412
413
        while (!is_null($segment = array_shift($key))) {
414
            if ($segment === '*') {
415
                if ($target instanceof Collection) {
416
                    $target = $target->all();
417
                } elseif (!is_array($target)) {
418
                    return static::value($default);
419
                }
420
421
                $result = self::pluck($target, $key);
422
423
                return in_array('*', $key) ? self::collapse($result) : $result;
424
            }
425
426
            if (self::accessible($target) && self::exists($target, $segment)) {
427
                $target = $target[$segment];
428
            } elseif (is_object($target) && isset($target->{$segment})) {
429
                $target = $target->{$segment};
430
            } else {
431
                return static::value($default);
432
            }
433
        }
434
435
        return $target;
436
    }
437
438
    /**
439
     * Pluck an array of values from an array.
440
     *
441
     * @param array             $array
442
     * @param string|array      $value
443
     * @param string|array|null $key
444
     *
445
     * @return array
446
     */
447
    public static function pluck($array, $value, $key = null)
448
    {
449
        $results = [];
450
451
        list($value, $key) = static::explodePluckParameters($value, $key);
452
453
        foreach ($array as $item) {
454
            $itemValue = static::data_get($item, $value);
455
456
            // If the key is "null", we will just append the value to the array and keep
457
            // looping. Otherwise we will key the array using the value of the key we
458
            // received from the developer. Then we'll return the final array form.
459
            if (is_null($key)) {
460
                $results[] = $itemValue;
461
            } else {
462
                $itemKey = static::data_get($item, $key);
463
464
                if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
465
                    $itemKey = (string) $itemKey;
466
                }
467
468
                $results[$itemKey] = $itemValue;
469
            }
470
        }
471
472
        return $results;
473
    }
474
475
    /**
476
     * Explode the "value" and "key" arguments passed to "pluck".
477
     *
478
     * @param string|array      $value
479
     * @param string|array|null $key
480
     *
481
     * @return array
482
     */
483
    protected static function explodePluckParameters($value, $key)
484
    {
485
        $value = is_string($value) ? explode('.', $value) : $value;
486
487
        $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
488
489
        return [$value, $key];
490
    }
491
492
    /**
493
     * Push an item onto the beginning of an array.
494
     *
495
     * @param array $array
496
     * @param mixed $value
497
     * @param mixed $key
498
     *
499
     * @return array
500
     */
501
    public static function prepend($array, $value, $key = null)
502
    {
503
        if (is_null($key)) {
504
            array_unshift($array, $value);
505
        } else {
506
            $array = [$key => $value] + $array;
507
        }
508
509
        return $array;
510
    }
511
512
    /**
513
     * Get a value from the array, and remove it.
514
     *
515
     * @param array  $array
516
     * @param string $key
517
     * @param mixed  $default
518
     *
519
     * @return mixed
520
     */
521
    public static function pull(&$array, $key, $default = null)
522
    {
523
        $value = static::get($array, $key, $default);
524
525
        static::forget($array, $key);
526
527
        return $value;
528
    }
529
530
    /**
531
     * Get one or a specified number of random values from an array.
532
     *
533
     * @param array    $array
534
     * @param int|null $number
535
     *
536
     * @throws \InvalidArgumentException
537
     *
538
     * @return mixed
539
     */
540
    public static function random($array, $number = null)
541
    {
542
        $requested = is_null($number) ? 1 : $number;
543
544
        $count = count($array);
545
546
        if ($requested > $count) {
547
            throw new InvalidArgumentException(
548
                "You requested {$requested} items, but there are only {$count} items available."
549
            );
550
        }
551
552
        if (is_null($number)) {
553
            return $array[array_rand($array)];
554
        }
555
556
        if ((int) $number === 0) {
557
            return [];
558
        }
559
560
        $keys = array_rand($array, $number);
561
562
        $results = [];
563
564
        foreach ((array) $keys as $key) {
565
            $results[] = $array[$key];
566
        }
567
568
        return $results;
569
    }
570
571
    /**
572
     * Set an array item to a given value using "dot" notation.
573
     *
574
     * If no key is given to the method, the entire array will be replaced.
575
     *
576
     * @param array  $array
577
     * @param string $key
578
     * @param mixed  $value
579
     *
580
     * @return array
581
     */
582
    public static function set(&$array, $key, $value)
583
    {
584
        if (is_null($key)) {
0 ignored issues
show
introduced by
The condition is_null($key) is always false.
Loading history...
585
            return $array = $value;
586
        }
587
588
        $keys = explode('.', $key);
589
590
        while (count($keys) > 1) {
591
            $key = array_shift($keys);
592
593
            // If the key doesn't exist at this depth, we will just create an empty array
594
            // to hold the next value, allowing us to create the arrays to hold final
595
            // values at the correct depth. Then we'll keep digging into the array.
596
            if (!isset($array[$key]) || !is_array($array[$key])) {
597
                $array[$key] = [];
598
            }
599
600
            $array = &$array[$key];
601
        }
602
603
        $array[array_shift($keys)] = $value;
604
605
        return $array;
606
    }
607
608
    /**
609
     * Shuffle the given array and return the result.
610
     *
611
     * @param array $array
612
     *
613
     * @return array
614
     */
615
    public static function shuffle($array)
616
    {
617
        shuffle($array);
618
619
        return $array;
620
    }
621
622
    /**
623
     * Sort the array using the given callback or "dot" notation.
624
     *
625
     * @param array                $array
626
     * @param callable|string|null $callback
627
     *
628
     * @return array
629
     */
630
    public static function sort($array, $callback = null)
631
    {
632
        return Collection::make($array)->sortBy($callback)->all();
633
    }
634
635
    /**
636
     * Recursively sort an array by keys and values.
637
     *
638
     * @param array $array
639
     *
640
     * @return array
641
     */
642
    public static function sortRecursive($array)
643
    {
644
        foreach ($array as &$value) {
645
            if (is_array($value)) {
646
                $value = static::sortRecursive($value);
647
            }
648
        }
649
650
        if (static::isAssoc($array)) {
651
            ksort($array);
652
        } else {
653
            sort($array);
654
        }
655
656
        return $array;
657
    }
658
659
    /**
660
     * Filter the array using the given callback.
661
     *
662
     * @param array    $array
663
     * @param callable $callback
664
     *
665
     * @return array
666
     */
667
    public static function where($array, callable $callback)
668
    {
669
        return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
670
    }
671
672
    /**
673
     * If the given value is not an array, wrap it in one.
674
     *
675
     * @param mixed $value
676
     *
677
     * @return array
678
     */
679
    public static function wrap($value)
680
    {
681
        return !is_array($value) ? [$value] : $value;
682
    }
683
}
684