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 | 529 | public function __construct($source, ?string $path = null) |
|
84 | { |
||
85 | 529 | if ($path !== null) { |
|
86 | 2 | $this->_object = $source; |
|
87 | 2 | $this->_path = $path; |
|
88 | 2 | $this->_store_from_object(true); |
|
89 | } else { |
||
90 | 529 | $this->_global = $source; |
|
91 | 529 | $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 | 401 | private function _store_from_object(bool $global = false, bool $merge = false) |
|
109 | { |
||
110 | // Cast to DBA type. |
||
111 | 401 | 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 | 401 | $array = $this->_object->list_parameters($this->_path); |
|
116 | |||
117 | 401 | if ($global) { |
|
118 | 2 | $this->_global = $merge ? array_merge($this->_global, $array) : $array; |
|
119 | } |
||
120 | |||
121 | 401 | $this->_check_local_array($array); |
|
122 | 401 | $this->_local = $merge ? array_merge($this->_local, $array) : $array; |
|
123 | 401 | $this->_update_cache(); |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * Merge the local and the global configuration arrays into the cache array. |
||
128 | */ |
||
129 | 412 | private function _update_cache() |
|
130 | { |
||
131 | 412 | $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 | 401 | private function _check_local_array(array $array) |
|
143 | { |
||
144 | 401 | $diff = array_keys(array_diff_key($array, $this->_global)); |
|
145 | 401 | 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. |
||
0 ignored issues
–
show
|
|||
183 | * @param string $path The parameter domain to query. |
||
184 | * @param boolean $merge Should the existing local config be overridden or merged |
||
185 | */ |
||
186 | 401 | public function store_from_object(object $object, string $path, bool $merge = false) |
|
187 | { |
||
188 | 401 | $this->_object = $object; |
|
189 | 401 | $this->_path = $path; |
|
190 | 401 | $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 | 490 | public function get(string $key) |
|
216 | { |
||
217 | 490 | if ($this->exists($key)) { |
|
218 | 489 | return $this->_merged[$key]; |
|
219 | } |
||
220 | 15 | return false; |
|
221 | } |
||
222 | |||
223 | 292 | public function get_array(string $key) : array |
|
224 | { |
||
225 | 292 | $value = $this->get($key) ?: []; |
|
226 | 292 | if (!is_array($value)) { |
|
227 | throw new midcom_error('Config key "' . $key . '" is not an array'); |
||
228 | } |
||
229 | 292 | 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 | 490 | public function exists(string $key) : bool |
|
255 | { |
||
256 | 490 | 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