|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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; |
|
|
|
|
|
|
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)]); |
|
|
|
|
|
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
if (empty($key)) { |
|
186
|
|
|
return $this->services; |
|
|
|
|
|
|
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())) { |
|
|
|
|
|
|
306
|
|
|
$className = $this->binding()->get($value->getType()->getName()); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
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.