Completed
Pull Request — master (#91)
by
unknown
04:40
created

AbstractConfig::has()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

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