Passed
Push — main ( aa41db...017a71 )
by Thierry
02:06
created

PackageManager::getPackageLibConfig()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 18
rs 10
cc 3
nc 3
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\Utils\Config\Config;
26
27
use function is_array;
28
use function is_callable;
29
use function is_integer;
30
use function is_string;
31
use function is_subclass_of;
32
use function trim;
33
34
class PackageManager
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class PackageManager
Loading history...
35
{
36
    /**
37
     * @var Container
38
     */
39
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
40
41
    /**
42
     * @var PluginManager
43
     */
44
    protected $xPluginManager;
45
46
    /**
47
     * @var ConfigManager
48
     */
49
    protected $xConfigManager;
50
51
    /**
52
     * @var CodeGenerator
53
     */
54
    private $xCodeGenerator;
55
56
    /**
57
     * @var ViewRenderer
58
     */
59
    protected $xViewRenderer;
60
61
    /**
62
     * @var Translator
63
     */
64
    protected $xTranslator;
65
66
    /**
67
     * The constructor
68
     *
69
     * @param Container $di
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
70
     * @param PluginManager $xPluginManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
71
     * @param ConfigManager $xConfigManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
72
     * @param CodeGenerator $xCodeGenerator
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
73
     * @param ViewRenderer $xViewRenderer
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
74
     * @param Translator $xTranslator
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...
75
     */
76
    public function __construct(Container $di, PluginManager $xPluginManager, ConfigManager $xConfigManager,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
77
        CodeGenerator $xCodeGenerator, ViewRenderer $xViewRenderer, Translator $xTranslator)
78
    {
79
        $this->di = $di;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 13 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...
80
        $this->xPluginManager = $xPluginManager;
81
        $this->xConfigManager = $xConfigManager;
82
        $this->xCodeGenerator = $xCodeGenerator;
83
        $this->xViewRenderer = $xViewRenderer;
84
        $this->xTranslator = $xTranslator;
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...
85
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
86
87
    /**
88
     * Save items in the DI container
89
     *
90
     * @param Config $xConfig
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
91
     *
92
     * @return void
93
     */
94
    private function updateContainer(Config $xConfig)
95
    {
96
        $aOptions = $xConfig->getOption('container.set', []);
97
        foreach($aOptions as $xKey => $xValue)
98
        {
99
            // The key is the class name. It must be a string.
100
            $this->di->set((string)$xKey, $xValue);
101
        }
102
        $aOptions = $xConfig->getOption('container.val', []);
103
        foreach($aOptions as $xKey => $xValue)
104
        {
105
            // The key is the class name. It must be a string.
106
            $this->di->val((string)$xKey, $xValue);
107
        }
108
        $aOptions = $xConfig->getOption('container.auto', []);
109
        foreach($aOptions as $xValue)
110
        {
111
            // The key is the class name. It must be a string.
112
            $this->di->auto((string)$xValue);
113
        }
114
        $aOptions = $xConfig->getOption('container.alias', []);
115
        foreach($aOptions as $xKey => $xValue)
116
        {
117
            // The key is the class name. It must be a string.
118
            $this->di->alias((string)$xKey, (string)$xValue);
119
        }
120
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
121
122
    /**
123
     * Register callables from a section of the config
124
     *
125
     * @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...
126
     * @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...
127
     *
128
     * @return void
129
     * @throws SetupException
130
     */
131
    private function registerCallables(array $aOptions, string $sCallableType)
132
    {
133
        foreach($aOptions as $xKey => $xValue)
134
        {
135
            if(is_integer($xKey) && is_string($xValue))
136
            {
137
                // Register a function without options
138
                $this->xPluginManager->registerCallable($sCallableType, $xValue);
139
            }
140
            elseif(is_string($xKey) && (is_array($xValue) || is_string($xValue)))
141
            {
142
                // Register a function with options
143
                $this->xPluginManager->registerCallable($sCallableType, $xKey, $xValue);
144
            }
145
        }
146
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
147
148
    /**
149
     * Read and set Jaxon options from a JSON config file
150
     *
151
     * @param Config $xConfig The config options
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
152
     * @param Config|null $xUserConfig The user provided package options
153
     *
154
     * @return void
155
     * @throws SetupException
156
     */
157
    private function registerItemsFromConfig(Config $xConfig, ?Config $xUserConfig = null)
158
    {
159
        // Register functions, classes and directories
160
        $this->registerCallables($xConfig->getOption('functions', []), Jaxon::CALLABLE_FUNCTION);
161
        $this->registerCallables($xConfig->getOption('classes', []), Jaxon::CALLABLE_CLASS);
162
        $this->registerCallables($xConfig->getOption('directories', []), Jaxon::CALLABLE_DIR);
163
        // Register the view namespaces
164
        // Note: the $xUserConfig can provide a "template" option, which is used to customize
165
        // the user defined view namespaces. That's why it is needed here.
166
        $this->xViewRenderer->addNamespaces($xConfig, $xUserConfig);
167
        // Save items in the DI container
168
        $this->updateContainer($xConfig);
169
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
170
171
    /**
172
     * Get the options provided by the package library
173
     *
174
     * @param string $sClassName    The package class
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
175
     *
176
     * @return Config
177
     * @throws SetupException
178
     */
179
    private function getPackageLibConfig(string $sClassName): Config
180
    {
181
        // $this->aPackages contains packages config file paths.
182
        $aLibOptions = $sClassName::config();
183
        if(is_string($aLibOptions))
184
        {
185
            // A string is supposed to be the path to a config file.
186
            $aLibOptions = $this->xConfigManager->read($aLibOptions);
187
        }
188
        elseif(!is_array($aLibOptions))
189
        {
190
            // Otherwise, anything else than an array is not accepted.
191
            $sMessage = $this->xTranslator->trans('errors.register.invalid', ['name' => $sClassName]);
192
            throw new SetupException($sMessage);
193
        }
194
        // Add the package name to the config
195
        $aLibOptions['package'] = $sClassName;
196
        return $this->xConfigManager->newConfig($aLibOptions);
197
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
198
199
    /**
200
     * Get the options provided by the package user
201
     *
202
     * @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...
203
     *
204
     * @return Config
205
     * @throws SetupException
206
     */
207
    private function getPackageUserConfig(array $aUserOptions): Config
208
    {
209
        $xOptionsProvider = $aUserOptions['provider'] ?? null;
210
        // The user can provide a callable that returns the package options.
211
        if(is_callable($xOptionsProvider))
212
        {
213
            $aUserOptions = $xOptionsProvider($aUserOptions);
214
        }
215
        return $this->xConfigManager->newConfig($aUserOptions);
216
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
217
218
    /**
219
     * Register a package
220
     *
221
     * @param string $sClassName    The package class
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
222
     * @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...
223
     *
224
     * @return void
225
     * @throws SetupException
226
     */
227
    public function registerPackage(string $sClassName, array $aUserOptions)
228
    {
229
        $sClassName = trim($sClassName, '\\ ');
230
        if(!is_subclass_of($sClassName, Package::class))
231
        {
232
            $sMessage = $this->xTranslator->trans('errors.register.invalid', ['name' => $sClassName]);
233
            throw new SetupException($sMessage);
234
        }
235
236
        // Register the declarations in the package config.
237
        $xAppConfig = $this->getPackageLibConfig($sClassName);
238
        $xUserConfig = $this->getPackageUserConfig($aUserOptions);
239
        $this->registerItemsFromConfig($xAppConfig, $xUserConfig);
240
        // Register the package and its options in the DI
241
        $this->di->registerPackage($sClassName, $xUserConfig);
242
243
        // Register the package as a code generator.
244
        $this->xCodeGenerator->addCodeGenerator($sClassName, 500);
245
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
246
247
    /**
248
     * Get a package instance
249
     *
250
     * @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...
251
     *
252
     * @return Package|null
253
     */
254
    public function getPackage(string $sClassName): ?Package
255
    {
256
        $sClassName = trim($sClassName, '\\ ');
257
        return $this->di->h($sClassName) ? $this->di->g($sClassName) : null;
258
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
259
260
    /**
261
     * Read and set Jaxon options from the config
262
     *
263
     * @param Config $xAppConfig    The config options
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
264
     *
265
     * @return void
266
     * @throws SetupException
267
     */
268
    public function registerFromConfig(Config $xAppConfig)
269
    {
270
        $this->registerItemsFromConfig($xAppConfig);
271
272
        // Register packages
273
        $aPackageConfig = $xAppConfig->getOption('packages', []);
274
        foreach($aPackageConfig as $sClassName => $aPkgOptions)
275
        {
276
            $this->registerPackage($sClassName, $aPkgOptions);
277
        }
278
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
279
}
280