ArrayManipulations::setArrayValueByKeys()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 4
nop 3
dl 0
loc 13
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace alkemann\h2l\util;
4
5
use OutOfBoundsException;
6
use InvalidArgumentException;
7
8
/**
9
 * Class Util
10
 *
11
 * @package alkemann\h2l
12
 */
13
class ArrayManipulations
14
{
15
    /**
16
     * Look for a deeo value in a nested data array.
17
     *
18
     * Given $data = ['one' => ['two' => ['three' => 55]], 'four' => []];
19
     *
20
     * ```php
21
     *  getFromArrayByKey('one.two.three', $data) -> 55
22
     *  getFromArrayByKey('one|two', $data, '|') -> ['three' => 55]
23
     *  getFromArrayByKey('four.five', $data) -> throws OutOfBoundsException
24
     * ```
25
     *
26
     * @param string $key
27
     * @param array<string, mixed> $data
28
     * @param string $delimiter
29
     * @return mixed|null
30
     * @throws InvalidArgumentException if $delimiter is empty string
31
     */
32
    public static function getFromArrayByKey(string $key, array $data, string $delimiter = '.')
33
    {
34
        if ($delimiter === '') {
35
            throw new InvalidArgumentException("Delimiter can't be empty string");
36
        }
37
        $keys = explode($delimiter, $key);
38
        try {
39
            return self::getArrayValueByKeys($keys, $data);
40
        } catch (\OutOfBoundsException $e) {
41
            return null;
42
        }
43
    }
44
45
    /**
46
     * Look for a deep value in a data array.
47
     *
48
     * Given $data = ['one' => ['two' => ['three' => 55]], 'four' => []];
49
     *
50
     * ```php
51
     *  getArrayValueByKeys(['one','two','three'], $data) will return 55
52
     *  getArrayValueByKeys(['four','five'], $data) will throw OutOfBoundsException
53
     * ```
54
     *
55
     * @param  array<string> $keys
56
     * @param  mixed $data passed by reference
57
     * @return mixed
58
     * @throws OutOfBoundsException if the key does not exist in data
59
     */
60
    public static function getArrayValueByKeys(array $keys, &$data)
61
    {
62
        $key = array_shift($keys);
63
        if (!is_array($data) || empty($key)) {
64
            return $data;
65
        }
66
        if (array_key_exists($key, $data) === false) {
67
            throw new OutOfBoundsException("Key [{$key}." . join('.', $keys) . "] not set in " . print_r($data, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($data, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

67
            throw new OutOfBoundsException("Key [{$key}." . join('.', $keys) . "] not set in " . /** @scrutinizer ignore-type */ print_r($data, true));
Loading history...
68
        }
69
        if (empty($keys)) {
70
            return $data[$key];
71
        } else {
72
            return self::getArrayValueByKeys($keys, $data[$key]);
73
        }
74
    }
75
76
    /**
77
     * Update or Insert a value in a nested array by "dot" notation string
78
     *
79
     * Given $data = ['one' => ['two' => ['three' => 55]], 'four' => []];
80
     *
81
     * ```php
82
     *  setToArrayByKey('one.two.three', 42, $data) // will replace 55 with 42
83
     *  setToArrayByKey('one.two.five', 42, $data) // will add a second key in the 'two' array
84
     * ```
85
     *
86
     * @param string $key
87
     * @param mixed $value the value to assign
88
     * @param array<string, mixed> $data The array to update
89
     * @param string $delimiter defaults to `.`
90
     * @throws InvalidArgumentException if $delimiter is empty string
91
     */
92
    public static function setToArrayByKey(string $key, $value, array &$data, string $delimiter = '.'): void
93
    {
94
        if ($delimiter === '') {
95
            throw new InvalidArgumentException("Delimiter can't be empty string");
96
        }
97
        $keys = explode($delimiter, $key);
98
        self::setArrayValueByKeys($keys, $value, $data);
99
    }
100
101
    /**
102
     * Update or Insert value in a nested array
103
     *
104
     * @param array<string> $keys
105
     * @param mixed $value
106
     * @param mixed $data passed by reference
107
     */
108
    public static function setArrayValueByKeys(array $keys, $value, &$data): void
109
    {
110
        $key = array_shift($keys);
111
        if (is_null($key)) {
112
            throw new InvalidArgumentException("At least one key is required");
113
        }
114
        if (empty($keys)) {
115
            $data[$key] = $value;
116
        } else {
117
            if (array_key_exists($key, $data) === false) {
118
                $data[$key] = [];
119
            }
120
            self::setArrayValueByKeys($keys, $value, $data[$key]);
121
        }
122
    }
123
}
124