Passed
Branch master (8bf58c)
by Korotkov
02:01
created

Rudra::serviceList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author    : Jagepard <[email protected]">
7
 * @license   https://mit-license.org/ MIT
8
 */
9
10
namespace Rudra\Container;
11
12
use Rudra\Container\Interfaces\RudraInterface;
13
use Rudra\Container\Interfaces\RequestInterface;
14
use Rudra\Container\Interfaces\ResponseInterface;
15
use Rudra\Container\Interfaces\ContainerInterface;
16
use Rudra\Container\Traits\InstantiationsTrait;
17
18
class Rudra implements RudraInterface, ContainerInterface
19
{
20
    use InstantiationsTrait;
21
22
    public static ?RudraInterface $rudra = null;
23
24
    /**
25
     * Creates a container to associate interfaces with implementations
26
     * ----------------------------------------------------------------
27
     * Создает контейнер для связи интерфейсов с реализациями
28
     * 
29
     * @param  array              $contracts
30
     * @return ContainerInterface
31
     */
32
    public function binding(array $contracts = []): ContainerInterface
33
    {
34
        return $this->containerize("binding", Container::class, $contracts);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->containerize('bin...ner::class, $contracts) targeting Rudra\Container\Rudra::containerize() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->containeri...ner::class, $contracts) returns the type void which is incompatible with the type-hinted return Rudra\Container\Interfaces\ContainerInterface.
Loading history...
35
    }
36
37
    /**
38
     * Creates a container with a list of services
39
     * -------------------------------------------
40
     * Создает контейнер со списком серверов
41
     * 
42
     * @param  array              $services
43
     * @return ContainerInterface
44
     */
45
    public function serviceList(array $services = []): ContainerInterface
46
    {
47
        return $this->containerize("services", Container::class, $services);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->containerize('ser...iner::class, $services) targeting Rudra\Container\Rudra::containerize() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->containeri...iner::class, $services) returns the type void which is incompatible with the type-hinted return Rudra\Container\Interfaces\ContainerInterface.
Loading history...
48
    }
49
    
50
    /**
51
     * Creates a configuration container
52
     * ---------------------------------
53
     * Создает контейнер конфигураций
54
     * 
55
     * @param  array              $config
56
     * @return ContainerInterface
57
     */
58
    public function config(array $config = []): ContainerInterface
59
    {
60
        return $this->containerize("config", Container::class, $config);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->containeri...tainer::class, $config) returns the type void which is incompatible with the type-hinted return Rudra\Container\Interfaces\ContainerInterface.
Loading history...
Bug introduced by
Are you sure the usage of $this->containerize('con...tainer::class, $config) targeting Rudra\Container\Rudra::containerize() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
61
    }
62
63
    /**
64
     * Creates a configuration container
65
     * ---------------------------------
66
     * Создает контейнер конфигураций
67
     * 
68
     * @param  array              $data
69
     * @return ContainerInterface
70
     */
71
    public function data(array $data = []): ContainerInterface
72
    {
73
        return $this->containerize("data", Container::class, $data);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->containerize('dat...ontainer::class, $data) targeting Rudra\Container\Rudra::containerize() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->containeri...ontainer::class, $data) returns the type void which is incompatible with the type-hinted return Rudra\Container\Interfaces\ContainerInterface.
Loading history...
74
    }
75
    
76
    /**
77
     * Initializes the service for the HTTP / 1.1 Common Method Kit
78
     * -----------------------------------------------
79
     * Инициализирует сервис для HTTP/1.1 Common Method Kit
80
     * 
81
     * @return RequestInterface
82
     */
83
    public function request(): RequestInterface
84
    {
85
        return $this->init(Request::class);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->init(Rudra\Container\Request::class) targeting Rudra\Container\Rudra::init() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->init(Rudra...ntainer\Request::class) returns the type void which is incompatible with the type-hinted return Rudra\Container\Interfaces\RequestInterface.
Loading history...
86
    }
87
88
    /**
89
     * Initializes the service for different types of responses
90
     * ------------------------------------------------
91
     * Инициализирует сервис для разных типов ответов
92
     * 
93
     * @return ResponseInterface
94
     */
95
    public function response(): ResponseInterface
96
    {
97
        return $this->init(Response::class);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->init(Rudra\Container\Response::class) targeting Rudra\Container\Rudra::init() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->init(Rudra...tainer\Response::class) returns the type void which is incompatible with the type-hinted return Rudra\Container\Interfaces\ResponseInterface.
Loading history...
98
    }
99
100
    /**
101
     * Initializes the cookie service
102
     * -------------------------------------------
103
     * Инициализирует сервис для работы с cookie
104
     * 
105
     * @return Cookie
106
     */
107
    public function cookie(): Cookie
108
    {
109
        return $this->init(Cookie::class);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->init(Rudra\Container\Cookie::class) returns the type void which is incompatible with the type-hinted return Rudra\Container\Cookie.
Loading history...
Bug introduced by
Are you sure the usage of $this->init(Rudra\Container\Cookie::class) targeting Rudra\Container\Rudra::init() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
110
    }
111
112
    /**
113
     * Initializes the service for working with sessions
114
     * -------------------------------------------------
115
     * Инициализирует сервис для работы с сессиями
116
     * 
117
     * @return Session
118
     */
119
    public function session(): Session
120
    {
121
        return $this->init(Session::class);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->init(Rudra\Container\Session::class) targeting Rudra\Container\Rudra::init() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->init(Rudra...ntainer\Session::class) returns the type void which is incompatible with the type-hinted return Rudra\Container\Session.
Loading history...
122
    }
123
124
    /**
125
     * Creates an object without adding to the container
126
     * -------------------------------------------------
127
     * Создает объект без добавления в контейнер
128
     * 
129
     * @param  string     $object
130
     * @param  array|null $params
131
     * @return object
132
     */
133
    public function new(string $object, ?array $params = null): object
134
    {
135
        $reflection = new \ReflectionClass($object);
136
        $constructor = $reflection->getConstructor();
137
138
        if ($constructor && $constructor->getNumberOfParameters()) {
139
            $paramsIoC = $this->getParamsIoC($constructor, $params);
140
141
            return $reflection->newInstanceArgs($paramsIoC);
142
        }
143
144
        return new $object();
145
    }
146
147
    /**
148
     * Creates the main application singleton
149
     * --------------------------------------
150
     * Создает основной синглтон приложения
151
     * 
152
     * @return RudraInterface
153
     */
154
    public static function run(): RudraInterface
155
    {
156
        if (!static::$rudra instanceof static) {
157
            static::$rudra = new static();
158
        }
159
160
        return static::$rudra;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::rudra could return the type null which is incompatible with the type-hinted return Rudra\Container\Interfaces\RudraInterface. Consider adding an additional type-check to rule them out.
Loading history...
161
    }
162
163
    /**
164
     * Gets a service by key, or an array of services if no key is specified
165
     * ---------------------------------------------------------------------
166
     * Получает сервис по ключу или массив сервисов, если ключ не указан
167
     * 
168
     * @param  string|null $key
169
     * @return void
170
     */
171
    public function get(string $key = null)
172
    {
173
        if (isset($key) && !$this->has($key)) {
174
            if (!$this->serviceList()->has($key)) {
175
                if (class_exists($key)) {
176
                    $this->serviceList()->set([$key => $key]);
177
                } else {
178
                    throw new \InvalidArgumentException("Service '$key' is not installed");
179
                }
180
            }
181
182
            $this->set([$key, $this->serviceList()->get($key)]);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->serviceList()->get($key) targeting Rudra\Container\Interfac...ntainerInterface::get() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
183
        }
184
185
        if (empty($key)) {
186
            return $this->services;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->services returns the type array which is incompatible with the documented return type void.
Loading history...
187
        }
188
189
        return ($this->services[$key] instanceof \Closure) ? $this->services[$key]() : $this->services[$key];
190
    }
191
192
    /**
193
     * Adds a service to an application
194
     * --------------------------------
195
     * Добавляет сервис в приложение
196
     * 
197
     * @param  array $data
198
     * @return void
199
     */
200
    public function set(array $data): void
201
    {
202
        list($key, $object) = $data;
203
204
        if (is_array($object)) {
205
            if (array_key_exists(1, $object) && !is_object($object[0])) {
206
                $this->iOc($key, $object[0], $object[1]);
207
                return;
208
            }
209
210
            $this->setObject($key, $object[0]);
211
            return;
212
        }
213
214
        $this->setObject($key, $object);
215
    }
216
217
    /**
218
     * Checks for the existence of a service
219
     * -------------------------------------
220
     * Проверяет наличие сервиса
221
     * 
222
     * @param  string  $key
223
     * @return boolean
224
     */
225
    public function has(string $key): bool
226
    {
227
        return array_key_exists($key, $this->services);
228
    }
229
230
    /**
231
     * Sets an object
232
     * --------------
233
     * Устанавливает объект
234
     *
235
     * @param  string        $key
236
     * @param  string|object $object
237
     * @return void
238
     */
239
    private function setObject(string $key, string|object $object): void
240
    {
241
        (is_object($object)) ? $this->mergeData($key, $object) : $this->iOc($key, $object);
242
    }
243
244
    /**
245
     * Combines data
246
     * -------------
247
     * Объединяет данные
248
     *
249
     * @param  string $key
250
     * @param  object $object
251
     * @return void
252
     */
253
    private function mergeData(string $key, object $object): void
254
    {
255
        $this->services = array_merge([$key => $object], $this->services);
256
    }
257
258
259
    /**
260
     * Creates an object using inversion of control
261
     * --------------------------------------------
262
     * Создает объект при помощи инверсии контроля
263
     *
264
     * @param  string     $key
265
     * @param  string     $object
266
     * @param  array|null $params
267
     * @return void
268
     */
269
    private function iOc(string $key, string $object, ?array $params = null): void
270
    {
271
        $reflection = new \ReflectionClass($object);
272
        $constructor = $reflection->getConstructor();
273
274
        if ($constructor && $constructor->getNumberOfParameters()) {
275
            $paramsIoC = $this->getParamsIoC($constructor, $params);
276
            $this->mergeData($key, $reflection->newInstanceArgs($paramsIoC));
277
            return;
278
        }
279
280
        $this->mergeData($key, new $object());
281
    }
282
283
    /**
284
     * Gets parameters using inversion of control
285
     * ------------------------------------------
286
     * Получает параметры при помощи инверсии контроля
287
     *
288
     * @param  \ReflectionMethod $constructor
289
     * @param  array             $params
290
     * @return array
291
     */
292
    private function getParamsIoC(\ReflectionMethod $constructor, ?array $params): array
293
    {
294
        $i = 0;
295
        $paramsIoC = [];
296
        $params = (is_array($params) && array_key_exists(0, $params)) ? $params : [$params];
297
298
        foreach ($constructor->getParameters() as $value) {
299
            /*
300
             | If in the constructor expects the implementation of interface,
301
             | so that the container automatically created the necessary object and substituted as an argument,
302
             | we need to bind the interface with the implementation.
303
             */
304
            if (version_compare(PHP_VERSION, '8.0.0') >= 0) {
305
                if (null !== $value->getType()->getName() && $this->binding()->has($value->getType()->getName())) {
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

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

305
                if (null !== $value->getType()->/** @scrutinizer ignore-call */ getName() && $this->binding()->has($value->getType()->getName())) {
Loading history...
306
                    $className = $this->binding()->get($value->getType()->getName());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $className is correct as $this->binding()->get($v...->getType()->getName()) targeting Rudra\Container\Interfac...ntainerInterface::get() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
307
                    $paramsIoC[] = (is_object($className)) ? $className : new $className;
308
                    continue;
309
                }
310
            } else {
311
                if (isset($value->getClass()->name) && $this->binding()->has($value->getClass()->name)) {
312
                    $className = $this->binding()->get($value->getClass()->name);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $className is correct as $this->binding()->get($value->getClass()->name) targeting Rudra\Container\Interfac...ntainerInterface::get() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
313
                    $paramsIoC[] = (is_object($className)) ? $className : new $className;
314
                    continue;
315
                }
316
            }
317
318
            /*
319
             | If the class constructor contains arguments with default values,
320
             | then if no arguments are passed,
321
             | values will be added by default by container
322
             */
323
            if ($value->isDefaultValueAvailable() && !isset($params[$i])) {
324
                $paramsIoC[] = $value->getDefaultValue();
325
                continue;
326
            }
327
328
            $paramsIoC[] = $params[$i++];
329
        }
330
331
        return $paramsIoC;
332
    }
333
}
334