Passed
Push — main ( 5eae70...95b356 )
by Thierry
04:13
created

ConfigManager::asset()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
c 0
b 0
f 0
nc 16
nop 5
dl 0
loc 20
rs 9.6111
1
<?php
2
3
/**
4
 * ConfigManager.php - Jaxon config reader
5
 *
6
 * Extends the config reader in the jaxon-config package, and provides exception handlers.
7
 *
8
 * @package jaxon-core
9
 * @author Thierry Feuzeu <[email protected]>
10
 * @copyright 2022 Thierry Feuzeu <[email protected]>
11
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
12
 * @link https://github.com/jaxon-php/jaxon-core
13
 */
14
15
namespace Jaxon\App\Config;
16
17
use Jaxon\App\I18n\Translator;
18
use Jaxon\Config\Config;
19
use Jaxon\Config\ConfigReader;
20
use Jaxon\Config\ConfigSetter;
21
use Jaxon\Config\Exception\DataDepth;
22
use Jaxon\Config\Exception\FileAccess;
23
use Jaxon\Config\Exception\FileContent;
24
use Jaxon\Config\Exception\FileExtension;
25
use Jaxon\Config\Exception\YamlExtension;
26
use Jaxon\Exception\SetupException;
27
28
use function dirname;
29
30
class ConfigManager
31
{
32
    /**
33
     * @var Config
34
     */
35
    protected $xLibConfig;
36
37
    /**
38
     * @var Config
39
     */
40
    protected $xAppConfig;
41
42
    /**
43
     * @var Config|null
44
     */
45
    private Config|null $xExportConfig = null;
46
47
    /**
48
     * The constructor
49
     *
50
     * @param array $aDefaultOptions
51
     * @param Translator $xTranslator
52
     * @param ConfigReader $xConfigReader
53
     * @param ConfigSetter $xConfigSetter
54
     * @param ConfigEventManager $xEventManager
55
     */
56
    public function __construct(array $aDefaultOptions, private Translator $xTranslator,
57
        private ConfigReader $xConfigReader, private ConfigSetter $xConfigSetter,
58
        private ConfigEventManager $xEventManager)
59
    {
60
        $this->xLibConfig = $xConfigSetter->newConfig($aDefaultOptions);
61
        $this->xAppConfig = $xConfigSetter->newConfig();
62
    }
63
64
    /**
65
     * Read a config file
66
     *
67
     * @param string $sConfigFile
68
     *
69
     * @return array
70
     * @throws SetupException
71
     */
72
    public function read(string $sConfigFile): array
73
    {
74
        try
75
        {
76
            return $this->xConfigReader->read($sConfigFile);
77
        }
78
        catch(YamlExtension $e)
79
        {
80
            $sMessage = $this->xTranslator->trans('errors.yaml.install');
81
            throw new SetupException($sMessage);
82
        }
83
        catch(FileExtension $e)
84
        {
85
            $sMessage = $this->xTranslator->trans('errors.file.extension', ['path' => $sConfigFile]);
86
            throw new SetupException($sMessage);
87
        }
88
        catch(FileAccess $e)
89
        {
90
            $sMessage = $this->xTranslator->trans('errors.file.access', ['path' => $sConfigFile]);
91
            throw new SetupException($sMessage);
92
        }
93
        catch(FileContent $e)
94
        {
95
            $sMessage = $this->xTranslator->trans('errors.file.content', ['path' => $sConfigFile]);
96
            throw new SetupException($sMessage);
97
        }
98
    }
99
100
    /**
101
     * Read options from a config file and set the library config
102
     *
103
     * @param string $sConfigFile The full path to the config file
104
     * @param string $sConfigSection The section of the config file to be loaded
105
     *
106
     * @return void
107
     * @throws SetupException
108
     */
109
    public function load(string $sConfigFile, string $sConfigSection = ''): void
110
    {
111
        try
112
        {
113
            // Read the options and save in the config.
114
            $this->xLibConfig = $this->xConfigSetter
115
                ->setOptions($this->xLibConfig, $this->read($sConfigFile), $sConfigSection);
116
            // Call the config change listeners.
117
            $this->xEventManager->libConfigChanged($this->xLibConfig, '');
118
        }
119
        catch(DataDepth $e)
120
        {
121
            $sMessage = $this->xTranslator->trans('errors.data.depth', [
122
                'key' => $e->sPrefix,
123
                'depth' => $e->nDepth,
124
            ]);
125
            throw new SetupException($sMessage);
126
        }
127
    }
128
129
    /**
130
     * Set the config options of the library
131
     *
132
     * @param array $aOptions
133
     * @param string $sNamePrefix A prefix for the config option names
134
     *
135
     * @return bool
136
     * @throws SetupException
137
     */
138
    public function setOptions(array $aOptions, string $sNamePrefix = ''): bool
139
    {
140
        try
141
        {
142
            $this->xLibConfig = $this->xConfigSetter
143
                ->setOptions($this->xLibConfig, $aOptions, $sNamePrefix);
144
            // Call the config change listeners.
145
            $this->xEventManager->libConfigChanged($this->xLibConfig, '');
146
            return $this->xLibConfig->changed();
147
        }
148
        catch(DataDepth $e)
149
        {
150
            $sMessage = $this->xTranslator->trans('errors.data.depth', [
151
                'key' => $e->sPrefix,
152
                'depth' => $e->nDepth,
153
            ]);
154
            throw new SetupException($sMessage);
155
        }
156
    }
157
158
    /**
159
     * Set the value of a config option
160
     *
161
     * @param string $sName The option name
162
     * @param mixed $xValue The option value
163
     *
164
     * @return void
165
     */
166
    public function setOption(string $sName, $xValue): void
167
    {
168
        $this->xLibConfig = $this->xConfigSetter
169
            ->setOption($this->xLibConfig, $sName, $xValue);
170
        // Call the config change listeners.
171
        $this->xEventManager->libConfigChanged($this->xLibConfig, $sName);
172
    }
173
174
    /**
175
     * Get the value of a config option
176
     *
177
     * @param string $sName The option name
178
     * @param mixed $xDefault The default value, to be returned if the option is not defined
179
     *
180
     * @return mixed
181
     */
182
    public function getOption(string $sName, $xDefault = null): mixed
183
    {
184
        return $this->xLibConfig->getOption($sName, $xDefault);
185
    }
186
187
    /**
188
     * Check the presence of a config option
189
     *
190
     * @param string $sName The option name
191
     *
192
     * @return bool
193
     */
194
    public function hasOption(string $sName): bool
195
    {
196
        return $this->xLibConfig->hasOption($sName);
197
    }
198
199
    /**
200
     * Get the names of the options matching a given prefix
201
     *
202
     * @param string $sPrefix The prefix to match
203
     *
204
     * @return array
205
     */
206
    public function getOptionNames(string $sPrefix): array
207
    {
208
        return $this->xLibConfig->getOptionNames($sPrefix);
209
    }
210
211
    /**
212
     * Set the value of a config option
213
     *
214
     * @param string $sName The option name
215
     * @param mixed $xValue The option value
216
     *
217
     * @return void
218
     */
219
    public function setAppOption(string $sName, $xValue): void
220
    {
221
        $this->xAppConfig = $this->xConfigSetter
222
            ->setOption($this->xAppConfig, $sName, $xValue);
223
        // Call the config change listeners.
224
        $this->xEventManager->appConfigChanged($this->xAppConfig, $sName);
225
    }
226
227
    /**
228
     * Get the application config
229
     *
230
     * @return Config
231
     */
232
    public function getAppConfig(): Config
233
    {
234
        return $this->xAppConfig;
235
    }
236
237
    /**
238
     * Set the application config options
239
     *
240
     * @param array $aAppOptions
241
     * @param string $sNamePrefix A prefix for the config option names
242
     *
243
     * @return bool
244
     */
245
    public function setAppOptions(array $aAppOptions, string $sNamePrefix = ''): bool
246
    {
247
        try
248
        {
249
            $this->xAppConfig = $this->xConfigSetter
250
                ->setOptions($this->xAppConfig, $aAppOptions, $sNamePrefix);
251
            // Call the config change listeners.
252
            $this->xEventManager->appConfigChanged($this->xAppConfig, '');
253
            return $this->xAppConfig->changed();
254
        }
255
        catch(DataDepth $e)
256
        {
257
            $sMessage = $this->xTranslator->trans('errors.data.depth', [
258
                'key' => $e->sPrefix,
259
                'depth' => $e->nDepth,
260
            ]);
261
            throw new SetupException($sMessage);
262
        }
263
    }
264
265
    /**
266
     * Get the value of an application config option
267
     *
268
     * @param string $sName The option name
269
     * @param mixed $xDefault The default value, to be returned if the option is not defined
270
     *
271
     * @return mixed
272
     */
273
    public function getAppOption(string $sName, $xDefault = null): mixed
274
    {
275
        return $this->xAppConfig->getOption($sName, $xDefault);
276
    }
277
278
    /**
279
     * Check the presence of an application config option
280
     *
281
     * @param string $sName The option name
282
     *
283
     * @return bool
284
     */
285
    public function hasAppOption(string $sName): bool
286
    {
287
        return $this->xAppConfig->hasOption($sName);
288
    }
289
290
    /**
291
     * Get the app options with a given prefix in a new config object
292
     *
293
     * @param string $sPrefix
294
     *
295
     * @return Config
296
     */
297
    public function getConfig(string $sPrefix): Config
298
    {
299
        return $this->xConfigSetter->newConfig($this->getAppOption($sPrefix, []));
300
    }
301
302
    /**
303
     * Create a new the config object
304
     *
305
     * @param array $aOptions     The options array
306
     * @param string $sNamePrefix A prefix for the config option names
307
     *
308
     * @return Config
309
     * @throws SetupException
310
     */
311
    public function newConfig(array $aOptions = [], string $sNamePrefix = ''): Config
312
    {
313
        try
314
        {
315
            return $this->xConfigSetter->newConfig($aOptions, $sNamePrefix);
316
        }
317
        catch(DataDepth $e)
318
        {
319
            $sMessage = $this->xTranslator->trans('errors.data.depth', [
320
                'key' => $e->sPrefix,
321
                'depth' => $e->nDepth,
322
            ]);
323
            throw new SetupException($sMessage);
324
        }
325
    }
326
327
    /**
328
     * Check if the remote logging is enabled
329
     *
330
     * @return bool
331
     */
332
    public function loggingEnabled(): bool
333
    {
334
        return $this->getAppOption('options.logging.enabled', false);
335
    }
336
337
    /**
338
     * @param string $sClassName
339
     *
340
     * @return void
341
     */
342
    public function addLibEventListener(string $sClassName): void
343
    {
344
        $this->xEventManager->addLibConfigListener($sClassName);
345
    }
346
347
    /**
348
     * @param string $sClassName
349
     *
350
     * @return void
351
     */
352
    public function addAppEventListener(string $sClassName): void
353
    {
354
        $this->xEventManager->addAppConfigListener($sClassName);
355
    }
356
357
    /**
358
     * Make the helpers functions available in the global namespace.
359
     *
360
     * @param bool $bForce
361
     *
362
     * @return void
363
     */
364
    public function globals(bool $bForce = false): void
365
    {
366
        if($bForce || $this->getAppOption('helpers.global', true))
367
        {
368
            require_once dirname(__DIR__, 2) . '/globals.php';
369
        }
370
    }
371
372
    /**
373
     * @return Config
374
     */
375
    public function getExportConfig(): Config
376
    {
377
        if($this->xExportConfig !== null)
378
        {
379
            return $this->xExportConfig;
380
        }
381
382
        // Copy the assets options in a new config object.
383
        return $this->xExportConfig = $this->hasAppOption('assets') ?
384
            $this->xConfigSetter->newConfig($this->getAppOption('assets')) :
385
            // Convert the options in the "lib" section to the same format as in the "app" section.
386
            $this->xConfigSetter->newConfig([
387
                'js' => $this->getOption('js.app'),
388
                'include' => $this->getOption('assets.include'),
389
            ]);
390
    }
391
392
    /**
393
     * Set the javascript or css asset
394
     *
395
     * @param bool $bExport    Whether to export the code in a file
396
     * @param bool $bMinify    Whether to minify the exported file
397
     * @param string $sUri     The URI to access the exported file
398
     * @param string $sDir     The directory where to create the file
399
     * @param string $sType    The asset type: "js" or "css"
400
     *
401
     * @return void
402
     */
403
    public function asset(bool $bExport, bool $bMinify,
404
        string $sUri = '', string $sDir = '', string $sType = ''): void
405
    {
406
        $sPrefix = $sType === 'js' || $sType === 'css' ? "assets.$sType" : 'assets';
407
        // Jaxon library settings
408
        $aJsOptions = [
409
            'export' => $bExport,
410
            'minify' => $bMinify,
411
        ];
412
        if($sUri !== '')
413
        {
414
            $aJsOptions['uri'] = $sUri;
415
        }
416
        if($sDir !== '')
417
        {
418
            $aJsOptions['dir'] = $sDir;
419
        }
420
421
        // The export options are saved in the "app" section of the config.
422
        $this->setAppOptions($aJsOptions, $sPrefix);
423
    }
424
}
425