Passed
Push — master ( bf0683...f36612 )
by Radu
02:26
created

ArrayStorage::add()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 15
rs 9.6111
cc 5
nc 4
nop 3
1
<?php
2
namespace WebServCo\Framework;
3
4
use WebServCo\Framework\Exceptions\ArrayStorageException;
5
6
final class ArrayStorage
7
{
8
    /**
9
     * Parse the setting key to make sure it's a simple string
10
     * or an array.
11
     */
12
    private static function parseSetting($setting)
13
    {
14
        if (is_string($setting) &&
15
        false !== strpos($setting, \WebServCo\Framework\Settings::DIVIDER)) {
16
            return explode(\WebServCo\Framework\Settings::DIVIDER, $setting);
17
        }
18
        return $setting;
19
    }
20
21
    /**
22
     * Retrieve a value from a storage array.
23
     *
24
     * @param mixed $storage
25
     * @param mixed $setting Can be an array, a string,
26
     *                          or a special formatted string
27
     *                          (eg 'app/path/project').
28
     * @param mixed $defaultValue
29
     * @return mixed
30
     */
31
    public static function get($storage, $setting = null, $defaultValue = false)
32
    {
33
        $setting = self::parseSetting($setting);
34
35
        if (!isset($setting) || is_bool($setting) || empty($storage)) {
36
            // use "!isset" for `$setting` and not "empty" (can be 0)
37
            // `is_bool` check: handle wrong $setting type
38
            //     prevents: "array_key_exists(): The first argument should be either a string or an integer"
39
            return $defaultValue;
40
        }
41
42
        if (!is_array($storage)) {
43
            return $defaultValue;
44
        }
45
46
        /**
47
         * If $setting is an array, process it recursively.
48
         */
49
        if (is_array($setting)) {
50
            /**
51
             * Check if we have the first $setting element in the
52
             * configuration data array.
53
             */
54
            if (array_key_exists(0, $setting) && array_key_exists($setting[0], $storage)) {
55
                /**
56
                 * Remove first element from $setting.
57
                 */
58
                $key = array_shift($setting);
59
                /**
60
                 * At the end of the recursion $setting will be
61
                 * an empty array. In this case we simply return the
62
                 * current configuration data.
63
                 */
64
                if (empty($setting)) {
65
                    return false !== $storage[$key] ? $storage[$key] : $defaultValue;
66
                }
67
                /**
68
                 * Go down one element in the configuration data
69
                 * and call the method again, with the remainig setting.
70
                 */
71
                return self::get($storage[$key], $setting, $defaultValue);
72
            }
73
            /**
74
             * The requested setting doesn't exist in our
75
             * configuration data array.
76
             */
77
            return $defaultValue;
78
        }
79
80
        /**
81
         * If we arrive here, $setting must be a simple string.
82
         */
83
        if (array_key_exists($setting, $storage)) {
84
            return $storage[$setting];
85
        }
86
87
        /**
88
         * If we got this far, there is no data to return.
89
         */
90
        return $defaultValue;
91
    }
92
93
    /**
94
     * Retrieve a value from a storage array.
95
     *
96
     * Returns $defaultValue if $setting is empty.
97
     *
98
     * @param mixed $storage
99
     * @param mixed $setting Can be an array, a string,
100
     *                          or a special formatted string
101
     *                          (eg 'app/path/project').
102
     * @param mixed $defaultValue
103
     * @return mixed
104
     */
105
    public static function getElse($storage, $setting = null, $defaultValue = false)
106
    {
107
        $data = self::get($storage, $setting, $defaultValue);
108
        return !empty($data) ? $data : $defaultValue;
109
    }
110
111
    public static function has($storage, $setting)
112
    {
113
        $value = 'WSFW_NOEXIST';
114
        $check = self::get($storage, $setting, $value);
115
        return $check !== $value;
116
    }
117
118
    /**
119
     * Sets a value in a storage array.
120
     *
121
     * @param array $storage
122
     * @param mixed $setting Can be an array, a string,
123
     *                          or a special formatted string
124
     *                          (eg 'app/path/project').
125
     * @param mixed $value The value to be stored.
126
     *
127
     * @return array The storage array with new data.
128
     * @throws \WebServCo\Framework\Exceptions\ArrayStorageException
129
     */
130
    public static function set($storage, $setting, $value)
131
    {
132
        if (!is_array($storage) || empty($setting)) {
0 ignored issues
show
introduced by
The condition is_array($storage) is always true.
Loading history...
133
            throw new ArrayStorageException('Invalid parameters specified.');
134
        }
135
        $setting = self::parseSetting($setting);
136
        if (is_array($setting)) {
137
            $reference = &$storage;
138
            foreach ($setting as $item) {
139
                if (!is_array($reference)) {
140
                    $reference = [];
141
                }
142
                $reference = &$reference[$item];
143
            }
144
            $reference = $value;
145
            unset($reference);
146
            return $storage;
147
        }
148
        $storage[$setting] = $value;
149
        return $storage;
150
    }
151
152
    /**
153
     * Add data to an existing key of a storage array.
154
     *
155
     * @param array $storage
156
     * @param mixed $setting Can be an array, a string,
157
     *                          or a special formatted string
158
     *                          (eg 'app/path/project').
159
     * @param mixed $data
160
     * @return array
161
     * @throws \WebServCo\Framework\Exceptions\ArrayStorageException
162
     */
163
    public static function add($storage, $setting, $data)
164
    {
165
        if (!is_array($storage) || empty($setting)) {
0 ignored issues
show
introduced by
The condition is_array($storage) is always true.
Loading history...
166
            throw new ArrayStorageException('Invalid parameters specified.');
167
        }
168
        $setting = self::parseSetting($setting);
169
        $newData = [$data];
170
        if (self::has($storage, $setting)) {
171
            $existingData = self::get($storage, $setting);
172
            if (!is_array($existingData)) {
173
                throw new ArrayStorageException('Invalid existing data type.');
174
            }
175
            $newData = array_merge($existingData, $newData);
176
        }
177
        return self::set($storage, $setting, $newData);
178
    }
179
180
    /**
181
     * Append data to a storage array.
182
     *
183
     * @param array $storage
184
     * @param mixed $data
185
     * @return array
186
     * @throws \WebServCo\Framework\Exceptions\ArrayStorageException
187
     */
188
    public static function append($storage, $data = [])
189
    {
190
        if (!is_array($storage) || !is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($storage) is always true.
Loading history...
191
            throw new ArrayStorageException('Invalid parameters specified.');
192
        }
193
        foreach ($data as $setting => $value) {
194
            if (array_key_exists($setting, $storage) &&
195
                is_array($storage[$setting]) &&
196
                is_array($value)
197
            ) {
198
                $storage[$setting] = self::append($storage[$setting], $value);
199
            } else {
200
                $storage[$setting] = $value;
201
            }
202
        }
203
        return $storage;
204
    }
205
206
    /**
207
     * Removes a setting from a storage array.
208
     *
209
     * @param array $storage
210
     * @param mixed $setting Can be an array, a string,
211
     *                          or a special formatted string
212
     *                          (eg 'app/path/project').
213
     *
214
     * @return array The updated storage array.
215
     * @throws \WebServCo\Framework\Exceptions\ArrayStorageException
216
     */
217
    public static function remove($storage, $setting)
218
    {
219
        if (!is_array($storage) || empty($setting)) {
0 ignored issues
show
introduced by
The condition is_array($storage) is always true.
Loading history...
220
            throw new ArrayStorageException('Invalid parameters specified.');
221
        }
222
223
        $setting = self::parseSetting($setting);
224
225
        if (empty($setting)) {
226
            throw new ArrayStorageException('Empty setting.');
227
        }
228
229
        if (is_array($setting)) {
230
            return self::removeByIndex($storage, $setting);
231
        }
232
        if (!array_key_exists($setting, $storage)) {
233
            throw new ArrayStorageException(
234
                sprintf('setting "%s" does not exist in storage object.', $setting)
235
            );
236
        }
237
        unset($storage[$setting]);
238
        return $storage;
239
    }
240
241
    /**
242
     * Remove index from multi-dimensional array.
243
     *
244
     * https://stackoverflow.com/questions/26661828/
245
     *
246
     * @param array $array
247
     *   The array to remove the index from.
248
     * @param array $indices
249
     *   Indexed array containing the indices chain up to the index that should be
250
     *   removed.
251
     * @return array
252
     *   The array with the index removed.
253
     * @throws \WebServCo\Framework\Exceptions\ArrayStorageException
254
     *   If the index does not exist within the array.
255
     */
256
    protected static function removeByIndex($array, $indices)
257
    {
258
        // Create a reference to the original array.
259
        $a = &$array;
260
        // Count all passed indices, remove one because arrays are zero based.
261
        $c = count($indices) - 1;
262
        // Iterate over all passed indices.
263
        for ($i = 0; $i <= $c; ++$i) {
264
            // Make sure the index to go down for deletion actually exists.
265
            if (!array_key_exists($indices[$i], $a)) {
266
                throw new ArrayStorageException(
267
                    sprintf('"%s" does not exist in storage object.', $indices[$i])
268
                );
269
            }
270
            // This is the target if we reached the last index that was passed.
271
            if ($i === $c) {
272
                unset($a[$indices[$i]]);
273
            } elseif (is_array($a[$indices[$i]])) {
274
                // Make sure we have an array to go further down.
275
                $a = &$a[$indices[$i]];
276
            } else {
277
                throw new ArrayStorageException(
278
                    sprintf('"%s" does not exist in storage object.', $indices[$i])
279
                );
280
            }
281
        }
282
        return $array;
283
    }
284
}
285