Passed
Push — master ( 5a0590...0c08dd )
by Andreas
49:13 queued 24:34
created

midcom_helper_configuration   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 86.11%

Importance

Changes 0
Metric Value
eloc 60
dl 0
loc 244
ccs 62
cts 72
cp 0.8611
rs 10
c 0
b 0
f 0
wmc 30

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 3
A store() 0 13 4
A _update_cache() 0 6 3
A get_all() 0 8 3
A _check_local_array() 0 6 3
A _store_from_object() 0 19 5
A reset_local() 0 4 1
A store_from_object() 0 5 1
A set() 0 5 2
A exists() 0 8 3
A get() 0 6 2
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
     * @var Array
50
     */
51
    public $_global = [];
52
53
    /**
54
     * Locally overridden configuration data.
55
     *
56
     * @var Array
57
     */
58
    public $_local = [];
59
60
    /**
61
     * Merged, current configuration state.
62
     *
63
     * @var Array
64
     */
65
    private $_merged = [];
66
67
    /**
68
     * Internal cache-related items
69
     * @ignore
70
     */
71
    private $_object_stored = false;
72
    private $_object;
73
    private $_path;
74
75
    /**
76
     * The constructor initializes the global configuration.
77
     *
78
     * Two sources can be specified:
79
     *
80
     * First, if passed a single associative array to the constructor,
81
     * it will use its contents as global configuration.
82
     *
83
     * Alternatively you can specify any Midgard object and a parameter
84
     * domain. It will then use the contents of this domain as global
85
     * configuration.
86
     *
87
     * @param mixed $param1        Either an associative array or a Midgard object.
88
     * @param mixed $param2        Either null or the name of a Parameter domain.
89
     */
90 489
    public function __construct($param1, $param2 = null)
91
    {
92 489
        if ($param2 !== null) {
93 2
            $this->_object = $param1;
94 2
            $this->_path = $param2;
95 2
            $this->_store_from_object(true);
96 489
        } elseif ($param1 !== null) {
97 489
            $this->_global = $param1;
98 489
            $this->_merged = $param1;
99
        }
100 489
    }
101
102
    /**
103
     * Fetch the configuration data stored in the parameter domain _path of _object.
104
     *
105
     * The flag $global controls whether the global or the local configuration should
106
     * be updated. No control whether an update of the global data is allowed is done
107
     * here, the caller has to do this.
108
     * This function will update the config data cache array. If it stores global
109
     * configuration data it will automatically erase the local configuration data.
110
     *
111
     * Any error such as invalid configuration data will trigger a MidCOM error.
112
     *
113
     * @param boolean            $global        Set to true to replace the global configuration.
114
     */
115 377
    private function _store_from_object($global = false, $merge = false)
116
    {
117
        // Cast to DBA type.
118 377
        if (!midcom::get()->dbclassloader->is_midcom_db_object($this->_object)) {
119
            $this->_object = midcom::get()->dbfactory->convert_midgard_to_midcom($this->_object);
120
        }
121
122 377
        $array = $this->_object->list_parameters($this->_path);
123
124 377
        if ($global) {
125 2
            $this->_global = ($merge) ? array_merge($this->_global, $array) : $array;
126 2
            $this->_local = [];
127 2
            $this->_merged = $array;
128
        }
129
130 377
        $this->_check_local_array($array);
131 377
        $this->_local = ($merge) ? array_merge($this->_local, $array) : $array;
132 377
        $this->_update_cache();
133 377
        $this->_object_stored = true;
134 377
    }
135
136
    /**
137
     * Merge the local and the global configuration arrays into the cache array.
138
     */
139 382
    private function _update_cache()
140
    {
141 382
        $this->_merged = $this->_global;
142 382
        if (   !empty($this->_local)
143 382
            && is_array($this->_local)) {
144 27
            $this->_merged = array_merge($this->_merged, $this->_local);
145
        }
146 382
    }
147
148
    /**
149
     * Check local data array for validity
150
     *
151
     * Since the local array must only include configuration parameters that are
152
     * included in the global configuration, this function is used to check a local
153
     * array against the current global configuration. true/false is returned
154
     * accordingly.
155
     */
156 377
    private function _check_local_array(array $array)
157
    {
158 377
        if (!empty($array)) {
159 20
            $diff = array_keys(array_diff_key($array, $this->_global));
160 20
            foreach ($diff as $key) {
161
                debug_add("The key {$key} is not present in the global configuration array.", MIDCOM_LOG_INFO);
162
            }
163
        }
164 377
    }
165
166
    /**
167
     * Write the parameters in $params into the local configuration.
168
     *
169
     * If $reset is set, the local configuration will be cleared before
170
     * the new set is imported, if not, the new data is merged with the old local
171
     * configuration, overwriting duplicates. During import each configuration key will
172
     * be checked against the global configuration values. If an unknown value is found,
173
     * import will be aborted and no changes to the configuration is done.
174
     *
175
     * After import the cache array will be updated, reset is done by reset_local.
176
     *
177
     * @param array    $params        The new local parameters
178
     * @param boolean    $reset        If set to true, the current local configuration will be discarded first.
179
     * @see midcom_helper_configuration::reset_local()
180
     */
181 1
    public function store(array $params, $reset = true)
182
    {
183 1
        if (   !$this->_object_stored
184 1
            && $this->_object) {
185
            $this->_store_from_object();
186
        }
187
188 1
        $this->_check_local_array($params);
189 1
        if ($reset == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
190
            $this->reset_local();
191
        }
192 1
        $this->_local = array_merge($this->_local, $params);
193 1
        $this->_update_cache();
194 1
    }
195
196
    /**
197
     * Import data from a Midgard object.
198
     *
199
     * To import configuration data from a Midgard Object, use this method. As in the
200
     * respective constructor it will retrieve the configuration data in the parameter
201
     * domain $path of $object. Unlike the constructor this function will store the
202
     * data in the local configuration.
203
     *
204
     * @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...
205
     * @param string $path    The parameter domain to query.
206
     * @param boolean $merge Should the existing local config be overridden or merged
207
     */
208 377
    public function store_from_object($object, $path, $merge = false)
209
    {
210 377
        $this->_object = $object;
211 377
        $this->_path = $path;
212 377
        $this->_store_from_object(false, $merge);
213 377
    }
214
215
    /**
216
     * Clear the local configuration data, effectively reverting to the global
217
     * default.
218
     */
219
    public function reset_local()
220
    {
221
        $this->_local = [];
222
        $this->_merged = $this->_global;
223
    }
224
225
    /**
226
     * Retrieve a configuration key
227
     *
228
     * If $key exists in the configuration data, its value is returned to the caller.
229
     * If the value does not exist, the boolean value false will be returned. Be aware
230
     * that this is not always good for error checking, since "false" is a perfectly good
231
     * value in the configuration data. Do error checking with the function exists (see
232
     * below).
233
     *
234
     * @param string    $key    The configuration key to query.
235
     * @return mixed        Its value or false, if the key doesn't exist.
236
     * @see midcom_helper_configuration::exists()
237
     */
238 470
    public function get($key)
239
    {
240 470
        if ($this->exists($key)) {
241 470
            return $this->_merged[$key];
242
        }
243 11
        return false;
244
    }
245
246
    /**
247
     * Set a value on the current instance, if the given key exists
248
     *
249
     * @param string $key The configuration key to set.
250
     * @param mixed $value The value to set.
251
     */
252 17
    public function set($key, $value)
253
    {
254 17
        if ($this->exists($key)) {
255 17
            $this->_local[$key] = $value;
256 17
            $this->_update_cache();
257
        }
258 17
    }
259
260
    /**
261
     * Retrieve a copy the complete configuration array.
262
     *
263
     * @return Array    The complete current configuration.
264
     */
265 2
    public function get_all()
266
    {
267 2
        if (   !$this->_object_stored
268 2
            && $this->_object) {
269
            $this->_store_from_object();
270
        }
271
272 2
        return $this->_merged;
273
    }
274
275
    /**
276
     * Checks for the existence of a configuration key.
277
     *
278
     * @param string    $key    The configuration key to check for.
279
     */
280 470
    public function exists($key) : bool
281
    {
282 470
        if (   !$this->_object_stored
283 470
            && $this->_object) {
284
            $this->_store_from_object();
285
        }
286
287 470
        return array_key_exists($key, $this->_merged);
288
    }
289
}
290