Completed
Push — develop ( ff002b...f70fac )
by Davide
09:00
created

AbstractConfig::get()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 24
ccs 13
cts 13
cp 1
rs 8.6846
cc 4
eloc 13
nc 4
nop 2
crap 4
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 = array();
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 array();
54
    }
55
56
    /**
57
     * ConfigInterface Methods
58
     */
59
60
    /**
61
     * {@inheritDoc}
62
     */
63 24
    public function get($key, $default = null)
64
    {
65
        // Check if already cached
66 24
        if (isset($this->cache[$key])) {
67 3
            return $this->cache[$key];
68
        }
69
70 24
        $segs = explode('.', $key);
71 24
        $root = $this->data;
72
73
        // nested case
74 24
        foreach ($segs as $part) {
75 24
            if (isset($root[$part])) {
76 15
                $root = $root[$part];
77 15
                continue;
78
            } else {
79 12
                $root = $default;
80 12
                break;
81
            }
82 24
        }
83
84
        // whatever we have is what we needed
85 24
        return ($this->cache[$key] = $root);
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91 18
    public function set($key, $value)
92
    {
93 18
        $segs = explode('.', $key);
94 18
        $root = &$this->data;
95 18
        $cacheKey = '';
96
97
        // Look for the key, creating nested keys if needed
98 18
        while ($part = array_shift($segs)) {
99 18
            if($cacheKey != ''){
100 12
                $cacheKey .= '.';
101 12
            }
102 18
            $cacheKey .= $part;
103 18
            if (!isset($root[$part]) && count($segs)) {
104 3
                $root[$part] = array();
105 3
            }
106 18
            $root = &$root[$part];
107
108
            //Unset all old nested cache
109 18
            if(isset($this->cache[$cacheKey])){
110 9
                unset($this->cache[$cacheKey]);
111 9
            }
112
113
            //Unset all old nested cache in case of array
114 18
            if(count($segs) == 0){
115 18
                foreach ($this->cache as $cacheLocalKey => $cacheValue) {
116 9
                    if(substr($cacheLocalKey, 0, strlen($cacheKey)) === $cacheKey){
117 6
                        unset($this->cache[$cacheLocalKey]);
118 6
                    }
119 18
                }
120 18
            }
121 18
        }
122
123
        // Assign value at target node
124 18
        $this->cache[$key] = $root = $value;
125 18
    }
126
127
    /**
128
     * {@inheritDoc}
129
     */
130 6
    public function has($key)
131
    {
132 6
        return !is_null($this->get($key));
133
    }
134
135
    /**
136
     * {@inheritDoc}
137
     */
138 3
    public function all()
139
    {
140 3
        return $this->data;
141
    }
142
143
144
145
    /**
146
     * ArrayAccess Methods
147
     */
148
149
    /**
150
     * Gets a value using the offset as a key
151
     *
152
     * @param  string $offset
153
     *
154
     * @return mixed
155
     */
156 6
    public function offsetGet($offset)
157
    {
158 6
        return $this->get($offset);
159
    }
160
161
    /**
162
     * Checks if a key exists
163
     *
164
     * @param  string $offset
165
     *
166
     * @return bool
167
     */
168 6
    public function offsetExists($offset)
169
    {
170 6
        return $this->has($offset);
171
    }
172
173
    /**
174
     * Sets a value using the offset as a key
175
     *
176
     * @param  string $offset
177
     * @param  mixed  $value
178
     *
179
     * @return void
180
     */
181 3
    public function offsetSet($offset, $value)
182
    {
183 3
        $this->set($offset, $value);
184 3
    }
185
186
    /**
187
     * Deletes a key and its value
188
     *
189
     * @param  string $offset
190
     *
191
     * @return void
192
     */
193 3
    public function offsetUnset($offset)
194
    {
195 3
        $this->set($offset, null);
196 3
    }
197
198
    /**
199
     * Iterator Methods
200
     */
201
202
    /**
203
     * Returns the data array element referenced by its internal cursor
204
     *
205
     * @return mixed The element referenced by the data array's internal cursor.
206
     *     If the array is empty or there is no element at the cursor, the
207
     *     function returns false. If the array is undefined, the function
208
     *     returns null
209
     */
210 3
    public function current()
211
    {
212 3
        return (is_array($this->data) ? current($this->data) : null);
213
    }
214
215
    /**
216
     * Returns the data array index referenced by its internal cursor
217
     *
218
     * @return mixed The index referenced by the data array's internal cursor.
219
     *     If the array is empty or undefined or there is no element at the
220
     *     cursor, the function returns null
221
     */
222 3
    public function key()
223
    {
224 3
        return (is_array($this->data) ? key($this->data) : null);
225
    }
226
227
    /**
228
     * Moves the data array's internal cursor forward one element
229
     *
230
     * @return mixed The element referenced by the data array's internal cursor
231
     *     after the move is completed. If there are no more elements in the
232
     *     array after the move, the function returns false. If the data array
233
     *     is undefined, the function returns null
234
     */
235 3
    public function next()
236
    {
237 3
        return (is_array($this->data) ? next($this->data) : null);
238
    }
239
240
    /**
241
     * Moves the data array's internal cursor to the first element
242
     *
243
     * @return mixed The element referenced by the data array's internal cursor
244
     *     after the move is completed. If the data array is empty, the function
245
     *     returns false. If the data array is undefined, the function returns
246
     *     null
247
     */
248 3
    public function rewind()
249
    {
250 3
        return (is_array($this->data) ? reset($this->data) : null);
251
    }
252
253
    /**
254
     * Tests whether the iterator's current index is valid
255
     *
256
     * @return bool True if the current index is valid; false otherwise
257
     */
258 3
    public function valid()
259
    {
260 3
        return (is_array($this->data) ? key($this->data) !== null : false);
261
    }
262
}
263