Completed
Push — master ( c248d9...d97e55 )
by Maxim
07:18
created

ArrayHelper   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 188
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
c 1
b 0
f 0
dl 0
loc 188
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
B setValue() 0 21 6
C getValue() 0 34 12
C merge() 0 22 8
1
<?php
2
3
namespace WebComplete\core\utils\helpers;
4
5
class ArrayHelper
6
{
7
8
    /**
9
     * Retrieves the value of an array element or object property with the given key or property name.
10
     * If the key does not exist in the array or object, the default value will be returned instead.
11
     *
12
     * The key may be specified in a dot format to retrieve the value of a sub-array or the property
13
     * of an embedded object. In particular, if the key is `x.y.z`, then the returned value would
14
     * be `$array['x']['y']['z']` or `$array->x->y->z` (if `$array` is an object). If `$array['x']`
15
     * or `$array->x` is neither an array nor an object, the default value will be returned.
16
     * Note that if the array already has an element `x.y.z`, then its value will be returned
17
     * instead of going through the sub-arrays. So it is better to be done specifying an array of key names
18
     * like `['x', 'y', 'z']`.
19
     *
20
     * Below are some usage examples,
21
     *
22
     * ```php
23
     * // working with array
24
     * $username = \yii\helpers\ArrayHelper::getValue($_POST, 'username');
25
     * // working with object
26
     * $username = \yii\helpers\ArrayHelper::getValue($user, 'username');
27
     * // working with anonymous function
28
     * $fullName = \yii\helpers\ArrayHelper::getValue($user, function ($user, $defaultValue) {
29
     *     return $user->firstName . ' ' . $user->lastName;
30
     * });
31
     * // using dot format to retrieve the property of embedded object
32
     * $street = \yii\helpers\ArrayHelper::getValue($users, 'address.street');
33
     * // using an array of keys to retrieve the value
34
     * $value = \yii\helpers\ArrayHelper::getValue($versions, ['1.0', 'date']);
35
     * ```
36
     *
37
     * @param array|object $array array or object to extract value from
38
     * @param string|\Closure|array $key key name of the array element, an array of keys or property name of the object,
39
     * or an anonymous function returning the value. The anonymous function signature should be:
40
     * `function($array, $defaultValue)`.
41
     * The possibility to pass an array of keys is available since version 2.0.4.
42
     * @param mixed $default the default value to be returned if the specified array key does not exist. Not used when
43
     * getting value from an object.
44
     * @return mixed the value of the element if found, default value otherwise
45
     */
46
    public function getValue(array $array, $key, $default = null)
47
    {
48
        if ($key instanceof \Closure) {
49
            return $key($array, $default);
50
        }
51
52
        if (\is_array($key)) {
53
            $lastKey = \array_pop($key);
54
            foreach ((array)$key as $keyPart) {
55
                $array = $this->getValue($array, $keyPart);
56
            }
57
            $key = $lastKey;
58
        }
59
60
        if (\is_array($array) && (isset($array[$key]) || \array_key_exists($key, $array))) {
61
            return $array[$key];
62
        }
63
64
        if (($pos = \strrpos($key, '.')) !== false) {
65
            $array = $this->getValue($array, \substr($key, 0, $pos), $default);
66
            $key = (string)\substr($key, $pos + 1);
67
        }
68
69
        if (\is_object($array)) {
70
            // this is expected to fail if the property does not exist, or __get() is not implemented
71
            // it is not reliably possible to check whether a property is accessible beforehand
72
            return $array->$key;
73
        }
74
75
        if (\is_array($array)) {
76
            return (isset($array[$key]) || \array_key_exists($key, $array)) ? $array[$key] : $default;
77
        }
78
79
        return $default;
80
    }
81
82
    /**
83
     * Writes a value into an associative array at the key path specified.
84
     * If there is no such key path yet, it will be created recursively.
85
     * If the key exists, it will be overwritten.
86
     *
87
     * ```php
88
     *  $array = [
89
     *      'key' => [
90
     *          'in' => [
91
     *              'val1',
92
     *              'key' => 'val'
93
     *          ]
94
     *      ]
95
     *  ];
96
     * ```
97
     *
98
     * The result of `ArrayHelper::setValue($array, 'key.in.0', ['arr' => 'val']);` will be the following:
99
     *
100
     * ```php
101
     *  [
102
     *      'key' => [
103
     *          'in' => [
104
     *              ['arr' => 'val'],
105
     *              'key' => 'val'
106
     *          ]
107
     *      ]
108
     *  ]
109
     *
110
     * ```
111
     *
112
     * The result of
113
     * `ArrayHelper::setValue($array, 'key.in', ['arr' => 'val']);` or
114
     * `ArrayHelper::setValue($array, ['key', 'in'], ['arr' => 'val']);`
115
     * will be the following:
116
     *
117
     * ```php
118
     *  [
119
     *      'key' => [
120
     *          'in' => [
121
     *              'arr' => 'val'
122
     *          ]
123
     *      ]
124
     *  ]
125
     * ```
126
     *
127
     * @param array $array the array to write the value to
128
     * @param string|array|null $path the path of where do you want to write a value to `$array`
129
     * the path can be described by a string when each key should be separated by a dot
130
     * you can also describe the path as an array of keys
131
     * if the path is null then `$array` will be assigned the `$value`
132
     * @param mixed $value the value to be written
133
     * @since 2.0.13
134
     */
135
    public function setValue(array &$array, $path, $value)
136
    {
137
        if ($path === null) {
138
            $array = $value;
139
            return;
140
        }
141
142
        $keys = \is_array($path) ? $path : \explode('.', $path);
143
144
        while (\count($keys) > 1) {
145
            $key = \array_shift($keys);
146
            if (!isset($array[$key])) {
147
                $array[$key] = [];
148
            }
149
            if (!\is_array($array[$key])) {
150
                $array[$key] = [$array[$key]];
151
            }
152
            $array = &$array[$key];
153
        }
154
155
        $array[\array_shift($keys)] = $value;
156
    }
157
158
    /**
159
     * Merges two or more arrays into one recursively.
160
     * If each array has an element with the same string key value, the latter
161
     * will overwrite the former (different from array_merge_recursive).
162
     * Recursive merging will be conducted if both arrays have an element of array
163
     * type and are having the same key.
164
     * For integer-keyed elements, the elements from the latter array will
165
     * be appended to the former array.
166
     * @param array $array1 array to be merged to
167
     * @param array $array2 array to be merged from. You can specify additional
168
     * arrays via third argument, fourth argument etc.
169
     * @return array the merged array (the original arrays are not changed.)
170
     */
171
    public function merge(array $array1, array $array2)
172
    {
173
        $args = \func_get_args();
174
        $result = \array_shift($args);
175
        while (!empty($args)) {
176
            $next = \array_shift($args);
177
            foreach ((array)$next as $k => $v) {
178
                if (\is_int($k)) {
179
                    if (\array_key_exists($k, $result)) {
180
                        $result[] = $v;
181
                    } else {
182
                        $result[$k] = $v;
183
                    }
184
                } elseif (\is_array($v) && isset($result[$k]) && \is_array($result[$k])) {
185
                    $result[$k] = $this->merge($result[$k], $v);
186
                } else {
187
                    $result[$k] = $v;
188
                }
189
            }
190
        }
191
192
        return $result;
193
    }
194
}
195