Passed
Push — main ( 120722...2226e2 )
by Thierry
10:15
created

PackageManager::registerExceptionHandlers()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 5
rs 10
cc 3
nc 2
nop 1
1
<?php
2
3
/**
4
 * PackageManager.php - Jaxon package manager
5
 *
6
 * Register Jaxon plugins, packages and callables from a config file.
7
 *
8
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
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
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
14
15
namespace Jaxon\Plugin\Manager;
16
17
use Jaxon\Jaxon;
18
use Jaxon\App\Config\ConfigManager;
19
use Jaxon\App\I18n\Translator;
20
use Jaxon\App\View\ViewRenderer;
21
use Jaxon\Di\Container;
22
use Jaxon\Exception\SetupException;
23
use Jaxon\Plugin\Code\CodeGenerator;
24
use Jaxon\Plugin\Package;
25
use Jaxon\Request\Handler\CallbackManager;
26
use Jaxon\Utils\Config\Config;
27
28
use function is_array;
29
use function is_callable;
30
use function is_integer;
31
use function is_string;
32
use function is_subclass_of;
33
use function trim;
34
35
class PackageManager
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class PackageManager
Loading history...
36
{
37
    /**
38
     * @var Container
39
     */
40
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
41
42
    /**
43
     * @var PluginManager
44
     */
45
    protected $xPluginManager;
46
47
    /**
48
     * @var CallbackManager
49
     */
50
    protected $xCallbackManager;
51
52
    /**
53
     * @var ConfigManager
54
     */
55
    protected $xConfigManager;
56
57
    /**
58
     * @var CodeGenerator
59
     */
60
    private $xCodeGenerator;
61
62
    /**
63
     * @var ViewRenderer
64
     */
65
    protected $xViewRenderer;
66
67
    /**
68
     * @var Translator
69
     */
70
    protected $xTranslator;
71
72
    /**
73
     * The constructor
74
     *
75
     * @param Container $di
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
76
     * @param PluginManager $xPluginManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
77
     * @param ConfigManager $xConfigManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
78
     * @param CallbackManager $xCallbackManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
79
     * @param CodeGenerator $xCodeGenerator
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
80
     * @param ViewRenderer $xViewRenderer
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
81
     * @param Translator $xTranslator
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
82
     */
83
    public function __construct(Container $di, PluginManager $xPluginManager,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
84
        ConfigManager $xConfigManager, CallbackManager $xCallbackManager,
85
        CodeGenerator $xCodeGenerator, ViewRenderer $xViewRenderer, Translator $xTranslator)
86
    {
87
        $this->di = $di;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 15 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
88
        $this->xPluginManager = $xPluginManager;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
89
        $this->xConfigManager = $xConfigManager;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
90
        $this->xCallbackManager = $xCallbackManager;
91
        $this->xCodeGenerator = $xCodeGenerator;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
92
        $this->xViewRenderer = $xViewRenderer;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
93
        $this->xTranslator = $xTranslator;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
94
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
95
96
    /**
97
     * Save items in the DI container
98
     *
99
     * @param Config $xConfig
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
100
     *
101
     * @return void
102
     */
103
    private function updateContainer(Config $xConfig)
104
    {
105
        $aOptions = $xConfig->getOption('container.set', []);
106
        foreach($aOptions as $xKey => $xValue)
107
        {
108
            // The key is the class name. It must be a string.
109
            $this->di->set((string)$xKey, $xValue);
110
        }
111
        $aOptions = $xConfig->getOption('container.val', []);
112
        foreach($aOptions as $xKey => $xValue)
113
        {
114
            // The key is the class name. It must be a string.
115
            $this->di->val((string)$xKey, $xValue);
116
        }
117
        $aOptions = $xConfig->getOption('container.auto', []);
118
        foreach($aOptions as $xValue)
119
        {
120
            // The key is the class name. It must be a string.
121
            $this->di->auto((string)$xValue);
122
        }
123
        $aOptions = $xConfig->getOption('container.alias', []);
124
        foreach($aOptions as $xKey => $xValue)
125
        {
126
            // The key is the class name. It must be a string.
127
            $this->di->alias((string)$xKey, (string)$xValue);
128
        }
129
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
130
131
    /**
132
     * Register callables from a section of the config
133
     *
134
     * @param array $aOptions    The content of the config section
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter name; 4 found
Loading history...
135
     * @param string $sCallableType    The type of callable to register
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
136
     *
137
     * @return void
138
     * @throws SetupException
139
     */
140
    private function registerCallables(array $aOptions, string $sCallableType)
141
    {
142
        foreach($aOptions as $xKey => $xValue)
143
        {
144
            if(is_integer($xKey) && is_string($xValue))
145
            {
146
                // Register a function without options
147
                $this->xPluginManager->registerCallable($sCallableType, $xValue);
148
            }
149
            elseif(is_string($xKey) && (is_array($xValue) || is_string($xValue)))
150
            {
151
                // Register a function with options
152
                $this->xPluginManager->registerCallable($sCallableType, $xKey, $xValue);
153
            }
154
        }
155
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
156
157
    /**
158
     * Register exceptions handlers
159
     *
160
     * @param Config $xConfig
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
161
     *
162
     * @return void
163
     */
164
    private function registerExceptionHandlers(Config $xConfig)
165
    {
166
        foreach($xConfig->getOption('exceptions', []) as $sExClass => $xExHandler)
167
        {
168
            $this->xCallbackManager->error($xExHandler, is_string($sExClass) ? $sExClass : '');
169
        }
170
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
171
172
    /**
173
     * Read and set Jaxon options from a JSON config file
174
     *
175
     * @param Config $xConfig The config options
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
176
     * @param Config|null $xUserConfig The user provided package options
177
     *
178
     * @return void
179
     * @throws SetupException
180
     */
181
    private function registerItemsFromConfig(Config $xConfig, ?Config $xUserConfig = null)
182
    {
183
        // Register functions, classes and directories
184
        $this->registerCallables($xConfig->getOption('functions', []), Jaxon::CALLABLE_FUNCTION);
185
        $this->registerCallables($xConfig->getOption('classes', []), Jaxon::CALLABLE_CLASS);
186
        $this->registerCallables($xConfig->getOption('directories', []), Jaxon::CALLABLE_DIR);
187
        // Register the view namespaces
188
        // Note: the $xUserConfig can provide a "template" option, which is used to customize
189
        // the user defined view namespaces. That's why it is needed here.
190
        $this->xViewRenderer->addNamespaces($xConfig, $xUserConfig);
191
        // Save items in the DI container
192
        $this->updateContainer($xConfig);
193
        // Register the exception handlers
194
        $this->registerExceptionHandlers($xConfig);
195
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
196
197
    /**
198
     * Get the options provided by the package library
199
     *
200
     * @param string $sClassName    The package class
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
201
     *
202
     * @return Config
203
     * @throws SetupException
204
     */
205
    private function getPackageLibConfig(string $sClassName): Config
206
    {
207
        // $this->aPackages contains packages config file paths.
208
        $aLibOptions = $sClassName::config();
209
        if(is_string($aLibOptions))
210
        {
211
            // A string is supposed to be the path to a config file.
212
            $aLibOptions = $this->xConfigManager->read($aLibOptions);
213
        }
214
        elseif(!is_array($aLibOptions))
215
        {
216
            // Otherwise, anything else than an array is not accepted.
217
            $sMessage = $this->xTranslator->trans('errors.register.invalid', ['name' => $sClassName]);
218
            throw new SetupException($sMessage);
219
        }
220
        // Add the package name to the config
221
        $aLibOptions['package'] = $sClassName;
222
        return $this->xConfigManager->newConfig($aLibOptions);
223
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
224
225
    /**
226
     * Get the options provided by the package user
227
     *
228
     * @param array $aUserOptions    The user provided options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
229
     *
230
     * @return Config
231
     * @throws SetupException
232
     */
233
    private function getPackageUserConfig(array $aUserOptions): Config
234
    {
235
        $xOptionsProvider = $aUserOptions['provider'] ?? null;
236
        // The user can provide a callable that returns the package options.
237
        if(is_callable($xOptionsProvider))
238
        {
239
            $aUserOptions = $xOptionsProvider($aUserOptions);
240
        }
241
        return $this->xConfigManager->newConfig($aUserOptions);
242
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
243
244
    /**
245
     * Register a package
246
     *
247
     * @param string $sClassName    The package class
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
248
     * @param array $aUserOptions    The user provided package options
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
249
     *
250
     * @return void
251
     * @throws SetupException
252
     */
253
    public function registerPackage(string $sClassName, array $aUserOptions)
254
    {
255
        $sClassName = trim($sClassName, '\\ ');
256
        if(!is_subclass_of($sClassName, Package::class))
257
        {
258
            $sMessage = $this->xTranslator->trans('errors.register.invalid', ['name' => $sClassName]);
259
            throw new SetupException($sMessage);
260
        }
261
262
        // Register the declarations in the package config.
263
        $xAppConfig = $this->getPackageLibConfig($sClassName);
264
        $xUserConfig = $this->getPackageUserConfig($aUserOptions);
265
        $this->registerItemsFromConfig($xAppConfig, $xUserConfig);
266
        // Register the package and its options in the DI
267
        $this->di->registerPackage($sClassName, $xUserConfig);
268
269
        // Register the package as a code generator.
270
        $this->xCodeGenerator->addCodeGenerator($sClassName, 500);
271
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
272
273
    /**
274
     * Get a package instance
275
     *
276
     * @param string $sClassName    The package class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
277
     *
278
     * @return Package|null
279
     */
280
    public function getPackage(string $sClassName): ?Package
281
    {
282
        $sClassName = trim($sClassName, '\\ ');
283
        return $this->di->h($sClassName) ? $this->di->g($sClassName) : null;
284
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
285
286
    /**
287
     * Read and set Jaxon options from the config
288
     *
289
     * @param Config $xAppConfig    The config options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
290
     *
291
     * @return void
292
     * @throws SetupException
293
     */
294
    public function registerFromConfig(Config $xAppConfig)
295
    {
296
        $this->registerItemsFromConfig($xAppConfig);
297
298
        // Register packages
299
        $aPackageConfig = $xAppConfig->getOption('packages', []);
300
        foreach($aPackageConfig as $sClassName => $aPkgOptions)
301
        {
302
            $this->registerPackage($sClassName, $aPkgOptions);
303
        }
304
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
305
}
306