Completed
Pull Request — develop (#124)
by Filip
12:16
created

AbstractConfig::getDefaults()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Noodlehaus;
4
5
use ArrayAccess;
6
use Iterator;
7
8
/**
9
 * Abstract Config class
10
 *
11
 * @package    Config
12
 * @author     Jesus A. Domingo <[email protected]>
13
 * @author     Hassan Khan <[email protected]>
14
 * @link       https://github.com/noodlehaus/config
15
 * @license    MIT
16
 */
17
abstract class AbstractConfig implements ArrayAccess, ConfigInterface, Iterator
18
{
19
    /**
20
     * Stores the configuration data
21
     *
22
     * @var array|null
23
     */
24
    protected $data = null;
25
26
    /**
27
     * Caches the configuration data
28
     *
29
     * @var array
30
     */
31
    protected $cache = [];
32
33
    /**
34
     * Constructor method and sets default options, if any
35
     *
36
     * @param array $data
37
     */
38 3
    public function __construct(array $data)
39
    {
40 3
        $this->data = array_merge($this->getDefaults(), $data);
41 3
    }
42
43
    /**
44
     * Override this method in your own subclass to provide an array of default
45
     * options and values
46
     *
47
     * @return array
48
     *
49
     * @codeCoverageIgnore
50
     */
51
    protected function getDefaults()
52
    {
53
        return [];
54
    }
55
56
    /**
57
     * ConfigInterface Methods
58
     */
59
60
    /**
61
     * {@inheritDoc}
62
     */
63 24
    public function get($key, $default = null)
64
    {
65 24
        if ($this->has($key)) {
66 12
            return $this->cache[$key];
67
        }
68
69 12
        return $default;
70
    }
71
72
    /**
73
     * {@inheritDoc}
74
     */
75 18
    public function set($key, $value)
76
    {
77 18
        $segs = explode('.', $key);
78 18
        $root = &$this->data;
79 18
        $cacheKey = '';
80
81
        // Look for the key, creating nested keys if needed
82 18
        while ($part = array_shift($segs)) {
83 18
            if ($cacheKey != '') {
84 12
                $cacheKey .= '.';
85
            }
86 18
            $cacheKey .= $part;
87 18
            if (!isset($root[$part]) && count($segs)) {
88 3
                $root[$part] = [];
89
            }
90 18
            $root = &$root[$part];
91
92
            //Unset all old nested cache
93 18
            if (isset($this->cache[$cacheKey])) {
94 9
                unset($this->cache[$cacheKey]);
95
            }
96
97
            //Unset all old nested cache in case of array
98 18
            if (count($segs) == 0) {
99 18
                foreach ($this->cache as $cacheLocalKey => $cacheValue) {
100 9
                    if (substr($cacheLocalKey, 0, strlen($cacheKey)) === $cacheKey) {
101 6
                        unset($this->cache[$cacheLocalKey]);
102
                    }
103
                }
104
            }
105
        }
106
107
        // Assign value at target node
108 18
        $this->cache[$key] = $root = $value;
109 18
    }
110
111
    /**
112
     * {@inheritDoc}
113
     */
114 9
    public function unset($key)
115
    {
116
        $segs = explode('.', $key);
117 9
        $root = &$this->data;
118 3
119
        foreach(array_slice($segs, 0, -1) as $seg) {
120
            $root = &$root[$seg];
121 9
        }
122 9
123
        unset($root[array_pop($segs)]);
124
        unset($this->cache[$key]);
125 9
    }
126 9
127 9
    /**
128 9
     * {@inheritDoc}
129
     */
130 6
    public function has($key)
131
    {
132
        // Check if already cached
133
        if (isset($this->cache[$key])) {
134
            return true;
135 9
        }
136
137 9
        $segments = explode('.', $key);
138
        $root = $this->data;
139
140
        // nested case
141
        foreach ($segments as $segment) {
142
            if (array_key_exists($segment, $root)) {
143
                $root = $root[$segment];
144
                continue;
145
            } else {
146 3
                return false;
147
            }
148 3
        }
149 3
150
        // Set cache for the given key
151
        $this->cache[$key] = $root;
152
153
        return true;
154
    }
155 3
156
    /**
157 3
     * Merge config from another instance
158
     *
159
     * @param ConfigInterface $config
160
     * @return ConfigInterface
161
     */
162
    public function merge(ConfigInterface $config)
163
    {
164
        $this->data = array_replace_recursive($this->data, $config->all());
165
        return $this;
166
    }
167
168
    /**
169
     * {@inheritDoc}
170
     */
171 6
    public function all()
172
    {
173 6
        return $this->data;
174
    }
175
176
    /**
177
     * ArrayAccess Methods
178
     */
179
180
    /**
181
     * Gets a value using the offset as a key
182
     *
183 6
     * @param  string $offset
184
     *
185 6
     * @return mixed
186
     */
187
    public function offsetGet($offset)
188
    {
189
        return $this->get($offset);
190
    }
191
192
    /**
193
     * Checks if a key exists
194
     *
195
     * @param  string $offset
196 3
     *
197
     * @return bool
198 3
     */
199 3
    public function offsetExists($offset)
200
    {
201
        return $this->has($offset);
202
    }
203
204
    /**
205
     * Sets a value using the offset as a key
206
     *
207
     * @param  string $offset
208 3
     * @param  mixed  $value
209
     *
210 3
     * @return void
211 3
     */
212
    public function offsetSet($offset, $value)
213
    {
214
        $this->set($offset, $value);
215
    }
216
217
    /**
218
     * Deletes a key and its value
219
     *
220
     * @param  string $offset
221
     *
222
     * @return void
223
     */
224
    public function offsetUnset($offset)
225 3
    {
226
        $this->unset($offset);
227 3
    }
228
229
    /**
230
     * Iterator Methods
231
     */
232
233
    /**
234
     * Returns the data array element referenced by its internal cursor
235
     *
236
     * @return mixed The element referenced by the data array's internal cursor.
237 3
     *     If the array is empty or there is no element at the cursor, the
238
     *     function returns false. If the array is undefined, the function
239 3
     *     returns null
240
     */
241
    public function current()
242
    {
243
        return (is_array($this->data) ? current($this->data) : null);
244
    }
245
246
    /**
247
     * Returns the data array index referenced by its internal cursor
248
     *
249
     * @return mixed The index referenced by the data array's internal cursor.
250 3
     *     If the array is empty or undefined or there is no element at the
251
     *     cursor, the function returns null
252 3
     */
253
    public function key()
254
    {
255
        return (is_array($this->data) ? key($this->data) : null);
256
    }
257
258
    /**
259
     * Moves the data array's internal cursor forward one element
260
     *
261
     * @return mixed The element referenced by the data array's internal cursor
262
     *     after the move is completed. If there are no more elements in the
263 3
     *     array after the move, the function returns false. If the data array
264
     *     is undefined, the function returns null
265 3
     */
266
    public function next()
267
    {
268
        return (is_array($this->data) ? next($this->data) : null);
269
    }
270
271
    /**
272
     * Moves the data array's internal cursor to the first element
273 3
     *
274
     * @return mixed The element referenced by the data array's internal cursor
275 3
     *     after the move is completed. If the data array is empty, the function
276
     *     returns false. If the data array is undefined, the function returns
277
     *     null
278
     */
279
    public function rewind()
280
    {
281
        return (is_array($this->data) ? reset($this->data) : null);
282
    }
283
284
    /**
285 3
     * Tests whether the iterator's current index is valid
286
     *
287 3
     * @return bool True if the current index is valid; false otherwise
288 3
     */
289
    public function valid()
290
    {
291
        return (is_array($this->data) ? key($this->data) !== null : false);
292
    }
293
294
    /**
295
     * Remove a value using the offset as a key
296
     *
297
     * @param  string $key
298
     *
299
     * @return void
300
     */
301
    public function remove($key)
302
    {
303
        $this->unset($key);
304
    }
305
}
306