Passed
Push — main ( 639af1...96f9cc )
by Andrey
12:38 queued 11:16
created

Arr   F

Complexity

Total Complexity 66

Size/Duplication

Total Lines 463
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 9
Bugs 2 Features 0
Metric Value
eloc 100
c 9
b 2
f 0
dl 0
loc 463
ccs 127
cts 127
cp 1
rs 3.12
wmc 66

24 Methods

Rating   Name   Duplication   Size   Complexity  
A sort() 0 13 4
A renameKeysMap() 0 4 1
A sortByKeys() 0 6 1
A addUnique() 0 11 3
A merge() 0 15 4
A get() 0 3 1
A only() 0 17 6
A wrap() 0 7 3
A longestStringLength() 0 5 2
A except() 0 9 3
A renameKeys() 0 11 2
A exists() 0 7 2
A toArray() 0 13 5
A getKey() 0 3 2
A ksort() 0 13 4
A store() 0 5 2
A isArrayable() 0 3 3
A map() 0 11 5
A storeAsJson() 0 5 1
A prepareToStore() 0 13 2
A storeAsArray() 0 5 1
A isEmpty() 0 6 5
A flatten() 0 17 3
A doesntEmpty() 0 3 1

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.

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 Helldar\Support\Helpers;
4
5
use ArrayAccess;
6
use Helldar\Support\Facades\Helpers\Filesystem\File;
7
use Helldar\Support\Facades\Tools\Sorter;
8
use Helldar\Support\Facades\Tools\Stub;
9
use Helldar\Support\Tools\Stub as StubTool;
10
11
class Arr
12
{
13
    /**
14
     * Renaming array keys.
15
     * As the second parameter, a callback function is passed, which determines the actions for processing the value.
16
     * The output of the function must be a string with a name.
17
     *
18
     * @param  array  $array
19
     * @param  callable  $callback
20
     *
21
     * @return array
22
     */
23 4
    public function renameKeys(array $array, callable $callback): array
24
    {
25 4
        $result = [];
26
27 4
        foreach ($array as $key => $value) {
28 4
            $new = $callback($key, $value);
29
30 4
            $result[$new] = $value;
31
        }
32
33 4
        return $result;
34
    }
35
36
    /**
37
     * Renaming array keys with map.
38
     *
39
     * @param  array  $array
40
     * @param  array  $map
41
     *
42
     * @return array
43
     */
44 2
    public function renameKeysMap(array $array, array $map): array
45
    {
46 2
        return $this->renameKeys($array, static function ($key) use ($map) {
47 2
            return $map[$key] ?? $key;
48 2
        });
49
    }
50
51
    /**
52
     * Get the size of the longest text element of the array.
53
     *
54
     * @param  array  $array
55
     *
56
     * @return int
57
     */
58 2
    public function longestStringLength(array $array): int
59
    {
60 2
        return ! empty($array)
61 2
            ? max(array_map('mb_strlen', $array))
62 2
            : 0;
63
    }
64
65
    /**
66
     * Push one a unique element onto the end of array.
67
     *
68
     * @param  array  $array
69
     * @param  mixed  $values
70
     *
71
     * @return array
72
     */
73 2
    public function addUnique(array $array, $values): array
74
    {
75 2
        if ($this->isArrayable($values)) {
76 2
            foreach ($values as $value) {
77 2
                $array = $this->addUnique($array, $value);
78
            }
79
        } else {
80 2
            array_push($array, $values);
81
        }
82
83 2
        return array_values(array_unique($array));
84
    }
85
86
    /**
87
     * Sort an associative array in the order specified by an array of keys.
88
     *
89
     * Example:
90
     *
91
     *  $arr = ['q' => 1, 'r' => 2, 's' => 5, 'w' => 123];
92
     *
93
     *  Arr::sortByKeys($arr, ['q', 'w', 'e']);
94
     *
95
     * print_r($arr);
96
     *
97
     *   Array
98
     *   (
99
     *     [q] => 1
100
     *     [w] => 123
101
     *     [r] => 2
102
     *     [s] => 5
103
     *   )
104
     *
105
     * @see https://gist.github.com/Ellrion/a3145621f936aa9416f4c04987533d8d#file-helper-php
106
     *
107
     * @param  array  $array
108
     * @param  array  $sorter
109
     *
110
     * @return array
111
     */
112 2
    public function sortByKeys(array $array, array $sorter): array
113
    {
114 2
        $sorter = array_intersect($sorter, array_keys($array));
115 2
        $array  = array_merge(array_flip($sorter), $array);
116
117 2
        return $array;
118
    }
119
120
    /**
121
     * Recursively sorting an array by values.
122
     *
123
     * @param  array  $array
124
     * @param  callable|null  $callback
125
     *
126
     * @return array
127
     */
128 4
    public function sort(array $array, callable $callback = null): array
129
    {
130 4
        $callback = $callback ?: Sorter::defaultCallback();
131
132 4
        usort($array, $callback);
133
134 4
        foreach ($array as $key => &$value) {
135 4
            if (is_array($value)) {
136 4
                $value = $this->sort($value, $callback);
137
            }
138
        }
139
140 4
        return $array;
141
    }
142
143
    /**
144
     * Recursively sorting an array by keys.
145
     *
146
     * @param  array  $array
147
     * @param  callable|null  $callback
148
     *
149
     * @return array
150
     */
151 12
    public function ksort(array $array, callable $callback = null): array
152
    {
153 12
        $callback = $callback ?: Sorter::defaultCallback();
154
155 12
        uksort($array, $callback);
156
157 12
        foreach ($array as $key => &$value) {
158 12
            if (is_array($value)) {
159 6
                $value = $this->ksort($value, $callback);
160
            }
161
        }
162
163 12
        return $array;
164
    }
165
166
    /**
167
     * Merge one or more arrays recursively.
168
     * Don't forget that numeric keys NOT will be renumbered!
169
     *
170
     * @param  array[]  ...$arrays
171
     *
172
     * @return array
173
     */
174 2
    public function merge(...$arrays): array
175
    {
176 2
        $result = [];
177
178 2
        foreach ($arrays as $array) {
179 2
            foreach ($array as $key => $value) {
180 2
                if (is_array($value)) {
181 2
                    $value = $this->merge($result[$key] ?? [], $value);
182
                }
183
184 2
                $result[$key] = $value;
185
            }
186
        }
187
188 2
        return $this->ksort($result);
189
    }
190
191
    /**
192
     * If the given value is not an array and not null, wrap it in one.
193
     *
194
     * @param  mixed  $value
195
     *
196
     * @return array
197
     */
198 64
    public function wrap($value = null): array
199
    {
200 64
        if (is_array($value)) {
201 16
            return $value;
202
        }
203
204 58
        return ! empty($value) ? [$value] : [];
205
    }
206
207
    /**
208
     * Get the instance as an array.
209
     *
210
     * @param  mixed  $value
211
     *
212
     * @return array
213
     */
214 2
    public function toArray($value = null): array
215
    {
216 2
        if (is_object($value)) {
217 2
            $value = method_exists($value, 'toArray') ? $value->toArray() : get_object_vars($value);
218
        }
219
220 2
        $array = $this->wrap($value);
221
222 2
        foreach ($array as &$item) {
223 2
            $item = $this->isArrayable($item) ? $this->toArray($item) : $item;
224
        }
225
226 2
        return $array;
227
    }
228
229
    /**
230
     * Determine if the given key exists in the provided array.
231
     *
232
     * @param  array|\ArrayAccess  $array
233
     * @param  mixed  $key
234
     *
235
     * @return bool
236
     */
237 34
    public function exists($array, $key): bool
238
    {
239 34
        if ($array instanceof ArrayAccess) {
240 2
            return $array->offsetExists($key);
241
        }
242
243 34
        return isset($array[$key]);
244
    }
245
246
    /**
247
     * Get an item from an array.
248
     *
249
     * @param  array|ArrayAccess  $array
250
     * @param  mixed  $key
251
     * @param  mixed|null  $default
252
     *
253
     * @return mixed|null
254
     */
255 34
    public function get($array, $key, $default = null)
256
    {
257 34
        return $array[$key] ?? $default;
258
    }
259
260
    /**
261
     * If the element key exists, then return the name of the key, otherwise the default value.
262
     *
263
     * @param  array|ArrayAccess  $array
264
     * @param  mixed  $key
265
     * @param  mixed  $default
266
     *
267
     * @return mixed|null
268
     */
269 32
    public function getKey($array, $key, $default = null)
270
    {
271 32
        return $this->exists($array, $key) ? $key : $default;
272
    }
273
274
    /**
275
     * Get all of the given array except for a specified array of keys.
276
     *
277
     * @param  array|ArrayAccess  $array
278
     * @param  array|callable|string  $keys
279
     *
280
     * @return array
281
     */
282 4
    public function except($array, $keys): array
283
    {
284 4
        $callback = is_callable($keys)
285 2
            ? $keys
286 2
            : static function ($key) use ($keys) {
287 2
                return empty($keys) || ! in_array($key, (array) $keys);
288 4
            };
289
290 4
        return array_filter((array) $array, $callback, ARRAY_FILTER_USE_KEY);
291
    }
292
293
    /**
294
     * Get a subset of the items from the given array.
295
     *
296
     * @param  array|ArrayAccess  $array
297
     * @param  array|callable|string  $keys
298
     *
299
     * @return array
300
     */
301 4
    public function only($array, $keys): array
302
    {
303 4
        if (is_callable($keys)) {
304 2
            return array_filter($array, $keys, ARRAY_FILTER_USE_KEY);
0 ignored issues
show
Bug introduced by
It seems like $array can also be of type ArrayAccess; however, parameter $array of array_filter() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

304
            return array_filter(/** @scrutinizer ignore-type */ $array, $keys, ARRAY_FILTER_USE_KEY);
Loading history...
305
        }
306
307 2
        $result = [];
308
309 2
        foreach ((array) $keys as $index => $key) {
310 2
            if (is_array($key) && isset($array[$index])) {
311 2
                $result[$index] = $this->only($array[$index], $key);
312 2
            } elseif (isset($array[$key])) {
313 2
                $result[$key] = $array[$key];
314
            }
315
        }
316
317 2
        return $result;
318
    }
319
320
    /**
321
     * Flatten a multi-dimensional array into a single level.
322
     *
323
     * @param  array  $array
324
     *
325
     * @return array
326
     */
327 2
    public function flatten(array $array): array
328
    {
329 2
        $result = [];
330
331 2
        foreach ($array as $item) {
332 2
            if (! $this->isArrayable($item)) {
333 2
                $result[] = $item;
334
335 2
                continue;
336
            }
337
338 2
            $values = $this->flatten(array_values($item));
339
340 2
            $result = array_merge($result, $values);
341
        }
342
343 2
        return array_values($result);
344
    }
345
346
    /**
347
     * Applies the callback to the elements of the given arrays.
348
     *
349
     * @param  array|ArrayAccess  $array
350
     * @param  callable  $callback
351
     * @param  bool  $recursive
352
     *
353
     * @return array
354
     */
355 4
    public function map($array, callable $callback, bool $recursive = false): array
356
    {
357 4
        foreach ($array as $key => &$value) {
358 4
            if ($recursive && is_array($value)) {
359 2
                $value = $this->map($value, $callback, $recursive);
360
            } else {
361 4
                $value = is_array($value) ? $value : $callback($value, $key);
362
            }
363
        }
364
365 4
        return $array;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $array could return the type ArrayAccess which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
366
    }
367
368
    /**
369
     * Check if the item is an array.
370
     *
371
     * @param  mixed  $value
372
     *
373
     * @return bool
374
     */
375 8
    public function isArrayable($value = null): bool
376
    {
377 8
        return is_array($value) || is_object($value) || $value instanceof ArrayAccess;
378
    }
379
380
    /**
381
     * Determines if the array or arrayable object is empty.
382
     *
383
     * @param  mixed  $value
384
     *
385
     * @return bool
386
     */
387 8
    public function isEmpty($value): bool
388
    {
389 8
        $value = is_object($value) && method_exists($value, 'toArray') ? $value->toArray() : $value;
390 8
        $value = is_object($value) ? (array) $value : $value;
391
392 8
        return is_array($value) && empty($value);
393
    }
394
395
    /**
396
     * Determines if the value is doesn't empty.
397
     *
398
     * @param  mixed  $value
399
     *
400
     * @return bool
401
     */
402 2
    public function doesntEmpty($value): bool
403
    {
404 2
        return ! $this->isEmpty($value);
405
    }
406
407
    /**
408
     * Save array to php or json file.
409
     *
410
     * @param  array|ArrayAccess  $array
411
     * @param  string  $path
412
     * @param  bool  $is_json
413
     * @param  bool  $sort_keys
414
     * @param  int  $json_flags
415
     */
416 6
    public function store($array, string $path, bool $is_json = false, bool $sort_keys = false, int $json_flags = 0): void
417
    {
418 6
        $is_json
419 4
            ? $this->storeAsJson($path, $array, $sort_keys, $json_flags)
420 2
            : $this->storeAsArray($path, $array, $sort_keys);
421 6
    }
422
423
    /**
424
     * Save array to json file.
425
     *
426
     * @param  string  $path
427
     * @param  array|ArrayAccess  $array
428
     * @param  bool  $sort_keys
429
     * @param  int  $flags
430
     */
431 8
    public function storeAsJson(string $path, $array, bool $sort_keys = false, int $flags = 0): void
432
    {
433 8
        $this->prepareToStore($path, StubTool::JSON, $array, static function (array $array) use ($flags) {
0 ignored issues
show
Bug introduced by
It seems like $array can also be of type ArrayAccess; however, parameter $array of Helldar\Support\Helpers\Arr::prepareToStore() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

433
        $this->prepareToStore($path, StubTool::JSON, /** @scrutinizer ignore-type */ $array, static function (array $array) use ($flags) {
Loading history...
434 8
            return json_encode($array, $flags);
435 8
        }, $sort_keys);
436 8
    }
437
438
    /**
439
     * Save array to php file.
440
     *
441
     * @param  string  $path
442
     * @param  array|ArrayAccess  $array
443
     * @param  bool  $sort_keys
444
     */
445 4
    public function storeAsArray(string $path, $array, bool $sort_keys = false): void
446
    {
447 4
        $this->prepareToStore($path, StubTool::PHP_ARRAY, $array, static function (array $array) {
0 ignored issues
show
Bug introduced by
It seems like $array can also be of type ArrayAccess; however, parameter $array of Helldar\Support\Helpers\Arr::prepareToStore() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

447
        $this->prepareToStore($path, StubTool::PHP_ARRAY, /** @scrutinizer ignore-type */ $array, static function (array $array) {
Loading history...
448 4
            return var_export($array, true);
449 4
        }, $sort_keys);
450 4
    }
451
452
    /**
453
     * Prepare an array for writing to a file.
454
     *
455
     * @param  string  $path
456
     * @param  string  $stub
457
     * @param  array|ArrayAccess  $array
458
     * @param  callable  $replace
459
     * @param  bool  $sort_keys
460
     */
461 12
    protected function prepareToStore(string $path, string $stub, array $array, callable $replace, bool $sort_keys = false): void
462
    {
463 12
        $array = (array) $array;
464
465 12
        if ($sort_keys) {
466 6
            $this->ksort($array);
467
        }
468
469 12
        $content = Stub::replace($stub, [
470 12
            '{{slot}}' => $replace($array),
471
        ]);
472
473 12
        File::store($path, $content);
474 12
    }
475
}
476