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
|
531 |
|
public function __construct($source, ?string $path = null) |
84
|
|
|
{ |
85
|
531 |
|
if ($path !== null) { |
86
|
2 |
|
$this->_object = $source; |
87
|
2 |
|
$this->_path = $path; |
88
|
2 |
|
$this->_store_from_object(true); |
89
|
|
|
} else { |
90
|
531 |
|
$this->_global = $source; |
91
|
531 |
|
$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
|
403 |
|
private function _store_from_object(bool $global = false, bool $merge = false) |
109
|
|
|
{ |
110
|
|
|
// Cast to DBA type. |
111
|
403 |
|
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
|
403 |
|
$array = $this->_object->list_parameters($this->_path); |
116
|
|
|
|
117
|
403 |
|
if ($global) { |
118
|
2 |
|
$this->_global = $merge ? array_merge($this->_global, $array) : $array; |
119
|
|
|
} |
120
|
|
|
|
121
|
403 |
|
$this->_check_local_array($array); |
122
|
403 |
|
$this->_local = $merge ? array_merge($this->_local, $array) : $array; |
123
|
403 |
|
$this->_update_cache(); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Merge the local and the global configuration arrays into the cache array. |
128
|
|
|
*/ |
129
|
414 |
|
private function _update_cache() |
130
|
|
|
{ |
131
|
414 |
|
$this->_merged = array_merge($this->_global, $this->_local); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Check local data array for validity |
136
|
|
|
* |
137
|
|
|
* Since the local array must only include configuration parameters that are |
138
|
|
|
* included in the global configuration, this function is used to check a local |
139
|
|
|
* array against the current global configuration. true/false is returned |
140
|
|
|
* accordingly. |
141
|
|
|
*/ |
142
|
403 |
|
private function _check_local_array(array $array) |
143
|
|
|
{ |
144
|
403 |
|
$diff = array_keys(array_diff_key($array, $this->_global)); |
145
|
403 |
|
foreach ($diff as $key) { |
146
|
|
|
debug_add("The key {$key} is not present in the global configuration array.", MIDCOM_LOG_INFO); |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Write the parameters in $params into the local configuration. |
152
|
|
|
* |
153
|
|
|
* If $reset is set, the local configuration will be cleared before |
154
|
|
|
* the new set is imported, if not, the new data is merged with the old local |
155
|
|
|
* configuration, overwriting duplicates. During import each configuration key will |
156
|
|
|
* be checked against the global configuration values. If an unknown value is found, |
157
|
|
|
* import will be aborted and no changes to the configuration is done. |
158
|
|
|
* |
159
|
|
|
* After import the cache array will be updated, reset is done by reset_local. |
160
|
|
|
* |
161
|
|
|
* @param boolean $reset If set to true, the current local configuration will be discarded first. |
162
|
|
|
* @see midcom_helper_configuration::reset_local() |
163
|
|
|
*/ |
164
|
1 |
|
public function store(array $params, bool $reset = true) |
165
|
|
|
{ |
166
|
1 |
|
$this->_check_local_array($params); |
167
|
1 |
|
if ($reset) { |
168
|
|
|
$this->reset_local(); |
169
|
|
|
} |
170
|
1 |
|
$this->_local = array_merge($this->_local, $params); |
171
|
1 |
|
$this->_update_cache(); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Import data from a Midgard object. |
176
|
|
|
* |
177
|
|
|
* To import configuration data from a Midgard Object, use this method. As in the |
178
|
|
|
* respective constructor it will retrieve the configuration data in the parameter |
179
|
|
|
* domain $path of $object. Unlike the constructor this function will store the |
180
|
|
|
* data in the local configuration. |
181
|
|
|
* |
182
|
|
|
* @param MidgardObject $object The object from which to import data. |
|
|
|
|
183
|
|
|
* @param string $path The parameter domain to query. |
184
|
|
|
* @param boolean $merge Should the existing local config be overridden or merged |
185
|
|
|
*/ |
186
|
403 |
|
public function store_from_object(object $object, string $path, bool $merge = false) |
187
|
|
|
{ |
188
|
403 |
|
$this->_object = $object; |
189
|
403 |
|
$this->_path = $path; |
190
|
403 |
|
$this->_store_from_object(merge: $merge); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Clear the local configuration data, effectively reverting to the global |
195
|
|
|
* default. |
196
|
|
|
*/ |
197
|
|
|
public function reset_local() |
198
|
|
|
{ |
199
|
|
|
$this->_local = []; |
200
|
|
|
$this->_merged = $this->_global; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* Retrieve a configuration key |
205
|
|
|
* |
206
|
|
|
* If $key exists in the configuration data, its value is returned to the caller. |
207
|
|
|
* If the value does not exist, the boolean value false will be returned. Be aware |
208
|
|
|
* that this is not always good for error checking, since "false" is a perfectly good |
209
|
|
|
* value in the configuration data. Do error checking with the function exists (see |
210
|
|
|
* below). |
211
|
|
|
* |
212
|
|
|
* @return mixed Its value or false, if the key doesn't exist. |
213
|
|
|
* @see midcom_helper_configuration::exists() |
214
|
|
|
*/ |
215
|
492 |
|
public function get(string $key) |
216
|
|
|
{ |
217
|
492 |
|
if ($this->exists($key)) { |
218
|
491 |
|
return $this->_merged[$key]; |
219
|
|
|
} |
220
|
15 |
|
return false; |
221
|
|
|
} |
222
|
|
|
|
223
|
294 |
|
public function get_array(string $key) : array |
224
|
|
|
{ |
225
|
294 |
|
$value = $this->get($key) ?: []; |
226
|
294 |
|
if (!is_array($value)) { |
227
|
|
|
throw new midcom_error('Config key "' . $key . '" is not an array'); |
228
|
|
|
} |
229
|
294 |
|
return $value; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Set a value on the current instance, if the given key exists |
234
|
|
|
*/ |
235
|
21 |
|
public function set(string $key, $value) |
236
|
|
|
{ |
237
|
21 |
|
if ($this->exists($key)) { |
238
|
21 |
|
$this->_local[$key] = $value; |
239
|
21 |
|
$this->_update_cache(); |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Retrieve a copy the complete configuration array. |
245
|
|
|
*/ |
246
|
10 |
|
public function get_all() : array |
247
|
|
|
{ |
248
|
10 |
|
return $this->_merged; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Checks for the existence of a configuration key. |
253
|
|
|
*/ |
254
|
492 |
|
public function exists(string $key) : bool |
255
|
|
|
{ |
256
|
492 |
|
return array_key_exists($key, $this->_merged); |
257
|
|
|
} |
258
|
|
|
} |
259
|
|
|
|
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