Passed
Push — main ( e0e27b...94cbb9 )
by Andrey
10:24 queued 08:24
created

Arr::set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

347
        return array_filter(/** @scrutinizer ignore-type */ $array, $callback, $mode);
Loading history...
348
    }
349
350
    /**
351
     * Return all the values of an array.
352
     *
353
     * @see  https://php.net/manual/en/function.array-values.php
354
     *
355
     * @param  mixed  $array
356
     *
357
     * @return array
358
     */
359 6
    public function values($array): array
360
    {
361 6
        return array_values($this->toArray($array));
362
    }
363
364
    /**
365
     * Flatten a multi-dimensional array into a single level.
366
     *
367
     * @param  array  $array
368
     * @param  bool  $ignore_keys
369
     *
370
     * @return array
371
     */
372 10
    public function flatten(array $array, bool $ignore_keys = true): array
373
    {
374 10
        $result = [];
375
376 10
        foreach ($array as $key => $item) {
377 10
            if (! $this->isArrayable($item)) {
378 10
                $ignore_keys
379 4
                    ? $result[]     = $item
380 6
                    : $result[$key] = $item;
381
382 10
                continue;
383
            }
384
385 10
            $flatten = $this->flatten($item, $ignore_keys);
386
387 10
            $values = $ignore_keys ? array_values($flatten) : $flatten;
388
389 10
            $result = array_merge($result, $values);
390
        }
391
392 10
        return $ignore_keys ? array_values($result) : $result;
393
    }
394
395
    /**
396
     * Applies the callback to the elements of the given arrays.
397
     *
398
     * @param  array|ArrayAccess  $array
399
     * @param  callable  $callback
400
     * @param  bool  $recursive
401
     *
402
     * @return array
403
     */
404 10
    public function map($array, callable $callback, bool $recursive = false): array
405
    {
406 10
        foreach ($array as $key => &$value) {
407 10
            if ($recursive && is_array($value)) {
408 4
                $value = $this->map($value, $callback, $recursive);
409
            } else {
410 10
                $value = is_array($value) ? $value : $callback($value, $key);
411
            }
412
        }
413
414 10
        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...
415
    }
416
417
    /**
418
     * Push elements onto the end of array.
419
     *
420
     * @see  https://php.net/manual/en/function.array-push.php
421
     *
422
     * @param  array|ArrayAccess  $array
423
     * @param  mixed  ...$values
424
     *
425
     * @return array
426
     */
427 6
    public function push($array, ...$values): array
428
    {
429 6
        foreach ($values as $value) {
430 6
            array_push($array, $value);
431
        }
432
433 6
        return $array;
434
    }
435
436
    /**
437
     * Assigns a value to an array key.
438
     *
439
     * @param  array|ArrayAccess  $array
440
     * @param  mixed  $key
441
     * @param  mixed  $value
442
     *
443
     * @return array
444
     */
445 6
    public function set($array, $key, $value): array
446
    {
447 6
        $array[$key] = $value;
448
449 6
        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...
450
    }
451
452
    /**
453
     * Removes an array key.
454
     *
455
     * @param  array|ArrayAccess  $array
456
     * @param  mixed  $key
457
     *
458
     * @return array
459
     */
460 6
    public function remove($array, $key): array
461
    {
462 6
        unset($array[$key]);
463
464 6
        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...
465
    }
466
467
    /**
468
     * Check if the item is an array.
469
     *
470
     * @param  mixed  $value
471
     *
472
     * @return bool
473
     */
474 24
    public function isArrayable($value = null): bool
475
    {
476 24
        return is_array($value) || is_object($value) || $value instanceof ArrayAccess;
477
    }
478
479
    /**
480
     * Determines if the array or arrayable object is empty.
481
     *
482
     * @param  mixed  $value
483
     *
484
     * @return bool
485
     */
486 8
    public function isEmpty($value): bool
487
    {
488 8
        $value = is_object($value) && method_exists($value, 'toArray') ? $value->toArray() : $value;
489 8
        $value = is_object($value) ? (array) $value : $value;
490
491 8
        return is_array($value) && empty($value);
492
    }
493
494
    /**
495
     * Determines if the value is doesn't empty.
496
     *
497
     * @param  mixed  $value
498
     *
499
     * @return bool
500
     */
501 2
    public function doesntEmpty($value): bool
502
    {
503 2
        return ! $this->isEmpty($value);
504
    }
505
506
    /**
507
     * Save array to php or json file.
508
     *
509
     * @param  array|ArrayAccess  $array
510
     * @param  string  $path
511
     * @param  bool  $is_json
512
     * @param  bool  $sort_keys
513
     * @param  int  $json_flags
514
     */
515 6
    public function store($array, string $path, bool $is_json = false, bool $sort_keys = false, int $json_flags = 0): void
516
    {
517 6
        $is_json
518 4
            ? $this->storeAsJson($path, $array, $sort_keys, $json_flags)
519 2
            : $this->storeAsArray($path, $array, $sort_keys);
520 6
    }
521
522
    /**
523
     * Save array to json file.
524
     *
525
     * @param  string  $path
526
     * @param  array|ArrayAccess  $array
527
     * @param  bool  $sort_keys
528
     * @param  int  $flags
529
     */
530 8
    public function storeAsJson(string $path, $array, bool $sort_keys = false, int $flags = 0): void
531
    {
532 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

532
        $this->prepareToStore($path, StubTool::JSON, /** @scrutinizer ignore-type */ $array, static function (array $array) use ($flags) {
Loading history...
533 8
            return json_encode($array, $flags);
534 8
        }, $sort_keys);
535 8
    }
536
537
    /**
538
     * Save array to php file.
539
     *
540
     * @param  string  $path
541
     * @param  array|ArrayAccess  $array
542
     * @param  bool  $sort_keys
543
     */
544 4
    public function storeAsArray(string $path, $array, bool $sort_keys = false): void
545
    {
546 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

546
        $this->prepareToStore($path, StubTool::PHP_ARRAY, /** @scrutinizer ignore-type */ $array, static function (array $array) {
Loading history...
547 4
            return var_export($array, true);
548 4
        }, $sort_keys);
549 4
    }
550
551
    /**
552
     * Prepare an array for writing to a file.
553
     *
554
     * @param  string  $path
555
     * @param  string  $stub
556
     * @param  array|ArrayAccess  $array
557
     * @param  callable  $replace
558
     * @param  bool  $sort_keys
559
     */
560 12
    protected function prepareToStore(string $path, string $stub, array $array, callable $replace, bool $sort_keys = false): void
561
    {
562 12
        $array = (array) $array;
563
564 12
        if ($sort_keys) {
565 6
            $this->ksort($array);
566
        }
567
568 12
        $content = Stub::replace($stub, [
569 12
            '{{slot}}' => $replace($array),
570
        ]);
571
572 12
        File::store($path, $content);
573 12
    }
574
}
575