Passed
Pull Request — main (#88)
by Andrey
15:31 queued 02:24
created

Arr::ksort()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

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

277
            return array_filter(/** @scrutinizer ignore-type */ $array, $keys, ARRAY_FILTER_USE_KEY);
Loading history...
278
        }
279
280
        $result = [];
281
282
        foreach ((array) $keys as $index => $key) {
283 2
            if (is_array($key) && isset($array[$index])) {
284
                $result[$index] = $this->only($array[$index], $key);
285 2
            } elseif (isset($array[$key])) {
286 2
                $result[$key] = $array[$key];
287
            }
288
        }
289 2
290
        return $result;
291
    }
292
293
    /**
294
     * Applies the callback to the elements of the given arrays.
295
     *
296
     * @param  array|ArrayAccess  $array
297
     * @param  callable  $callback
298
     *
299 6
     * @return array
300
     */
301 6
    public function map($array, callable $callback): array
302
    {
303
        foreach ($array as $key => &$value) {
304
            $value = $callback($value, $key);
305
        }
306
307
        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...
308
    }
309
310
    /**
311 8
     * Check if the item is an array.
312
     *
313 8
     * @param  mixed  $value
314 8
     *
315
     * @return bool
316 8
     */
317
    public function isArrayable($value = null): bool
318
    {
319
        return is_array($value) || is_object($value) || $value instanceof ArrayAccess;
320
    }
321
322
    /**
323
     * Determines if the array or arrayable object is empty.
324
     *
325
     * @param  mixed  $value
326 2
     *
327
     * @return bool
328 2
     */
329
    public function isEmpty($value): bool
330
    {
331
        $value = is_object($value) && method_exists($value, 'toArray') ? $value->toArray() : $value;
332
        $value = is_object($value) ? (array) $value : $value;
333
334
        return is_array($value) && empty($value);
335
    }
336
337
    /**
338
     * Determines if the value is doesn't empty.
339
     *
340 6
     * @param  mixed  $value
341
     *
342 6
     * @return bool
343 4
     */
344 2
    public function doesntEmpty($value): bool
345 6
    {
346
        return ! $this->isEmpty($value);
347
    }
348
349
    /**
350
     * Save array to php or json file.
351
     *
352
     * @param  array|ArrayAccess  $array
353
     * @param  string  $path
354
     * @param  bool  $is_json
355 8
     * @param  bool  $sort_keys
356
     * @param  int  $json_flags
357 8
     */
358 8
    public function store($array, string $path, bool $is_json = false, bool $sort_keys = false, int $json_flags = 0): void
359 8
    {
360 8
        $is_json
361
            ? $this->storeAsJson($path, $array, $sort_keys, $json_flags)
362
            : $this->storeAsArray($path, $array, $sort_keys);
363
    }
364
365
    /**
366
     * Save array to json file.
367
     *
368
     * @param  string  $path
369 4
     * @param  array|ArrayAccess  $array
370
     * @param  bool  $sort_keys
371 4
     * @param  int  $flags
372 4
     */
373 4
    public function storeAsJson(string $path, $array, bool $sort_keys = false, int $flags = 0): void
374 4
    {
375
        $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

375
        $this->prepareToStore($path, StubTool::JSON, /** @scrutinizer ignore-type */ $array, static function (array $array) use ($flags) {
Loading history...
376
            return json_encode($array, $flags);
377
        }, $sort_keys);
378
    }
379
380
    /**
381
     * Save array to php file.
382
     *
383
     * @param  string  $path
384
     * @param  array|ArrayAccess  $array
385 12
     * @param  bool  $sort_keys
386
     */
387 12
    public function storeAsArray(string $path, $array, bool $sort_keys = false): void
388
    {
389 12
        $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

389
        $this->prepareToStore($path, StubTool::PHP_ARRAY, /** @scrutinizer ignore-type */ $array, static function (array $array) {
Loading history...
390 6
            return var_export($array, true);
391
        }, $sort_keys);
392
    }
393 12
394 12
    /**
395
     * Prepare an array for writing to a file.
396
     *
397 12
     * @param  string  $path
398 12
     * @param  string  $stub
399
     * @param  array|ArrayAccess  $array
400
     * @param  callable  $replace
401
     * @param  bool  $sort_keys
402
     */
403
    protected function prepareToStore(string $path, string $stub, array $array, callable $replace, bool $sort_keys = false): void
404
    {
405 6
        $array = (array) $array;
406
407 6
        if ($sort_keys) {
408
            $this->ksort($array);
409 6
        }
410 6
411
        $content = Stub::replace($stub, [
412
            '{{slot}}' => $replace($array),
413
        ]);
414 6
415
        File::store($path, $content);
416
    }
417
}
418