Container::val()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * Container.php
5
 *
6
 * Jaxon DI container. Provide container service for Jaxon classes.
7
 *
8
 * @package jaxon-core
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
 */
14
15
namespace Jaxon\Di;
16
17
use Jaxon\App\I18n\Translator;
18
use Jaxon\App\Session\SessionInterface;
19
use Jaxon\Exception\SetupException;
20
use Lagdo\Facades\ContainerWrapper;
21
use Pimple\Container as PimpleContainer;
22
use Psr\Container\ContainerInterface;
23
use Psr\Log\LoggerInterface;
24
use Psr\Log\NullLogger;
25
use Closure;
26
use Throwable;
27
28
use function dirname;
29
use function is_a;
30
31
class Container implements ContainerInterface
32
{
33
    use Traits\AppTrait;
34
    use Traits\PsrTrait;
35
    use Traits\RequestTrait;
36
    use Traits\ResponseTrait;
37
    use Traits\PluginTrait;
38
    use Traits\CallableTrait;
39
    use Traits\ViewTrait;
40
    use Traits\UtilTrait;
41
    use Traits\MetadataTrait;
42
    use Traits\DiAutoTrait;
43
44
    /**
45
     * The library Dependency Injection Container
46
     *
47
     * @var PimpleContainer
48
     */
49
    private $xLibContainer;
50
51
    /**
52
     * The application or framework Dependency Injection Container
53
     *
54
     * @var ContainerInterface
55
     */
56
    private $xAppContainer = null;
57
58
    /**
59
     * The class constructor
60
     */
61
    public function __construct()
62
    {
63
        $this->xLibContainer = new PimpleContainer();
64
65
        // The container instance is saved in the container.
66
        $this->val(Container::class, $this);
67
68
        // Register the null logger by default
69
        $this->setLogger(new NullLogger());
70
71
        // Setup the logger facade. Don't overwrite if it's already set.
72
        ContainerWrapper::setContainer($this, false);
73
74
        $sBaseDir = dirname(__DIR__, 2);
75
        // Template directory
76
        $this->val('jaxon.core.dir.template', "$sBaseDir/templates");
77
78
        // Translation directory
79
        $this->val('jaxon.core.dir.translation', "$sBaseDir/translations");
80
81
        $this->registerAll();
82
        $this->setEventHandlers();
83
    }
84
85
    /**
86
     * The container for parameters
87
     *
88
     * @return Container
89
     */
90
    protected function cn(): Container
91
    {
92
        return $this;
93
    }
94
95
    /**
96
     * Register the values into the container
97
     *
98
     * @return void
99
     */
100
    private function registerAll()
101
    {
102
        $this->registerApp();
103
        $this->registerPsr();
104
        $this->registerRequests();
105
        $this->registerResponses();
106
        $this->registerPlugins();
107
        $this->registerCallables();
108
        $this->registerViews();
109
        $this->registerUtils();
110
        $this->registerMetadataReader();
111
    }
112
113
    /**
114
     * Set the logger
115
     *
116
     * @param LoggerInterface|Closure $xLogger
117
     *
118
     * @return void
119
     */
120
    public function setLogger(LoggerInterface|Closure $xLogger)
121
    {
122
        is_a($xLogger, LoggerInterface::class) ?
123
            $this->val(LoggerInterface::class, $xLogger) :
124
            $this->set(LoggerInterface::class, $xLogger);
125
    }
126
127
    /**
128
     * Get the logger
129
     *
130
     * @return LoggerInterface
131
     */
132
    public function getLogger(): LoggerInterface
133
    {
134
        return $this->get(LoggerInterface::class);
135
    }
136
137
    /**
138
     * Set the container provided by the integrated framework
139
     *
140
     * @param ContainerInterface $xContainer    The container implementation
141
     *
142
     * @return void
143
     */
144
    public function setContainer(ContainerInterface $xContainer)
145
    {
146
        $this->xAppContainer = $xContainer;
147
    }
148
149
    /**
150
     * Check if a class is defined in the container
151
     *
152
     * @param string $sClass    The full class name
153
     *
154
     * @return bool
155
     */
156
    public function h(string $sClass): bool
157
    {
158
        return $this->xLibContainer->offsetExists($sClass);
159
    }
160
161
    /**
162
     * Check if a class is defined in the container
163
     *
164
     * @param string $sClass    The full class name
165
     *
166
     * @return bool
167
     */
168
    public function has(string $sClass): bool
169
    {
170
        return $this->xAppContainer != null && $this->xAppContainer->has($sClass) ?
171
            true : $this->xLibContainer->offsetExists($sClass);
172
    }
173
174
    /**
175
     * Get a class instance
176
     *
177
     * @template T
178
     * @param class-string<T> $sClass The full class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
179
     *
180
     * @return T
181
     */
182
    public function g(string $sClass): mixed
183
    {
184
        return $this->xLibContainer->offsetGet($sClass);
185
    }
186
187
    /**
188
     * Get a class instance
189
     *
190
     * @template T
191
     * @param class-string<T> $sClass The full class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
192
     *
193
     * @return T
194
     * @throws SetupException
195
     */
196
    public function get(string $sClass): mixed
197
    {
198
        try
199
        {
200
            return $this->xAppContainer != null && $this->xAppContainer->has($sClass) ?
201
                $this->xAppContainer->get($sClass) : $this->xLibContainer->offsetGet($sClass);
202
        }
203
        catch(Throwable $e)
204
        {
205
            $xLogger = $this->g(LoggerInterface::class);
206
            $xTranslator = $this->g(Translator::class);
207
            $sMessage = $e->getMessage() . ': ' . $xTranslator->trans('errors.class.container', ['name' => $sClass]);
208
            $xLogger->error($e->getMessage(), ['message' => $sMessage]);
209
            throw new SetupException($sMessage);
210
        }
211
    }
212
213
    /**
214
     * Save a closure in the container
215
     *
216
     * @param string|class-string $sClass    The full class name
0 ignored issues
show
Documentation Bug introduced by
The doc comment string|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in string|class-string.
Loading history...
217
     * @param Closure $xClosure    The closure
218
     * @param bool $bIsSingleton
219
     *
220
     * @return void
221
     */
222
    public function set(string $sClass, Closure $xClosure, bool $bIsSingleton = true)
0 ignored issues
show
Unused Code introduced by
The parameter $xClosure 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

222
    public function set(string $sClass, /** @scrutinizer ignore-unused */ Closure $xClosure, bool $bIsSingleton = true)

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...
223
    {
224
        // Wrap the user closure into a new closure, so it can take this container as a parameter.
225
        $xClosure = fn() => $xClosure($this);
226
        $this->xLibContainer->offsetSet($sClass, $bIsSingleton ?
227
            $xClosure : $this->xLibContainer->factory($xClosure));
228
    }
229
230
    /**
231
     * Save a value in the container
232
     *
233
     * @param string|class-string $sKey    The key
0 ignored issues
show
Documentation Bug introduced by
The doc comment string|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in string|class-string.
Loading history...
234
     * @param mixed $xValue    The value
235
     *
236
     * @return void
237
     */
238
    public function val(string $sKey, $xValue)
239
    {
240
       $this->xLibContainer->offsetSet($sKey, $xValue);
241
    }
242
243
    /**
244
     * Set an alias in the container
245
     *
246
     * @param string|class-string $sAlias    The alias name
0 ignored issues
show
Documentation Bug introduced by
The doc comment string|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in string|class-string.
Loading history...
247
     * @param string|class-string $sClass    The class name
248
     *
249
     * @return void
250
     */
251
    public function alias(string $sAlias, string $sClass)
252
    {
253
        $this->set($sAlias, function($di) use ($sClass) {
254
            return $di->get($sClass);
255
        });
256
    }
257
258
    /**
259
     * Get the session manager
260
     *
261
     * @return SessionInterface|null
262
     */
263
    public function getSessionManager(): ?SessionInterface
264
    {
265
        return $this->h(SessionInterface::class) ? $this->g(SessionInterface::class) : null;
266
    }
267
268
    /**
269
     * Set the session manager
270
     *
271
     * @param Closure $xClosure    A closure to create the session manager instance
272
     *
273
     * @return void
274
     */
275
    public function setSessionManager(Closure $xClosure)
276
    {
277
        $this->set(SessionInterface::class, $xClosure);
278
    }
279
}
280