1 | <?php |
||
42 | class ConfigManager implements ConfigManagementInterface |
||
43 | { |
||
44 | /** |
||
45 | * Default priority used with addConfigFile method. |
||
46 | */ |
||
47 | const PRIORITY_DEFAULT = 1000; |
||
48 | /** |
||
49 | * ConfigManager constructor. |
||
50 | * |
||
51 | * @param ContainerInterface $dic Container instance. |
||
52 | * @param array $settings Additional parameters or objects from non-config file source. Normally only |
||
53 | * used internal by Yapeal-ng for things that need to be added but it should |
||
54 | * still be possible for an application developer to override them so they can |
||
55 | * not be added to the Container directly and end up being protected. Mostly |
||
56 | * things that need to be done at run time like cache/ and log/ directory paths. |
||
57 | */ |
||
58 | 19 | public function __construct(ContainerInterface $dic, array $settings = []) |
|
65 | /** |
||
66 | * Add a new config file candidate to be used during the composing of settings. |
||
67 | * |
||
68 | * This method is expected to be used with the update() method to change the config files used during the composing |
||
69 | * of settings. |
||
70 | * |
||
71 | * Though Yapeal-ng considers and treats all configuration files as optional the individual settings themselves are |
||
72 | * not and many of them if missing can cause it to not start, to fail, or possible cause other undefined behavior |
||
73 | * to happen instead. |
||
74 | * |
||
75 | * The behavior when adding the same config file with an absolute and relative path or more than one relative path |
||
76 | * is undefined and may change and is considered unsupported. It makes little sense to do so anyway but mentioned |
||
77 | * here so developers known to watch for this edge case. |
||
78 | * |
||
79 | * @param string $pathName Configuration file name with path. Path _should_ be absolute but it is not checked. |
||
80 | * @param int $priority An integer in the range 0 - PHP_INT_MAX with large number being a higher priority. |
||
81 | * The range between 100 and 100000 inclusively are reserved for application developer use |
||
82 | * with everything outside that range reserved for internal use only. |
||
83 | * @param bool $watched Flag to tell if file should be monitored for changes and updates or read initially and |
||
84 | * future changes ignored. Note that the $force flag of update() can be used to override |
||
85 | * this parameter. |
||
86 | * |
||
87 | * @return array Return the added config file candidate entry with 'priority' and 'watched'. |
||
88 | * @throws \InvalidArgumentException Throws this exception if you try adding the same $pathFile again. Use |
||
89 | * hasConfigFile() to see if entry already exists. |
||
90 | * @throws \LogicException |
||
91 | */ |
||
92 | 13 | public function addConfigFile(string $pathName, int $priority = self::PRIORITY_DEFAULT, bool $watched = true): array |
|
108 | /** |
||
109 | * @param string $pathName Configuration file name with path. |
||
110 | * @param bool $force Override watched flag. Allows checking of normally unwatched files. |
||
111 | * |
||
112 | * @return bool Returns true if config file was updated, else false |
||
113 | * @throws \InvalidArgumentException |
||
114 | * @throws \LogicException |
||
115 | */ |
||
116 | 12 | public function checkModifiedAndUpdate(string $pathName, bool $force = false): bool |
|
138 | /** |
||
139 | * The Create part of the CRUD interface. |
||
140 | * |
||
141 | * Creates a new Yapeal-ng config composed from the settings found in the given current config file(s). This would |
||
142 | * be the closest to the original mode of Yapeal-ng where all the config files are processed once and then use for |
||
143 | * the rest of the time. Both in the classic cron/scheduled task and when using 'yc Y:A' (Yapeal:AutoMagic) command |
||
144 | * this is the closest match to how they worked. All existing settings from the current known config files will be |
||
145 | * forgotten and the $configFiles list will be used to compose the new collection of settings. |
||
146 | * |
||
147 | * If you just need to update the processed config files look at using update() combined with addConfigFiles() and |
||
148 | * removeConfigFile(). |
||
149 | * |
||
150 | * One or more config file(s) must have been given and there must be some actual settings found after they have |
||
151 | * been processed or an exception will be thrown. |
||
152 | * |
||
153 | * The $configFiles parameter can be just a plain list (array) of config file names with directory paths. If given |
||
154 | * a plain list like this Yapeal-ng will use the default priority and watched modes as seen in the addConfigFile() |
||
155 | * method. An example of this would look something like this: |
||
156 | * |
||
157 | * <code> |
||
158 | * <?php |
||
159 | * ... |
||
160 | * $manager = new ConfigManager($dic); |
||
161 | * $configFiles = [ |
||
162 | * __DIR__ . '/yapealDefaults.yaml', |
||
163 | * dirname(__DIR__, 2) . '/config/yapeal.yaml' |
||
164 | * ]; |
||
165 | * $manager->create($configFiles); |
||
166 | * ... |
||
167 | * </code> |
||
168 | * |
||
169 | * An example that includes optional priority and watched flags: |
||
170 | * <code>> |
||
171 | * <?php |
||
172 | * ... |
||
173 | * $manager = new ConfigManager($dic); |
||
174 | * $configFiles = [ |
||
175 | * ['pathName' => __DIR__ . '/yapealDefaults.yaml', 'priority' => PHP_INT_MAX, 'watched' => false], |
||
176 | * ['pathName' => dirname(__DIR__, 2) . '/config/yapeal.yaml', 'priority' => 10], |
||
177 | * ['pathName' => __DIR__ . '/special/run.yaml'] |
||
178 | * ]; |
||
179 | * $manager->create($configFiles); |
||
180 | * ... |
||
181 | * </code> |
||
182 | * |
||
183 | * Including either 'priority' or 'watched' is optional and they will receive the same default value(s) as from |
||
184 | * addConfigFile() if not given. |
||
185 | * |
||
186 | * @param array $configFiles A list of config file names with optional priority and watched flag. See example for |
||
187 | * how to include them. |
||
188 | * |
||
189 | * @return bool |
||
190 | * @throws \DomainException |
||
191 | * @throws \InvalidArgumentException |
||
192 | * @throws \LogicException |
||
193 | */ |
||
194 | 13 | public function create(array $configFiles): bool |
|
215 | /** |
||
216 | * The Delete part of the CRUD interface. |
||
217 | * |
||
218 | * This both removes all the candidate config files and removes all of their settings so the Container retains only |
||
219 | * those settings it originally had when given. This does _not_ necessarily mean it is fully reset. The reason this |
||
220 | * can't provide a complete reset is that while the other config files were being used their settings might have |
||
221 | * been used in any created callable instances or as substitutions in the original. The only way to insure this |
||
222 | * does not happen would be to not use any substitutions or other settings from outside the original Container |
||
223 | * ones. This shouldn't be an issue as by default only an empty or nearly empty Container is normal given to the |
||
224 | * ConfigManager instance. I just wanted to clearly document this effect to remind myself and anyone else to use |
||
225 | * care when giving a non-empty Container to the ConfigManager instance and the ripple effects they can have and be |
||
226 | * effected by other things. |
||
227 | * |
||
228 | * @return bool |
||
229 | */ |
||
230 | 1 | public function delete(): bool |
|
236 | /** |
||
237 | * Allows checking if a config file candidate has already been added. |
||
238 | * |
||
239 | * @param string $pathName Configuration file name with path. Path _should_ be absolute but it is not checked. |
||
240 | * |
||
241 | * @return bool Returns true if candidate entry exist, false if unknown. |
||
242 | */ |
||
243 | 15 | public function hasConfigFile(string $pathName): bool |
|
247 | /** |
||
248 | * The Read part of the CRUD interface. |
||
249 | * |
||
250 | * Since the Container where the settings are kept is one of the main shared objects inside Yapeal-ng this is mostly |
||
251 | * redundant but used this method as a way to return only stuff added by the config files. |
||
252 | * |
||
253 | * @return array |
||
254 | */ |
||
255 | 2 | public function read(): array |
|
264 | /** |
||
265 | * Remove an existing config file candidate entry. |
||
266 | * |
||
267 | * This method is expected to be used with the update() method to change the config files used during the composing |
||
268 | * of settings. |
||
269 | * |
||
270 | * @param string $pathName Configuration file name with path. Path _should_ be absolute but it is not checked. |
||
271 | * |
||
272 | * @return array Return the removed config file candidate entry with 'priority' and 'watched'. |
||
273 | * @see addConfigFile() |
||
274 | * @throws \InvalidArgumentException Throw this exception if there is no matching entry found. Use hasConfigFile() |
||
275 | * to check if the candidate config file entry exists. |
||
276 | */ |
||
277 | 2 | public function removeConfigFile(string $pathName): array |
|
287 | /** |
||
288 | * @param ContainerInterface $value |
||
289 | * |
||
290 | * @return self Fluent interface |
||
291 | */ |
||
292 | 19 | public function setDic(ContainerInterface $value): self |
|
302 | /** |
||
303 | * Sets substitutions to require Yapeal prefix or to be more generic. |
||
304 | * |
||
305 | * @param bool $value |
||
306 | * |
||
307 | * @return self Fluent interface |
||
308 | * @see doSubstitutions() |
||
309 | */ |
||
310 | 1 | public function setMatchYapealOnly(bool $value = true): self |
|
315 | /** |
||
316 | * @param array $value |
||
317 | * |
||
318 | * @return self Fluent interface |
||
319 | */ |
||
320 | 19 | public function setSettings(array $value = []): self |
|
325 | /** |
||
326 | * The Update part of the CRUD interface. |
||
327 | * |
||
328 | * It is expected that this will see little or no use if Yapeal-ng is being used in the typical/original mode via |
||
329 | * direct calls to the Yapeal::autoMagic() method or manually running 'yc Y:A' from the command line but this |
||
330 | * method is expected to be used in a planned future Yapeal-ng daemon. This planned new daemon is one of the main |
||
331 | * reasons this interface and the implementing class are being created so it can be signaled to re-read it's |
||
332 | * configuration or even watch and auto-update it's configuration when it notices changes to any of the given |
||
333 | * config files. |
||
334 | * |
||
335 | * Note that it expected that the addConfigFile() and removeConfigFile() methods have been called already to change |
||
336 | * which config files will be used to compose the new settings. |
||
337 | * |
||
338 | * @param bool $force Override watched flag. Allows checking of normally unwatched files. |
||
339 | * |
||
340 | * @return bool |
||
341 | * @throws \InvalidArgumentException |
||
342 | * @throws \LogicException |
||
343 | */ |
||
344 | 10 | public function update(bool $force = false): bool |
|
360 | /** |
||
361 | * Looks for and replaces any {Yapeal.*} it finds in values with the corresponding other setting value. |
||
362 | * |
||
363 | * This will replace full value or part of the value. Examples: |
||
364 | * |
||
365 | * $settings = [ |
||
366 | * 'Yapeal.baseDir' => '/my/junk/path/Yapeal/', |
||
367 | * 'Yapeal.libDir' => '{Yapeal.baseDir}lib/' |
||
368 | * 'Yapeal.Sql.dir' => '{Yapeal.libDir}Sql/' |
||
369 | * ]; |
||
370 | * |
||
371 | * After doSubstitutions would be: |
||
372 | * |
||
373 | * $settings = [ |
||
374 | * 'Yapeal.baseDir' => '/my/junk/path/Yapeal/', |
||
375 | * 'Yapeal.libDir' => '/my/junk/path/Yapeal/lib/' |
||
376 | * 'Yapeal.Sql.dir' => '/my/junk/path/Yapeal/lib/Sql/' |
||
377 | * ]; |
||
378 | * |
||
379 | * Note that order in which subs are done is undefined so it could have |
||
380 | * done libDir first and then baseDir into both or done baseDir into libDir |
||
381 | * then libDir into Sql.dir. |
||
382 | * |
||
383 | * Subs from within $settings itself are used first with $dic used to |
||
384 | * fill-in as needed for any unknown ones. |
||
385 | * |
||
386 | * Subs are tried up to 25 times as long as any {Yapeal.*} are found before |
||
387 | * giving up to prevent infinite loop. |
||
388 | * |
||
389 | * @param array $settings |
||
390 | * |
||
391 | * @throws \InvalidArgumentException |
||
392 | */ |
||
393 | 10 | protected function doSubstitutions(array $settings) |
|
431 | /** |
||
432 | * Used to remove any parameters or objects that were added from config files. |
||
433 | */ |
||
434 | 10 | private function removeUnprotectedSettings() |
|
441 | /** |
||
442 | * Sorts config files by priority/path name order. |
||
443 | * |
||
444 | * Sorted the config files by their descending priority order (largest-smallest). If there are config files with |
||
445 | * equal priorities they will be sorted by descending path name order. |
||
446 | */ |
||
447 | 10 | private function sortConfigFiles() |
|
458 | /** |
||
459 | * @var array $configFiles |
||
460 | */ |
||
461 | private $configFiles; |
||
462 | /** |
||
463 | * @var ContainerInterface $dic |
||
464 | */ |
||
465 | private $dic; |
||
466 | /** |
||
467 | * Flag used while doing substitutions to decide if generic pattern or Yapeal prefixed one should be used. |
||
468 | * |
||
469 | * @var bool $matchYapealOnly |
||
470 | * @see doSubstitutions() |
||
471 | */ |
||
472 | private $matchYapealOnly; |
||
473 | /** |
||
474 | * List of Container keys that are protected from being overwritten. |
||
475 | * |
||
476 | * @var array $protectedKeys |
||
477 | */ |
||
478 | private $protectedKeys; |
||
479 | /** |
||
480 | * @var array $settings |
||
481 | */ |
||
482 | private $settings; |
||
483 | } |
||
484 |