Passed
Push — master ( baf979...6da3e4 )
by Thierry
03:26
created

Container::getParameter()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 19
rs 10
cc 4
nc 4
nop 2
1
<?php
2
3
/**
4
 * Container.php
5
 *
6
 * Jaxon DI container. Provide container service for Jaxon classes.
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 2016 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\Di;
16
17
use Jaxon\App\Ajax;
18
use Jaxon\App\I18n\Translator;
19
use Jaxon\App\Session\SessionInterface;
20
use Jaxon\Exception\SetupException;
21
use Pimple\Container as PimpleContainer;
22
use Psr\Container\ContainerInterface;
23
use Psr\Log\LoggerAwareInterface;
24
use Psr\Log\LoggerAwareTrait;
25
use Psr\Log\LoggerInterface;
26
use Psr\Log\NullLogger;
27
28
use Closure;
29
use Exception;
30
use ReflectionClass;
31
use ReflectionException;
32
use ReflectionNamedType;
33
use ReflectionParameter;
34
use Throwable;
35
36
use function array_map;
37
use function realpath;
38
39
class Container extends PimpleContainer implements LoggerAwareInterface
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class Container
Loading history...
40
{
41
    use LoggerAwareTrait;
42
43
    use Traits\AppTrait;
44
    use Traits\PsrTrait;
45
    use Traits\RequestTrait;
46
    use Traits\ResponseTrait;
47
    use Traits\PluginTrait;
48
    use Traits\CallableTrait;
49
    use Traits\RegisterTrait;
50
    use Traits\ViewTrait;
51
    use Traits\UtilTrait;
52
53
    /**
54
     * The Dependency Injection Container
55
     *
56
     * @var ContainerInterface
57
     */
58
    private $xContainer = null;
59
60
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $jaxon should have a doc-comment as per coding-style.
Loading history...
61
     * The class constructor
62
     */
63
    public function __construct(Ajax $jaxon)
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
64
    {
65
        parent::__construct();
66
67
        // Set the default logger
68
        $this->setLogger(new NullLogger());
69
70
        // Save the Ajax and Container instances
71
        $this->val(Ajax::class, $jaxon);
72
        $this->val(Container::class, $this);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
73
        // Register the logger
74
        $this->val(LoggerInterface::class, $this->logger);
75
76
        // Template directory
77
        $sTemplateDir = realpath(__DIR__ . '/../../templates');
78
        $this->val('jaxon.core.dir.template', $sTemplateDir);
79
80
        // Translation directory
81
        $sTranslationDir = realpath(__DIR__ . '/../../translations');
82
        $this->val('jaxon.core.dir.translation', $sTranslationDir);
83
84
        $this->registerAll();
85
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
86
87
    /**
88
     * Register the values into the container
89
     *
90
     * @return void
91
     */
92
    private function registerAll()
93
    {
94
        $this->registerApp();
95
        $this->registerPsr();
96
        $this->registerRequests();
97
        $this->registerResponses();
98
        $this->registerPlugins();
99
        $this->registerCallables();
100
        $this->registerViews();
101
        $this->registerUtils();
102
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
103
104
    /**
105
     * Get the logger
106
     *
107
     * @return LoggerInterface
108
     */
109
    public function getLogger(): LoggerInterface
110
    {
111
        return $this->logger;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->logger could return the type null which is incompatible with the type-hinted return Psr\Log\LoggerInterface. Consider adding an additional type-check to rule them out.
Loading history...
112
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
113
114
    /**
115
     * Set the container provided by the integrated framework
116
     *
117
     * @param ContainerInterface $xContainer    The container implementation
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
118
     *
119
     * @return void
120
     */
121
    public function setContainer(ContainerInterface $xContainer)
122
    {
123
        $this->xContainer = $xContainer;
124
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
125
126
    /**
127
     * Check if a class is defined in the container
128
     *
129
     * @param string $sClass    The full class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
130
     *
131
     * @return bool
132
     */
133
    public function h(string $sClass): bool
134
    {
135
        return $this->offsetExists($sClass);
136
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
137
138
    /**
139
     * Check if a class is defined in the container
140
     *
141
     * @param string $sClass    The full class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
142
     *
143
     * @return bool
144
     */
145
    public function has(string $sClass): bool
146
    {
147
        if($this->xContainer != null && $this->xContainer->has($sClass))
148
        {
149
            return true;
150
        }
151
        return $this->offsetExists($sClass);
152
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
153
154
    /**
155
     * Get a class instance
156
     *
157
     * @param string $sClass    The full class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
158
     *
159
     * @return mixed
160
     */
161
    public function g(string $sClass)
162
    {
163
        return $this->offsetGet($sClass);
164
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
165
166
    /**
167
     * Get a class instance
168
     *
169
     * @param string $sClass The full class name
170
     *
171
     * @return mixed
172
     * @throws SetupException
173
     */
174
    public function get(string $sClass)
175
    {
176
        try
177
        {
178
            if($this->xContainer != null && $this->xContainer->has($sClass))
179
            {
180
                return $this->xContainer->get($sClass);
181
            }
182
            return $this->offsetGet($sClass);
183
        }
184
        catch(Exception|Throwable $e)
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "|"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "|"; 0 found
Loading history...
185
        {
186
            $xLogger = $this->g(LoggerInterface::class);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 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...
187
            $xTranslator = $this->g(Translator::class);
188
            $sMessage = $e->getMessage() . ': ' . $xTranslator->trans('errors.class.container', ['name' => $sClass]);
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...
189
            $xLogger->error($e->getMessage(), ['message' => $sMessage]);
190
            throw new SetupException($sMessage);
191
        }
192
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
193
194
    /**
195
     * Save a closure in the container
196
     *
197
     * @param string $sClass    The full class name
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
198
     * @param Closure $xClosure    The closure
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
199
     *
200
     * @return void
201
     */
202
    public function set(string $sClass, Closure $xClosure)
203
    {
204
        $this->offsetSet($sClass, $xClosure);
205
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
206
207
    /**
208
     * Save a value in the container
209
     *
210
     * @param string $sKey    The key
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 4 found
Loading history...
211
     * @param mixed $xValue    The value
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...
212
     *
213
     * @return void
214
     */
215
    public function val(string $sKey, $xValue)
216
    {
217
        $this->offsetSet($sKey, $xValue);
218
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
219
220
    /**
221
     * Set an alias in the container
222
     *
223
     * @param string $sAlias    The alias name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
224
     * @param string $sClass    The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
225
     *
226
     * @return void
227
     */
228
    public function alias(string $sAlias, string $sClass)
229
    {
230
        $this->set($sAlias, function($c) use ($sClass) {
231
            return $c->get($sClass);
232
        });
233
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
234
235
    /**
236
     * @param ReflectionClass $xClass
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...
237
     * @param ReflectionParameter $xParameter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
238
     *
239
     * @return mixed
240
     * @throws SetupException
241
     */
242
    protected function getParameter(ReflectionClass $xClass, ReflectionParameter $xParameter)
0 ignored issues
show
Unused Code introduced by
The parameter $xClass is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

242
    protected function getParameter(/** @scrutinizer ignore-unused */ ReflectionClass $xClass, ReflectionParameter $xParameter)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
243
    {
244
        $xType = $xParameter->getType();
245
        // Check the parameter class first.
246
        if($xType instanceof ReflectionNamedType)
247
        {
248
            // Check the class + the name
249
            if($this->has($xType->getName() . ' $' . $xParameter->getName()))
250
            {
251
                return $this->get($xType->getName() . ' $' . $xParameter->getName());
252
            }
253
            // Check the class only
254
            if($this->get($xType->getName()))
255
            {
256
                return $this->get($xType->getName());
257
            }
258
        }
259
        // Check the name only
260
        return $this->get('$' . $xParameter->getName());
261
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
262
263
    /**
264
     * Create an instance of a class, getting the constructor parameters from the DI container
265
     *
266
     * @param string|ReflectionClass $xClass The class name or the reflection class
267
     *
268
     * @return object|null
269
     * @throws ReflectionException
270
     * @throws SetupException
271
     */
272
    public function make($xClass)
273
    {
274
        if(is_string($xClass))
275
        {
276
            $xClass = new ReflectionClass($xClass); // Create the reflection class instance
277
        }
278
        if(!($xClass instanceof ReflectionClass))
0 ignored issues
show
introduced by
$xClass is always a sub-type of ReflectionClass.
Loading history...
279
        {
280
            return null;
281
        }
282
        // Use the Reflection class to get the parameters of the constructor
283
        if(($constructor = $xClass->getConstructor()) === null)
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
284
        {
285
            return $xClass->newInstance();
286
        }
287
        $aParameterInstances = array_map(function($xParameter) use($xClass) {
288
            return $this->getParameter($xClass, $xParameter);
289
        }, $constructor->getParameters());
290
291
        return $xClass->newInstanceArgs($aParameterInstances);
292
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
293
294
    /**
295
     * Create an instance of a class by automatically fetching the dependencies in the constructor.
296
     *
297
     * @param string $sClass    The class name
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
298
     *
299
     * @return void
300
     */
301
    public function auto(string $sClass)
302
    {
303
        $this->set($sClass, function() use ($sClass) {
304
            return $this->make($sClass);
305
        });
306
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
307
308
    /**
309
     * Get the session manager
310
     *
311
     * @return SessionInterface|null
312
     */
313
    public function getSessionManager(): ?SessionInterface
314
    {
315
        return $this->h(SessionInterface::class) ? $this->g(SessionInterface::class) : null;
316
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
317
318
    /**
319
     * Set the session manager
320
     *
321
     * @param Closure $xClosure    A closure to create the session manager instance
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
322
     *
323
     * @return void
324
     */
325
    public function setSessionManager(Closure $xClosure)
326
    {
327
        $this->set(SessionInterface::class, $xClosure);
328
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
329
}
330