GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#10)
by Chad
01:17
created

Arrays::copyIfKeysExist()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 12
Code Lines 6

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
dl 12
loc 12
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 5
nop 3
1
<?php
2
/**
3
 * Defines the \TraderInteractive\Util\Arrays class.
4
 */
5
6
namespace TraderInteractive\Util;
7
8
/**
9
 * Class of static array utility functions.
10
 */
11
final class Arrays
12
{
13
    /**
14
     * Const for lower cased array keys.
15
     *
16
     * @const integer
17
     */
18
    const CASE_LOWER = 1;
19
20
    /**
21
     * Const for upper cased array keys.
22
     *
23
     * @const integer
24
     */
25
    const CASE_UPPER = 2;
26
27
    /**
28
     * Const for camel caps cased array keys.
29
     *
30
     * @const integer
31
     */
32
    const CASE_CAMEL_CAPS = 4;
33
34
    /**
35
     * Const for underscored cased array keys.
36
     *
37
     * @const integer
38
     */
39
    const CASE_UNDERSCORE = 8;
40
41
    /**
42
     * Simply returns an array value if the key exist or null if it does not.
43
     *
44
     * @param array $array the array to be searched
45
     * @param string|integer $key the key to search for
46
     * @param mixed $default the value to return if the $key is not found in $array
47
     *
48
     * @return mixed array value or given default value
49
     */
50
    public static function get(array $array, $key, $default = null)
51
    {
52
        return array_key_exists($key, $array) ? $array[$key] : $default;
53
    }
54
55
    /**
56
     * Simply returns an array value if the key isset,4 $default if it is not
57
     *
58
     * @param array $array the array to be searched
59
     * @param string|integer $key the key to search for
60
     * @param mixed $default the value to return if the $key is not found in $array or if the value of $key element is
61
     *                       null
62
     *
63
     * @return mixed array value or given default value
64
     */
65
    public static function getIfSet(array $array, $key, $default = null)
66
    {
67
        return isset($array[$key]) ? $array[$key] : $default;
68
    }
69
70
    /**
71
     * Sets destination array values to be the source values if the source key exist in the source array.
72
     *
73
     * @param array $source
74
     * @param array &$dest
75
     * @param array $keyMap mapping of dest keys to source keys. If $keyMap is associative, the keys will be the
76
     *                      destination keys. If numeric the values will be the destination keys
77
     *
78
     * @return void
79
     */
80 View Code Duplication
    public static function copyIfKeysExist(array $source, array &$dest, array $keyMap)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
81
    {
82
        foreach ($keyMap as $destKey => $sourceKey) {
83
            if (is_int($destKey)) {
84
                $destKey = $sourceKey;
85
            }
86
87
            if (array_key_exists($sourceKey, $source)) {
88
                $dest[$destKey] = $source[$sourceKey];
89
            }
90
        }
91
    }
92
93
    /**
94
     * Sets destination array values to be the source values if the source key is set in the source array.
95
     *
96
     * @param array $source
97
     * @param array &$dest
98
     * @param array $keyMap mapping of dest keys to source keys. If $keyMap is associative, the keys will be the
99
     *                      destination keys. If numeric the values will be the destination keys
100
     *
101
     * @return void
102
     */
103 View Code Duplication
    public static function copyIfSet(array $source, array &$dest, array $keyMap)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
104
    {
105
        foreach ($keyMap as $destKey => $sourceKey) {
106
            if (is_int($destKey)) {
107
                $destKey = $sourceKey;
108
            }
109
110
            if (isset($source[$sourceKey])) {
111
                $dest[$destKey] = $source[$sourceKey];
112
            }
113
        }
114
    }
115
116
    /**
117
     * Returns true and fills $value if $key exists in $array, otherwise fills $value with null and returns false
118
     *
119
     * @param array $array The array to pull from
120
     * @param string|integer $key The key to get
121
     * @param mixed &$value The value to set
122
     *
123
     * @return bool true if $key was found and filled in $value, false if $key was not found and $value was set to null
124
     */
125
    public static function tryGet(array $array, $key, &$value) : bool
126
    {
127
        if ((is_string($key) || is_int($key)) && array_key_exists($key, $array)) {
128
            $value = $array[$key];
129
            return true;
130
        }
131
132
        $value = null;
133
        return false;
134
    }
135
136
    /**
137
     * Projects values of a key into an array.
138
     *
139
     * if $input = [
140
     *     ['key 1' => 'item 1 value 1', 'key 2' => 'item 1 value 2'],
141
     *     ['key 1' => 'item 2 value 1', 'key 2' => 'item 2 value 2'],
142
     *     ['key 1' => 'item 3 value 1'],
143
     * ]
144
     * and $key = 'key 2'
145
     * and $strictKeyCheck = false
146
     *
147
     * then return ['item 1 value 2', 'item 2 value 2']
148
     *
149
     * but if $strictKeyCheck = true then an InvalidArgumentException occurs since 'key 2' wasnt in item 3
150
     *
151
     * @param array $input the array to project from
152
     * @param string|integer $key the key which values we are to project
153
     * @param boolean $strictKeyCheck ensure key is in each $input array or not
154
     *
155
     * @return array the projection
156
     *
157
     * @throws \InvalidArgumentException if a value in $input was not an array
158
     * @throws \InvalidArgumentException if a key was not in one of the $input arrays
159
     */
160
    public static function project(array $input, $key, bool $strictKeyCheck = true) : array
161
    {
162
        $projection = [];
163
164
        foreach ($input as $itemKey => $item) {
165
            self::ensureIsArray($item, 'a value in $input was not an array');
166
167
            if (array_key_exists($key, $item)) {
168
                $projection[$itemKey] = $item[$key];
169
            } elseif ($strictKeyCheck) {
170
                throw new \InvalidArgumentException('key was not in one of the $input arrays');
171
            }
172
        }
173
174
        return $projection;
175
    }
176
177
    /**
178
     * Returns a sub set of the given $array based on the given $conditions
179
     *
180
     * @param array[] $array an array of arrays to be checked
181
     * @param array $conditions array of key/value pairs to filter by
182
     *
183
     * @return array the subset
184
     *
185
     * @throws \InvalidArgumentException if a value in $array was not an array
186
     */
187
    public static function where(array $array, array $conditions) : array
188
    {
189
        $result = [];
190
        foreach ($array as $item) {
191
            self::ensureIsArray($item, 'a value in $array was not an array');
192
193
            foreach ($conditions as $key => $value) {
194
                if (!array_key_exists($key, $item) || $item[$key] !== $value) {
195
                    continue 2; // continue to the next item in $array
196
                }
197
            }
198
199
            $result[] = $item;
200
        }
201
202
        return $result;
203
    }
204
205
    /**
206
     * Takes each item and embeds it into the destination array, returning the result.
207
     *
208
     * Each item's key is used as the key in the destination array so that keys are preserved.  Each resulting item in
209
     * the destination will be embedded into a field named by $fieldName.  Any items that don't have an entry in
210
     * destination already will be added, not skipped.
211
     *
212
     * For example, embedInto(['Joe', 'Sue'], 'lastName', [['firstName' => 'Billy'], ['firstName' => 'Bobby']]) will
213
     * return [['firstName' => 'Billy', 'lastName' => 'Joe'], ['firstName' => 'Bobby', 'lastName' => 'Sue']]
214
     *
215
     * @param array $items The items to embed into the result.
216
     * @param string $fieldName The name of the field to embed the items into.  This field must not exist in the
217
     *                          destination items already.
218
     * @param array $destination An optional array of arrays to embed the items into.  If this is not provided then
219
     *                           empty records are assumed and the new record will be created only containing
220
     *                           $fieldName.
221
     * @param bool $overwrite whether to overwrite $fieldName in $destination array
222
     *
223
     * @return array $destination, with all items in $items added using their keys, but underneath a nested $fieldName
224
     *               key.
225
     *
226
     * @throws \InvalidArgumentException if $fieldName was not a string
227
     * @throws \InvalidArgumentException if a value in $destination was not an array
228
     * @throws \Exception if $fieldName key already exists in a $destination array
229
     */
230
    public static function embedInto(
231
        array $items,
232
        string $fieldName,
233
        array $destination = [],
234
        bool $overwrite = false
235
    ) : array {
236
        foreach ($items as $key => $item) {
237
            if (!array_key_exists($key, $destination)) {
238
                $destination[$key] = [$fieldName => $item];
239
                continue;
240
            }
241
242
            self::ensureIsArray($destination[$key], 'a value in $destination was not an array');
243
244
            if (!$overwrite && array_key_exists($fieldName, $destination[$key])) {
245
                throw new \Exception('$fieldName key already exists in a $destination array');
246
            }
247
248
            $destination[$key][$fieldName] = $item;
249
        }
250
251
        return $destination;
252
    }
253
254
    /**
255
     * Fills the given $template array with values from the $source array
256
     *
257
     * @param array $template the array to be filled
258
     * @param array $source the array to fetch values from
259
     *
260
     * @return array Returns a filled version of $template
261
     */
262
    public static function fillIfKeysExist(array $template, array $source)
263
    {
264
        $result = $template;
265
        foreach ($template as $key => $value) {
266
            if (array_key_exists($key, $source)) {
267
                $result[$key] = $source[$key];
268
            }
269
        }
270
271
        return $result;
272
    }
273
274
    /**
275
     * Extracts an associative array from the given multi-dimensional array.
276
     *
277
     * @param array $input The multi-dimensional array.
278
     * @param string|int $keyIndex The index to be used as the key of the resulting single dimensional result array.
279
     * @param string|int $valueIndex The index to be used as the value of the resulting single dimensional result array.
280
     *                               If a sub array does not contain this element null will be used as the value.
281
     * @param string $duplicateBehavior Instruct how to handle duplicate resulting values, 'takeFirst', 'takeLast',
282
     *                                  'throw'
283
     *
284
     * @return array an associative array
285
     *
286
     * @throws \InvalidArgumentException Thrown if $input is not an multi-dimensional array
287
     * @throws \InvalidArgumentException Thrown if $keyIndex is not an int or string
288
     * @throws \InvalidArgumentException Thrown if $valueIndex is not an int or string
289
     * @throws \InvalidArgumentException Thrown if $duplicateBehavior is not 'takeFirst', 'takeLast', 'throw'
290
     * @throws \UnexpectedValueException Thrown if a $keyIndex value is not a string or integer
291
     * @throws \Exception Thrown if $duplicatedBehavior is 'throw' and duplicate entries are found.
292
     */
293
    public static function extract(
294
        array $input,
295
        $keyIndex,
296
        $valueIndex,
297
        string $duplicateBehavior = 'takeLast'
298
    ) : array {
299
        if (!in_array($duplicateBehavior, ['takeFirst', 'takeLast', 'throw'])) {
300
            throw new \InvalidArgumentException("\$duplicateBehavior was not 'takeFirst', 'takeLast', or 'throw'");
301
        }
302
303
        self::ensureValidKey($keyIndex, '$keyIndex was not a string or integer');
304
        self::ensureValidKey($valueIndex, '$valueIndex was not a string or integer');
305
306
        $result = [];
307
        foreach ($input as $index => $array) {
308
            self::ensureIsArray($array, '$arrays was not a multi-dimensional array');
309
310
            $key = self::get($array, $keyIndex);
311
            self::ensureValidKey(
312
                $key,
313
                "Value for \$arrays[{$index}][{$keyIndex}] was not a string or integer",
314
                '\\UnexpectedValueException'
315
            );
316
317
            $value = self::get($array, $valueIndex);
318
            if (!array_key_exists($key, $result)) {
319
                $result[$key] = $value;
320
                continue;
321
            }
322
323
            if ($duplicateBehavior === 'throw') {
324
                throw new \Exception("Duplicate entry for '{$key}' found.");
325
            }
326
327
            if ($duplicateBehavior === 'takeLast') {
328
                $result[$key] = $value;
329
            }
330
        }
331
332
        return $result;
333
    }
334
335
    /**
336
     * Returns the first set {@see isset()} value specified by the given array of keys.
337
     *
338
     * @param array $array The array containing the possible values.
339
     * @param array $keys Array of keys to search for. The first set value will be returned.
340
     * @param mixed $default The default value to return if no set value was found in the array.
341
     *
342
     * @return mixed Returns the found set value or the given default value.
343
     */
344
    public static function getFirstSet(array $array, array $keys, $default = null)
345
    {
346
        foreach ($keys as $key) {
347
            if (isset($array[$key])) {
348
                return $array[$key];
349
            }
350
        }
351
352
        return $default;
353
    }
354
355
    /**
356
     * Partitions the given $input array into an array of $partitionCount sub arrays.
357
     *
358
     * This is a slight modification of the function suggested on
359
     * http://php.net/manual/en/function.array-chunk.php#75022. This method does not pad with empty partitions and
360
     * ensures positive partition count.
361
     *
362
     * @param array $input The array to partition.
363
     * @param int $partitionCount The maximum number of partitions to create.
364
     * @param bool $preserveKeys Flag to preserve numeric array indexes. Associative indexes are preserved by default.
365
     *
366
     * @return array A multi-dimensional array containing $partitionCount sub arrays.
367
     *
368
     * @throws \InvalidArgumentException Thrown if $partitionCount is not a positive integer.
369
     * @throws \InvalidArgumentException Thrown if $preserveKeys is not a boolean value.
370
     */
371
    public static function partition(array $input, int $partitionCount, bool $preserveKeys = false) : array
372
    {
373
        if ($partitionCount < 1) {
374
            throw new \InvalidArgumentException('$partitionCount must be a positive integer');
375
        }
376
377
        $inputLength = count($input);
378
        $partitionLength = floor($inputLength / $partitionCount);
379
        $partitionRemainder = $inputLength % $partitionCount;
380
        $partitions = [];
381
        $sliceOffset = 0;
382
        for ($partitionIndex = 0; $partitionIndex < $partitionCount && $sliceOffset < $inputLength; $partitionIndex++) {
383
            $sliceLength = ($partitionIndex < $partitionRemainder) ? $partitionLength + 1 : $partitionLength;
384
            $partitions[$partitionIndex] = array_slice($input, $sliceOffset, $sliceLength, $preserveKeys);
385
            $sliceOffset += $sliceLength;
386
        }
387
388
        return $partitions;
389
    }
390
391
    /**
392
     * Unsets all elements in the given $array specified by $keys
393
     *
394
     * @param array &$array The array containing the elements to unset.
395
     * @param array $keys Array of keys to unset.
396
     *
397
     * @return void
398
     */
399
    public static function unsetAll(array &$array, array $keys)
400
    {
401
        foreach ($keys as $key) {
402
            unset($array[$key]);
403
        }
404
    }
405
406
    /**
407
     * Convert all empty strings or strings that contain only whitespace to null in the given array
408
     *
409
     * @param array &$array The array containing empty strings
410
     *
411
     * @return void
412
     */
413
    public static function nullifyEmptyStrings(array &$array)
414
    {
415
        foreach ($array as &$value) {
416
            if (is_string($value) && trim($value) === '') {
417
                $value = null;
418
            }
419
        }
420
    }
421
422
    /**
423
     * Traverses the given $array using the key path specified by $delimitedKey and returns the final value.
424
     *
425
     * Example:
426
     * <br />
427
     * <pre>
428
     * use TraderInteractive\Util\Arrays;
429
     * $array = [
430
     *     'db' => [
431
     *         'host' => 'localhost',
432
     *         'login' => [
433
     *             'username' => 'scott',
434
     *             'password' => 'tiger',
435
     *         ],
436
     *     ],
437
     * ];
438
     * echo Arrays::getNested($array, 'db.login.username');
439
     * </pre>
440
     * <br />
441
     * Output:
442
     * <pre>
443
     * scott
444
     * </pre>
445
     *
446
     * @param array  $array        The array to traverse.
447
     * @param string $delimitedKey A string of keys to traverse into the array.
448
     * @param string $delimiter    A string specifiying how the keys are delimited. The default is '.'.
449
     *
450
     * @return mixed The value at the inner most key or null if a key does not exist.
451
     */
452
    final public static function getNested(array $array, string $delimitedKey, string $delimiter = '.')
453
    {
454
        $pointer = $array;
455
        foreach (explode($delimiter, $delimitedKey) as $key) {
456
            if (is_array($pointer) && array_key_exists($key, $pointer)) {
457
                $pointer = $pointer[$key];
458
                continue;
459
            }
460
461
            return null;
462
        }
463
464
        return $pointer;
465
    }
466
467
    /**
468
     * Changes the case of all keys in an array. Numbered indices are left as is.
469
     *
470
     * @param array   $input The array to work on.
471
     * @param integer $case  The case to which the keys should be set.
472
     *
473
     * @return array Returns an array with its keys case changed.
474
     */
475
    public static function changeKeyCase(array $input, int $case = self::CASE_LOWER) : array
476
    {
477
        if ($case & self::CASE_UNDERSCORE) {
478
            $copy = [];
479
            foreach ($input as $key => $value) {
480
                $copy[preg_replace("/([a-z])([A-Z0-9])/", '$1_$2', $key)] = $value;
481
            }
482
483
            $input = $copy;
484
        }
485
486
        if ($case & self::CASE_CAMEL_CAPS) {
487
            $copy = [];
488
            foreach ($input as $key => $value) {
489
                $key = implode(' ', array_filter(preg_split('/[^a-z0-9]/i', $key)));
490
                $key = lcfirst(str_replace(' ', '', ucwords(strtolower($key))));
491
                $copy[$key] = $value;
492
            }
493
494
            $input = $copy;
495
        }
496
497
        unset($copy); //gc
498
499
        if ($case & self::CASE_UPPER) {
500
            $input = array_change_key_case($input, \CASE_UPPER);
501
        }
502
503
        if ($case & self::CASE_LOWER) {
504
            $input = array_change_key_case($input, \CASE_LOWER);
505
        }
506
507
        return $input;
508
    }
509
510
    /**
511
     * Converts a multi-dimensional array into a single associative array whose keys are the concatinated keys
512
     *
513
     * @param array  $input     The array to flatten
514
     * @param string $delimiter The separator for the concatinated keys.
515
     *
516
     * @return array The flattened array
517
     */
518
    final public static function flatten(array $input, string $delimiter = '.') : array
519
    {
520
        $args = func_get_args();
521
        $prefix = count($args) === 3 ? array_pop($args) : '';
522
        $result = [];
523
        foreach ($input as $key => $value) {
524
            $newKey = $prefix . (empty($prefix) ? '' : $delimiter) . $key;
525
            if (is_array($value)) {
526
                $result = array_merge($result, self::flatten($value, $delimiter, $newKey));
527
                continue;
528
            }
529
530
            $result[$newKey] = $value;
531
        }
532
533
        return $result;
534
    }
535
536
    /**
537
     * Returns all elements in the given $input array which contain the specifed $targetKey index.
538
     *
539
     * @param array          $input     The multi-dimensional array to check.
540
     * @param string|integer $targetKey The key to search for.
541
     *
542
     * @return array All elements of $input which contained $targetKey element with original keys preserved.
543
     */
544
    final public static function getAllWhereKeyExists(array $input, $targetKey) : array
545
    {
546
        $result = [];
547
        foreach ($input as $key => $value) {
548
            if (array_key_exists($targetKey, $value)) {
549
                $result[$key] = $value;
550
            }
551
        }
552
553
        return $result;
554
    }
555
556
    private static function ensureValidKey(
557
        $key,
558
        string $message,
559
        string $exceptionClass = '\\InvalidArgumentException'
560
    ) {
561
        if (!is_string($key) && !is_int($key)) {
562
            $reflectionClass = new \ReflectionClass($exceptionClass);
563
            throw $reflectionClass->newInstanceArgs([$message]);
564
        }
565
    }
566
567
    private static function ensureIsArray(
568
        $value,
569
        string $message,
570
        string $exceptionClass = '\\InvalidArgumentException'
571
    ) {
572
        if (!is_array($value)) {
573
            $reflectionClass = new \ReflectionClass($exceptionClass);
574
            throw $reflectionClass->newInstanceArgs([$message]);
575
        }
576
    }
577
}
578