|
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
|
457 |
|
public function __construct($param1, $param2 = null) |
|
91
|
|
|
{ |
|
92
|
457 |
|
if ($param2 !== null) { |
|
93
|
2 |
|
$this->_object = $param1; |
|
94
|
2 |
|
$this->_path = $param2; |
|
95
|
2 |
|
$this->_store_from_object(true); |
|
96
|
457 |
|
} elseif ($param1 !== null) { |
|
97
|
457 |
|
$this->_global = $param1; |
|
98
|
457 |
|
$this->_merged = $param1; |
|
99
|
|
|
} |
|
100
|
457 |
|
} |
|
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
|
378 |
|
private function _store_from_object(bool $global = false, bool $merge = false) |
|
116
|
|
|
{ |
|
117
|
|
|
// Cast to DBA type. |
|
118
|
378 |
|
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
|
378 |
|
$array = $this->_object->list_parameters($this->_path); |
|
123
|
|
|
|
|
124
|
378 |
|
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
|
378 |
|
$this->_check_local_array($array); |
|
131
|
378 |
|
$this->_local = ($merge) ? array_merge($this->_local, $array) : $array; |
|
132
|
378 |
|
$this->_update_cache(); |
|
133
|
378 |
|
$this->_object_stored = true; |
|
134
|
378 |
|
} |
|
135
|
|
|
|
|
136
|
|
|
/** |
|
137
|
|
|
* Merge the local and the global configuration arrays into the cache array. |
|
138
|
|
|
*/ |
|
139
|
383 |
|
private function _update_cache() |
|
140
|
|
|
{ |
|
141
|
383 |
|
$this->_merged = $this->_global; |
|
142
|
383 |
|
if ( !empty($this->_local) |
|
143
|
383 |
|
&& is_array($this->_local)) { |
|
144
|
27 |
|
$this->_merged = array_merge($this->_merged, $this->_local); |
|
145
|
|
|
} |
|
146
|
383 |
|
} |
|
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
|
378 |
|
private function _check_local_array(array $array) |
|
157
|
|
|
{ |
|
158
|
378 |
|
$diff = array_keys(array_diff_key($array, $this->_global)); |
|
159
|
378 |
|
foreach ($diff as $key) { |
|
160
|
|
|
debug_add("The key {$key} is not present in the global configuration array.", MIDCOM_LOG_INFO); |
|
161
|
|
|
} |
|
162
|
378 |
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* Write the parameters in $params into the local configuration. |
|
166
|
|
|
* |
|
167
|
|
|
* If $reset is set, the local configuration will be cleared before |
|
168
|
|
|
* the new set is imported, if not, the new data is merged with the old local |
|
169
|
|
|
* configuration, overwriting duplicates. During import each configuration key will |
|
170
|
|
|
* be checked against the global configuration values. If an unknown value is found, |
|
171
|
|
|
* import will be aborted and no changes to the configuration is done. |
|
172
|
|
|
* |
|
173
|
|
|
* After import the cache array will be updated, reset is done by reset_local. |
|
174
|
|
|
* |
|
175
|
|
|
* @param array $params The new local parameters |
|
176
|
|
|
* @param boolean $reset If set to true, the current local configuration will be discarded first. |
|
177
|
|
|
* @see midcom_helper_configuration::reset_local() |
|
178
|
|
|
*/ |
|
179
|
1 |
|
public function store(array $params, bool $reset = true) |
|
180
|
|
|
{ |
|
181
|
1 |
|
if ( !$this->_object_stored |
|
182
|
1 |
|
&& $this->_object) { |
|
183
|
|
|
$this->_store_from_object(); |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
1 |
|
$this->_check_local_array($params); |
|
187
|
1 |
|
if ($reset) { |
|
188
|
|
|
$this->reset_local(); |
|
189
|
|
|
} |
|
190
|
1 |
|
$this->_local = array_merge($this->_local, $params); |
|
191
|
1 |
|
$this->_update_cache(); |
|
192
|
1 |
|
} |
|
193
|
|
|
|
|
194
|
|
|
/** |
|
195
|
|
|
* Import data from a Midgard object. |
|
196
|
|
|
* |
|
197
|
|
|
* To import configuration data from a Midgard Object, use this method. As in the |
|
198
|
|
|
* respective constructor it will retrieve the configuration data in the parameter |
|
199
|
|
|
* domain $path of $object. Unlike the constructor this function will store the |
|
200
|
|
|
* data in the local configuration. |
|
201
|
|
|
* |
|
202
|
|
|
* @param MidgardObject $object The object from which to import data. |
|
|
|
|
|
|
203
|
|
|
* @param string $path The parameter domain to query. |
|
204
|
|
|
* @param boolean $merge Should the existing local config be overridden or merged |
|
205
|
|
|
*/ |
|
206
|
378 |
|
public function store_from_object(object $object, string $path, bool $merge = false) |
|
207
|
|
|
{ |
|
208
|
378 |
|
$this->_object = $object; |
|
209
|
378 |
|
$this->_path = $path; |
|
210
|
378 |
|
$this->_store_from_object(false, $merge); |
|
211
|
378 |
|
} |
|
212
|
|
|
|
|
213
|
|
|
/** |
|
214
|
|
|
* Clear the local configuration data, effectively reverting to the global |
|
215
|
|
|
* default. |
|
216
|
|
|
*/ |
|
217
|
|
|
public function reset_local() |
|
218
|
|
|
{ |
|
219
|
|
|
$this->_local = []; |
|
220
|
|
|
$this->_merged = $this->_global; |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* Retrieve a configuration key |
|
225
|
|
|
* |
|
226
|
|
|
* If $key exists in the configuration data, its value is returned to the caller. |
|
227
|
|
|
* If the value does not exist, the boolean value false will be returned. Be aware |
|
228
|
|
|
* that this is not always good for error checking, since "false" is a perfectly good |
|
229
|
|
|
* value in the configuration data. Do error checking with the function exists (see |
|
230
|
|
|
* below). |
|
231
|
|
|
* |
|
232
|
|
|
* @param string $key The configuration key to query. |
|
233
|
|
|
* @return mixed Its value or false, if the key doesn't exist. |
|
234
|
|
|
* @see midcom_helper_configuration::exists() |
|
235
|
|
|
*/ |
|
236
|
480 |
|
public function get(string $key) |
|
237
|
|
|
{ |
|
238
|
480 |
|
if ($this->exists($key)) { |
|
239
|
480 |
|
return $this->_merged[$key]; |
|
240
|
|
|
} |
|
241
|
11 |
|
return false; |
|
242
|
|
|
} |
|
243
|
|
|
|
|
244
|
241 |
|
public function get_array(string $key) : array |
|
245
|
|
|
{ |
|
246
|
241 |
|
if ($value = $this->get($key)) { |
|
247
|
238 |
|
if (!is_array($value)) { |
|
248
|
|
|
throw new midcom_error('Config key "' . $key . '" is not an array'); |
|
249
|
|
|
} |
|
250
|
238 |
|
return $value; |
|
251
|
|
|
} |
|
252
|
12 |
|
return []; |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
/** |
|
256
|
|
|
* Set a value on the current instance, if the given key exists |
|
257
|
|
|
*/ |
|
258
|
17 |
|
public function set(string $key, $value) |
|
259
|
|
|
{ |
|
260
|
17 |
|
if ($this->exists($key)) { |
|
261
|
17 |
|
$this->_local[$key] = $value; |
|
262
|
17 |
|
$this->_update_cache(); |
|
263
|
|
|
} |
|
264
|
17 |
|
} |
|
265
|
|
|
|
|
266
|
|
|
/** |
|
267
|
|
|
* Retrieve a copy the complete configuration array. |
|
268
|
|
|
*/ |
|
269
|
2 |
|
public function get_all() : array |
|
270
|
|
|
{ |
|
271
|
2 |
|
if ( !$this->_object_stored |
|
272
|
2 |
|
&& $this->_object) { |
|
273
|
|
|
$this->_store_from_object(); |
|
274
|
|
|
} |
|
275
|
|
|
|
|
276
|
2 |
|
return $this->_merged; |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
/** |
|
280
|
|
|
* Checks for the existence of a configuration key. |
|
281
|
|
|
*/ |
|
282
|
480 |
|
public function exists(string $key) : bool |
|
283
|
|
|
{ |
|
284
|
480 |
|
if ( !$this->_object_stored |
|
285
|
480 |
|
&& $this->_object) { |
|
286
|
|
|
$this->_store_from_object(); |
|
287
|
|
|
} |
|
288
|
|
|
|
|
289
|
480 |
|
return array_key_exists($key, $this->_merged); |
|
290
|
|
|
} |
|
291
|
|
|
} |
|
292
|
|
|
|
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths