Arr   F
last analyzed

Complexity

Total Complexity 95

Size/Duplication

Total Lines 620
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 620
ccs 193
cts 193
cp 1
rs 1.98
c 0
b 0
f 0
wmc 95
lcom 2
cbo 2

28 Methods

Rating   Name   Duplication   Size   Complexity  
A accessible() 0 4 2
A add() 0 8 2
A collapse() 0 16 4
A crossJoin() 0 20 4
A divide() 0 4 1
A dot() 0 14 4
A except() 0 6 1
A exists() 0 8 2
B first() 0 20 6
A last() 0 8 3
B flatten() 0 22 6
B forget() 0 36 7
B get() 0 28 8
B has() 0 26 8
A isAssoc() 0 6 1
A only() 0 4 1
A pluck() 0 27 5
A explodePluckParameters() 0 8 4
A prepend() 0 10 2
A pull() 0 8 1
B random() 0 30 6
A set() 0 25 5
A shuffle() 0 12 2
A sort() 0 4 1
A sortRecursive() 0 16 4
A query() 0 4 1
A where() 0 4 1
A wrap() 0 8 3

How to fix   Complexity   

Complex Class

Complex classes like Arr often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Arr, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace IlluminateAgnostic\Arr\Support;
4
5
use ArrayAccess;
6
use IlluminateAgnostic\Arr\Support\Traits\Macroable;
7
use InvalidArgumentException;
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 94
    public static function accessible($value)
20
    {
21 94
        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 2
                $values = $values->all();
54 4
            } elseif (! is_array($values)) {
55 1
                continue;
56
            }
57
58 5
            $results[] = $values;
59
        }
60
61 5
        return array_merge([], ...$results);
62
    }
63
64
    /**
65
     * Cross join the given arrays, returning all possible permutations.
66
     *
67
     * @param  array  ...$arrays
68
     * @return array
69
     */
70 3
    public static function crossJoin(...$arrays)
71
    {
72 3
        $results = [[]];
73
74 3
        foreach ($arrays as $index => $array) {
75 3
            $append = [];
76
77 3
            foreach ($results as $product) {
78 3
                foreach ($array as $item) {
79 3
                    $product[$index] = $item;
80
81 3
                    $append[] = $product;
82
                }
83
            }
84
85 3
            $results = $append;
86
        }
87
88 3
        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 5
    public static function except($array, $keys)
132
    {
133 5
        static::forget($array, $keys);
134
135 5
        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 86
    public static function exists($array, $key)
146
    {
147 86
        if ($array instanceof ArrayAccess) {
148 5
            return $array->offsetExists($key);
149
        }
150
151 84
        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 29
    public static function first($array, callable $callback = null, $default = null)
163
    {
164 29
        if (is_null($callback)) {
165 18
            if (empty($array)) {
166 2
                return value($default);
167
            }
168
169 17
            foreach ($array as $item) {
170 17
                return $item;
171
            }
172
        }
173
174 12
        foreach ($array as $key => $value) {
175 12
            if ($callback($value, $key)) {
176 10
                return $value;
177
            }
178
        }
179
180 8
        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 13
    public static function last($array, callable $callback = null, $default = null)
192
    {
193 13
        if (is_null($callback)) {
194 11
            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
            } else {
217 5
                $values = $depth === 1
218 3
                    ? array_values($item)
219 5
                    : static::flatten($item, $depth - 1);
220
221 5
                foreach ($values as $value) {
222 5
                    $result[] = $value;
223
                }
224
            }
225
        }
226
227 5
        return $result;
228
    }
229
230
    /**
231
     * Remove one or many array items from a given array using "dot" notation.
232
     *
233
     * @param  array  $array
234
     * @param  array|string  $keys
235
     * @return void
236
     */
237 10
    public static function forget(&$array, $keys)
238
    {
239 10
        $original = &$array;
240
241 10
        $keys = (array) $keys;
242
243 10
        if (count($keys) === 0) {
244 1
            return;
245
        }
246
247 10
        foreach ($keys as $key) {
248
            // if the exact key exists in the top-level, remove it
249 10
            if (static::exists($array, $key)) {
250 7
                unset($array[$key]);
251
252 7
                continue;
253
            }
254
255 8
            $parts = explode('.', $key);
256
257
            // clean up before each pass
258 8
            $array = &$original;
259
260 8
            while (count($parts) > 1) {
261 3
                $part = array_shift($parts);
262
263 3
                if (isset($array[$part]) && is_array($array[$part])) {
264 3
                    $array = &$array[$part];
265
                } else {
266 2
                    continue 2;
267
                }
268
            }
269
270 7
            unset($array[array_shift($parts)]);
271
        }
272 10
    }
273
274
    /**
275
     * Get an item from an array using "dot" notation.
276
     *
277
     * @param  \ArrayAccess|array  $array
278
     * @param  string|int  $key
279
     * @param  mixed   $default
280
     * @return mixed
281
     */
282 6
    public static function get($array, $key, $default = null)
283
    {
284 6
        if (! static::accessible($array)) {
285 1
            return value($default);
286
        }
287
288 6
        if (is_null($key)) {
289 1
            return $array;
290
        }
291
292 6
        if (static::exists($array, $key)) {
293 4
            return $array[$key];
294
        }
295
296 4
        if (strpos($key, '.') === false) {
297 2
            return $array[$key] ?? value($default);
298
        }
299
300 3
        foreach (explode('.', $key) as $segment) {
301 3
            if (static::accessible($array) && static::exists($array, $segment)) {
302 2
                $array = $array[$segment];
303
            } else {
304 3
                return value($default);
305
            }
306
        }
307
308 1
        return $array;
309
    }
310
311
    /**
312
     * Check if an item or items exist in an array using "dot" notation.
313
     *
314
     * @param  \ArrayAccess|array  $array
315
     * @param  string|array  $keys
316
     * @return bool
317
     */
318 1
    public static function has($array, $keys)
319
    {
320 1
        $keys = (array) $keys;
321
322 1
        if (! $array || $keys === []) {
323 1
            return false;
324
        }
325
326 1
        foreach ($keys as $key) {
327 1
            $subKeyArray = $array;
328
329 1
            if (static::exists($array, $key)) {
330 1
                continue;
331
            }
332
333 1
            foreach (explode('.', $key) as $segment) {
334 1
                if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {
335 1
                    $subKeyArray = $subKeyArray[$segment];
336
                } else {
337 1
                    return false;
338
                }
339
            }
340
        }
341
342 1
        return true;
343
    }
344
345
    /**
346
     * Determines if an array is associative.
347
     *
348
     * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
349
     *
350
     * @param  array  $array
351
     * @return bool
352
     */
353 2
    public static function isAssoc(array $array)
354
    {
355 2
        $keys = array_keys($array);
356
357 2
        return array_keys($keys) !== $keys;
358
    }
359
360
    /**
361
     * Get a subset of the items from the given array.
362
     *
363
     * @param  array  $array
364
     * @param  array|string  $keys
365
     * @return array
366
     */
367 2
    public static function only($array, $keys)
368
    {
369 2
        return array_intersect_key($array, array_flip((array) $keys));
370
    }
371
372
    /**
373
     * Pluck an array of values from an array.
374
     *
375
     * @param  array  $array
376
     * @param  string|array  $value
377
     * @param  string|array|null  $key
378
     * @return array
379
     */
380 23
    public static function pluck($array, $value, $key = null)
381
    {
382 23
        $results = [];
383
384 23
        [$value, $key] = static::explodePluckParameters($value, $key);
385
386 23
        foreach ($array as $item) {
387 23
            $itemValue = data_get($item, $value);
388
389
            // If the key is "null", we will just append the value to the array and keep
390
            // looping. Otherwise we will key the array using the value of the key we
391
            // received from the developer. Then we'll return the final array form.
392 23
            if (is_null($key)) {
393 21
                $results[] = $itemValue;
394
            } else {
395 7
                $itemKey = data_get($item, $key);
396
397 7
                if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
398 1
                    $itemKey = (string) $itemKey;
399
                }
400
401 7
                $results[$itemKey] = $itemValue;
402
            }
403
        }
404
405 23
        return $results;
406
    }
407
408
    /**
409
     * Explode the "value" and "key" arguments passed to "pluck".
410
     *
411
     * @param  string|array  $value
412
     * @param  string|array|null  $key
413
     * @return array
414
     */
415 23
    protected static function explodePluckParameters($value, $key)
416
    {
417 23
        $value = is_string($value) ? explode('.', $value) : $value;
418
419 23
        $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
420
421 23
        return [$value, $key];
422
    }
423
424
    /**
425
     * Push an item onto the beginning of an array.
426
     *
427
     * @param  array  $array
428
     * @param  mixed  $value
429
     * @param  mixed  $key
430
     * @return array
431
     */
432 3
    public static function prepend($array, $value, $key = null)
433
    {
434 3
        if (is_null($key)) {
435 3
            array_unshift($array, $value);
436
        } else {
437 2
            $array = [$key => $value] + $array;
438
        }
439
440 3
        return $array;
441
    }
442
443
    /**
444
     * Get a value from the array, and remove it.
445
     *
446
     * @param  array   $array
447
     * @param  string  $key
448
     * @param  mixed   $default
449
     * @return mixed
450
     */
451 4
    public static function pull(&$array, $key, $default = null)
452
    {
453 4
        $value = static::get($array, $key, $default);
454
455 4
        static::forget($array, $key);
456
457 4
        return $value;
458
    }
459
460
    /**
461
     * Get one or a specified number of random values from an array.
462
     *
463
     * @param  array  $array
464
     * @param  int|null  $number
465
     * @return mixed
466
     *
467
     * @throws \InvalidArgumentException
468
     */
469 9
    public static function random($array, $number = null)
470
    {
471 9
        $requested = is_null($number) ? 1 : $number;
472
473 9
        $count = count($array);
474
475 9
        if ($requested > $count) {
476 3
            throw new InvalidArgumentException(
477 3
                "You requested {$requested} items, but there are only {$count} items available."
478
            );
479
        }
480
481 6
        if (is_null($number)) {
482 3
            return $array[array_rand($array)];
483
        }
484
485 6
        if ((int) $number === 0) {
486 6
            return [];
487
        }
488
489 3
        $keys = array_rand($array, $number);
490
491 3
        $results = [];
492
493 3
        foreach ((array) $keys as $key) {
494 3
            $results[] = $array[$key];
495
        }
496
497 3
        return $results;
498
    }
499
500
    /**
501
     * Set an array item to a given value using "dot" notation.
502
     *
503
     * If no key is given to the method, the entire array will be replaced.
504
     *
505
     * @param  array   $array
506
     * @param  string  $key
507
     * @param  mixed   $value
508
     * @return array
509
     */
510 3
    public static function set(&$array, $key, $value)
511
    {
512 3
        if (is_null($key)) {
513 1
            return $array = $value;
514
        }
515
516 3
        $keys = explode('.', $key);
517
518 3
        while (count($keys) > 1) {
519 3
            $key = array_shift($keys);
520
521
            // If the key doesn't exist at this depth, we will just create an empty array
522
            // to hold the next value, allowing us to create the arrays to hold final
523
            // values at the correct depth. Then we'll keep digging into the array.
524 3
            if (! isset($array[$key]) || ! is_array($array[$key])) {
525 2
                $array[$key] = [];
526
            }
527
528 3
            $array = &$array[$key];
529
        }
530
531 3
        $array[array_shift($keys)] = $value;
532
533 3
        return $array;
534
    }
535
536
    /**
537
     * Shuffle the given array and return the result.
538
     *
539
     * @param  array  $array
540
     * @param  int|null  $seed
541
     * @return array
542
     */
543 3
    public static function shuffle($array, $seed = null)
544
    {
545 3
        if (is_null($seed)) {
546 1
            shuffle($array);
547
        } else {
548 2
            mt_srand($seed);
549 2
            shuffle($array);
550 2
            mt_srand();
551
        }
552
553 3
        return $array;
554
    }
555
556
    /**
557
     * Sort the array using the given callback or "dot" notation.
558
     *
559
     * @param  array  $array
560
     * @param  callable|string|null  $callback
561
     * @return array
562
     */
563 1
    public static function sort($array, $callback = null)
564
    {
565 1
        return Collection::make($array)->sortBy($callback)->all();
566
    }
567
568
    /**
569
     * Recursively sort an array by keys and values.
570
     *
571
     * @param  array  $array
572
     * @return array
573
     */
574 1
    public static function sortRecursive($array)
575
    {
576 1
        foreach ($array as &$value) {
577 1
            if (is_array($value)) {
578 1
                $value = static::sortRecursive($value);
579
            }
580
        }
581
582 1
        if (static::isAssoc($array)) {
583 1
            ksort($array);
584
        } else {
585 1
            sort($array);
586
        }
587
588 1
        return $array;
589
    }
590
591
    /**
592
     * Convert the array into a query string.
593
     *
594
     * @param  array  $array
595
     * @return string
596
     */
597 1
    public static function query($array)
598
    {
599 1
        return http_build_query($array, null, '&', PHP_QUERY_RFC3986);
600
    }
601
602
    /**
603
     * Filter the array using the given callback.
604
     *
605
     * @param  array  $array
606
     * @param  callable  $callback
607
     * @return array
608
     */
609 52
    public static function where($array, callable $callback)
610
    {
611 52
        return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
612
    }
613
614
    /**
615
     * If the given value is not an array and not null, wrap it in one.
616
     *
617
     * @param  mixed  $value
618
     * @return array
619
     */
620 11
    public static function wrap($value)
621
    {
622 11
        if (is_null($value)) {
623 1
            return [];
624
        }
625
626 11
        return is_array($value) ? $value : [$value];
627
    }
628
}
629