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
Push — master ( 50fc5e...938d51 )
by Chad
14s queued 11s
created

Arrays::anyKeysExist()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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