Passed
Branch main (078a91)
by Alain
15:46
created

AbstractConfig::reduceToSubKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * Bright Nucleus Config Component.
4
 *
5
 * @package   BrightNucleus\Config
6
 * @author    Alain Schlesser <[email protected]>
7
 * @license   MIT
8
 * @link      http://www.brightnucleus.com/
9
 * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10
 */
11
12
namespace BrightNucleus\Config;
13
14
use ArrayObject;
15
use BrightNucleus\Config\Exception\KeyNotFoundException;
16
use Exception;
17
18
/**
19
 * Handles basic manipulation of configuration values.
20
 *
21
 * @since      0.1.0
22
 *
23
 * @package    BrightNucleus\Config
24
 * @author     Alain Schlesser <[email protected]>
25
 */
26
abstract class AbstractConfig extends ArrayObject implements ConfigInterface
27
{
28
29
    /**
30
     * Array of strings that are used as delimiters to parse configuration keys.
31
     *
32
     * @since 0.1.6
33
     *
34
     * @var array
35
     */
36
    protected $delimiter = ['\\', '/', '.'];
37
38
    /**
39
     * Instantiate the AbstractConfig object.
40
     *
41
     * @since 0.1.0
42
     * @since 0.1.6 Accepts a delimiter to parse configuration keys.
43
     *
44
     * @param array                $config    Array with settings.
45
     * @param string[]|string|null $delimiter A string or array of strings that are used as delimiters to parse
46
     *                                        configuration keys. Defaults to "\", "/" & ".".
47
     */
48 5
    public function __construct(array $config, $delimiter = null)
49
    {
50
        // Make sure the config entries can be accessed as properties.
51 5
        parent::__construct($config, ArrayObject::ARRAY_AS_PROPS);
52
53 5
        if (null !== $delimiter) {
54 1
            $this->delimiter = (array)$delimiter;
55
        }
56 5
    }
57
58
    /**
59
     * Get the value of a specific key.
60
     *
61
     * To get a value several levels deep, add the keys for each level as a comma-separated list.
62
     *
63
     * @since 0.1.0
64
     * @since 0.1.4 Accepts list of keys.
65
     *
66
     * @param string|array $_ List of keys.
67
     *
68
     * @return mixed
69
     * @throws KeyNotFoundException If an unknown key is requested.
70
     */
71 4
    public function getKey($_)
72
    {
73 4
        $keys = $this->validateKeys(func_get_args());
74
75 4
        $keys  = array_reverse($keys);
76 4
        $array = $this->getArrayCopy();
77 4
        while (count($keys) > 0) {
78 4
            $key   = array_pop($keys);
79 4
            $array = $array[$key];
80
        }
81
82 4
        return $array;
83
    }
84
85
    /**
86
     * Check whether the Config has a specific key.
87
     *
88
     * To check a value several levels deep, add the keys for each level as a comma-separated list.
89
     *
90
     * @since 0.1.0
91
     * @since 0.1.4 Accepts list of keys.
92
     *
93
     * @param string|array $_ List of keys.
94
     *
95
     * @return bool
96
     */
97 5
    public function hasKey($_)
98
    {
99
        try {
100 5
            $keys = array_reverse($this->getKeyArguments(func_get_args()));
101
102 5
            $array = $this->getArrayCopy();
103 5
            while (count($keys) > 0) {
104 5
                $key = array_pop($keys);
105 5
                if (! array_key_exists($key, $array)) {
106 3
                    return false;
107
                }
108 5
                $array = $array[$key];
109
            }
110
        } catch (Exception $exception) {
111
            return false;
112
        }
113
114 5
        return true;
115
    }
116
117
    /**
118
     * Get a (multi-dimensional) array of all the configuration settings.
119
     *
120
     * @since 0.1.4
121
     *
122
     * @return array
123
     */
124 1
    public function getAll()
125
    {
126 1
        return $this->getArrayCopy();
127
    }
128
129
    /**
130
     * Get the an array with all the keys
131
     *
132
     * @since 0.1.0
133
     * @return array
134
     */
135 1
    public function getKeys()
136
    {
137 1
        return array_keys((array)$this);
138
    }
139
140
    /**
141
     * Get a new config at a specific sub-level.
142
     *
143
     * @since 0.1.13
144
     *
145
     * @param string|array $_ List of keys.
146
     *
147
     * @return ConfigInterface
148
     * @throws KeyNotFoundException If an unknown key is requested.
149
     */
150 1
    public function getSubConfig($_)
151
    {
152 1
        $keys = $this->validateKeys(func_get_args());
153
154 1
        $subConfig = clone $this;
155 1
        $subConfig->reduceToSubKey($keys);
156
157 1
        return $subConfig;
158
    }
159
160
    /**
161
     * Validate a set of keys to make sure they exist.
162
     *
163
     * @since 0.1.13
164
     *
165
     * @param string|array $_ List of keys.
166
     *
167
     * @return array List of keys.
168
     * @throws KeyNotFoundException If an unknown key is requested.
169
     */
170 2
    public function validateKeys($_)
171
    {
172 2
        $keys = $this->getKeyArguments(func_get_args());
173
174 2
        if (! $this->hasKey($keys)) {
175 1
            throw new KeyNotFoundException(
176
                sprintf(
177 1
                    _('The configuration key %1$s does not exist.'),
178 1
                    implode('->', $keys)
179
                )
180
            );
181
        }
182
183 2
        return $keys;
184
    }
185
186
    /**
187
     * Reduce the currently stored config array to a subarray at a specific level.
188
     *
189
     * @since 0.1.13
190
     *
191
     * @param array $keys Array of keys that point to a key down in the hierarchy.
192
     */
193 1
    protected function reduceToSubKey(array $keys)
194
    {
195 1
        $this->exchangeArray($this->getKey($keys));
196 1
    }
197
198
    /**
199
     * Recursively extract the configuration key arguments from an arbitrary array.
200
     *
201
     * @since 0.1.6
202
     *
203
     * @param array $arguments Array as fetched through get_func_args().
204
     *
205
     * @return array Array of strings.
206
     */
207 6
    protected function getKeyArguments($arguments)
208
    {
209 6
        $keys = [];
210 6
        foreach ($arguments as $argument) {
211 6
            if (is_array($argument)) {
212 5
                $keys = array_merge($keys, $this->getKeyArguments($argument));
213
            }
214 6
            if (is_string($argument)) {
215 6
                $keys = array_merge($keys, $this->parseKeysString($argument));
216
            }
217
        }
218
219 6
        return $keys;
220
    }
221
222
    /**
223
     * Extract individual keys from a delimited string.
224
     *
225
     * @since 0.1.6
226
     *
227
     * @param string $keyString Delimited string of keys.
228
     *
229
     * @return array Array of key strings.
230
     */
231 4
    protected function parseKeysString($keyString)
232
    {
233
        // Replace all of the configured delimiters by the first one, so that we can then use explode().
234 4
        $normalizedString = str_replace($this->delimiter, $this->delimiter[0], $keyString);
235
236 4
        return (array)explode($this->delimiter[0], $normalizedString);
237
    }
238
239
    /**
240
     * Validate the Config file.
241
     *
242
     * @since  0.1.0
243
     * @return boolean
244
     */
245
    abstract public function isValid();
246
}
247