Passed
Push — master ( dceb22...74dea8 )
by Andreas
09:04
created

midcom_helper_configuration::_check_local_array()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 5
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 10
1
<?php
2
/**
3
 * @package midcom.helper
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * This class is designed to ease MidCOM Configuration management.
11
 *
12
 * Basically it supports key/value pairs of data, which can be retrieved out of Midgard
13
 * Parameters. In this case it would make the key/values a string/string pair with
14
 * a length limit of 255 characters. Since the current implementation only supports
15
 * read-access to the configuration data, this is a negligible fact, in reality it
16
 * supports all valid PHP data types as key or data values, as long it is allowed
17
 * to use the keys as array index elements.
18
 *
19
 * This class is designed to manage parameter like key/value configuration data.
20
 * The class makes no assumption about the value type of keys or values, any valid
21
 * PHP data type is allowed. Two different sets of configuration options are stored
22
 * within the class, the "global" and the "local" configuration.
23
 *
24
 * The global configuration must include all possible configuration parameters with
25
 * their default values. These data is fixed and cannot be changed after object
26
 * instantiation. Aimed specifically at MidCOM is the second set of configuration
27
 * data, the "local" parameters. It gives you a way of explicitly overwrite a part
28
 * of the configuration data with localized values. This customization data can be
29
 * overwritten at wish by deliberately resetting it to the defaults or by importing
30
 * a new one over the existing local configuration.
31
 *
32
 * Configuration data can be delivered in two ways: The easiest way is using a
33
 * associative array that will be used as configuration. Alternatively you can
34
 * specify both a MidgardObject and a MidCOM Path which is used to fetch
35
 * configuration data.
36
 *
37
 * Any configuration key in the local configuration, which is not present in the
38
 * global "template", will be logged as a warning. This should normally not happen.
39
 * Originally, this case threw a critical error, but that made upgrading
40
 * configurations quite difficult.
41
 *
42
 * @package midcom.helper
43
 */
44
class midcom_helper_configuration
45
{
46
    /**
47
     * Globally assigned configuration data.
48
     */
49
    public array $_global = [];
50
51
    /**
52
     * Locally overridden configuration data.
53
     */
54
    public array $_local = [];
55
56
    /**
57
     * Merged, current configuration state.
58
     */
59
    private array $_merged = [];
60
61
    /**
62
     * Internal cache-related items
63
     * @ignore
64
     */
65
    private $_object;
66
    private $_path;
67
68
    /**
69
     * The constructor initializes the global configuration.
70
     *
71
     * Two sources can be specified:
72
     *
73
     * First, if passed a single associative array to the constructor,
74
     * it will use its contents as global configuration.
75
     *
76
     * Alternatively you can specify any Midgard object and a parameter
77
     * domain. It will then use the contents of this domain as global
78
     * configuration.
79
     *
80
     * @param mixed $source      Either an associative array or a Midgard object.
81
     * @param string $path       Either null or the name of a Parameter domain.
82
     */
83 520
    public function __construct($source, string $path = null)
84
    {
85 520
        if ($path !== null) {
86 2
            $this->_object = $source;
87 2
            $this->_path = $path;
88 2
            $this->_store_from_object(true);
89
        } else {
90 520
            $this->_global = $source;
91 520
            $this->_merged = $source;
92
        }
93
    }
94
95
    /**
96
     * Fetch the configuration data stored in the parameter domain _path of _object.
97
     *
98
     * The flag $global controls whether the global or the local configuration should
99
     * be updated. No control whether an update of the global data is allowed is done
100
     * here, the caller has to do this.
101
     * This function will update the config data cache array. If it stores global
102
     * configuration data it will automatically erase the local configuration data.
103
     *
104
     * Any error such as invalid configuration data will trigger a MidCOM error.
105
     *
106
     * @param boolean            $global        Set to true to replace the global configuration.
107
     */
108 398
    private function _store_from_object(bool $global = false, bool $merge = false)
109
    {
110
        // Cast to DBA type.
111 398
        if (!midcom::get()->dbclassloader->is_midcom_db_object($this->_object)) {
112
            $this->_object = midcom::get()->dbfactory->convert_midgard_to_midcom($this->_object);
113
        }
114
115 398
        $array = $this->_object->list_parameters($this->_path);
116
117 398
        if ($global) {
118 2
            $this->_global = $merge ? array_merge($this->_global, $array) : $array;
119 2
            $this->_local = [];
120 2
            $this->_merged = $array;
121
        }
122
123 398
        $this->_check_local_array($array);
124 398
        $this->_local = $merge ? array_merge($this->_local, $array) : $array;
125 398
        $this->_update_cache();
126
    }
127
128
    /**
129
     * Merge the local and the global configuration arrays into the cache array.
130
     */
131 409
    private function _update_cache()
132
    {
133 409
        $this->_merged = array_merge($this->_global, $this->_local);
134
    }
135
136
    /**
137
     * Check local data array for validity
138
     *
139
     * Since the local array must only include configuration parameters that are
140
     * included in the global configuration, this function is used to check a local
141
     * array against the current global configuration. true/false is returned
142
     * accordingly.
143
     */
144 398
    private function _check_local_array(array $array)
145
    {
146 398
        $diff = array_keys(array_diff_key($array, $this->_global));
147 398
        foreach ($diff as $key) {
148
            debug_add("The key {$key} is not present in the global configuration array.", MIDCOM_LOG_INFO);
149
        }
150
    }
151
152
    /**
153
     * Write the parameters in $params into the local configuration.
154
     *
155
     * If $reset is set, the local configuration will be cleared before
156
     * the new set is imported, if not, the new data is merged with the old local
157
     * configuration, overwriting duplicates. During import each configuration key will
158
     * be checked against the global configuration values. If an unknown value is found,
159
     * import will be aborted and no changes to the configuration is done.
160
     *
161
     * After import the cache array will be updated, reset is done by reset_local.
162
     *
163
     * @param boolean    $reset        If set to true, the current local configuration will be discarded first.
164
     * @see midcom_helper_configuration::reset_local()
165
     */
166 1
    public function store(array $params, bool $reset = true)
167
    {
168 1
        $this->_check_local_array($params);
169 1
        if ($reset) {
170
            $this->reset_local();
171
        }
172 1
        $this->_local = array_merge($this->_local, $params);
173 1
        $this->_update_cache();
174
    }
175
176
    /**
177
     * Import data from a Midgard object.
178
     *
179
     * To import configuration data from a Midgard Object, use this method. As in the
180
     * respective constructor it will retrieve the configuration data in the parameter
181
     * domain $path of $object. Unlike the constructor this function will store the
182
     * data in the local configuration.
183
     *
184
     * @param MidgardObject $object    The object from which to import data.
0 ignored issues
show
Bug introduced by
The type MidgardObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
185
     * @param string $path    The parameter domain to query.
186
     * @param boolean $merge Should the existing local config be overridden or merged
187
     */
188 398
    public function store_from_object(object $object, string $path, bool $merge = false)
189
    {
190 398
        $this->_object = $object;
191 398
        $this->_path = $path;
192 398
        $this->_store_from_object(false, $merge);
193
    }
194
195
    /**
196
     * Clear the local configuration data, effectively reverting to the global
197
     * default.
198
     */
199
    public function reset_local()
200
    {
201
        $this->_local = [];
202
        $this->_merged = $this->_global;
203
    }
204
205
    /**
206
     * Retrieve a configuration key
207
     *
208
     * If $key exists in the configuration data, its value is returned to the caller.
209
     * If the value does not exist, the boolean value false will be returned. Be aware
210
     * that this is not always good for error checking, since "false" is a perfectly good
211
     * value in the configuration data. Do error checking with the function exists (see
212
     * below).
213
     *
214
     * @return mixed        Its value or false, if the key doesn't exist.
215
     * @see midcom_helper_configuration::exists()
216
     */
217 505
    public function get(string $key)
218
    {
219 505
        if ($this->exists($key)) {
220 504
            return $this->_merged[$key];
221
        }
222 15
        return false;
223
    }
224
225 246
    public function get_array(string $key) : array
226
    {
227 246
        $value = $this->get($key) ?: [];
228 246
        if (!is_array($value)) {
229
            throw new midcom_error('Config key "' . $key . '" is not an array');
230
        }
231 246
        return $value;
232
    }
233
234
    /**
235
     * Set a value on the current instance, if the given key exists
236
     */
237 21
    public function set(string $key, $value)
238
    {
239 21
        if ($this->exists($key)) {
240 21
            $this->_local[$key] = $value;
241 21
            $this->_update_cache();
242
        }
243
    }
244
245
    /**
246
     * Retrieve a copy the complete configuration array.
247
     */
248 10
    public function get_all() : array
249
    {
250 10
        return $this->_merged;
251
    }
252
253
    /**
254
     * Checks for the existence of a configuration key.
255
     */
256 505
    public function exists(string $key) : bool
257
    {
258 505
        return array_key_exists($key, $this->_merged);
259
    }
260
}
261