Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
binder.php
1<?php
2
4
6
7class Binder
8{
9 const STATUS_FOUND = true;
10 const STATUS_NOT_FOUND = false;
11
12 private $instance;
13 private $method;
15 private $configuration = [];
17 private static $globalAutoWiredParameters;
19 private $autoWiredParameters = [];
21 private $reflectionFunctionAbstract;
23 private $methodParams = null;
25 private $args = null;
26
27 public function __construct($instance, $method, $configuration = [])
28 {
29 $this->instance = $instance;
30 $this->method = $method;
31 $this->configuration = $configuration;
32
33 if ($this->instance === null)
34 {
35 $this->buildReflectionFunction();
36 }
37 else
38 {
39 $this->buildReflectionMethod();
40 }
41
42 }
43
44 final public static function buildForFunction($callable, $configuration = [])
45 {
46 return new static(null, $callable, $configuration);
47 }
48
49 final public static function buildForMethod($instance, $method, $configuration = [])
50 {
51 return new static($instance, $method, $configuration);
52 }
53
54 private function buildReflectionMethod()
55 {
56 $this->reflectionFunctionAbstract = new \ReflectionMethod($this->instance, $this->method);
57 $this->reflectionFunctionAbstract->setAccessible(true);
58 }
59
60 private function buildReflectionFunction()
61 {
62 $this->reflectionFunctionAbstract = new \ReflectionFunction($this->method);
63 }
64
68 public function getInstance()
69 {
70 return $this->instance;
71 }
72
76 public function getMethod()
77 {
78 return $this->method;
79 }
80
84 public function getConfiguration()
85 {
86 return $this->configuration;
87 }
88
94 public function setConfiguration($configuration)
95 {
96 $this->configuration = $configuration;
97
98 return $this;
99 }
100
106 public function setAutoWiredParameters(array $parameters)
107 {
108 $this->autoWiredParameters = [];
109
110 foreach ($parameters as $parameter)
111 {
112 $this->appendAutoWiredParameter($parameter);
113 }
114
115 return $this;
116 }
117
118 public function appendAutoWiredParameter(Parameter $parameter)
119 {
120 $this->autoWiredParameters[] = $parameter;
121
122 return $this;
123 }
124
130 public static function registerGlobalAutoWiredParameter(Parameter $parameter)
131 {
132 if (self::$globalAutoWiredParameters === null)
133 {
134 self::$globalAutoWiredParameters = new \SplObjectStorage();
135 }
136
137 if (!self::$globalAutoWiredParameters->contains($parameter))
138 {
139 self::$globalAutoWiredParameters[$parameter] = $parameter;
140 }
141 }
142
147 public static function unRegisterGlobalAutoWiredParameter(Parameter $parameter): void
148 {
149 if (self::$globalAutoWiredParameters === null)
150 {
151 return;
152 }
153
154 if (self::$globalAutoWiredParameters->contains($parameter))
155 {
156 self::$globalAutoWiredParameters->detach($parameter);
157 }
158 }
159
160 private function getPriorityByParameter(Parameter $parameter)
161 {
162 return $parameter->getPriority();
163 }
164
168 public function getAutoWiredParameters()
169 {
170 return $this->autoWiredParameters;
171 }
172
173 public function setSourcesParametersToMap(array $parameters)
174 {
175 $this->configuration['sourceParameters'] = $parameters;
176
177 return $this;
178 }
179
181 {
182 return $this->configuration['sourceParameters']?: [];
183 }
184
185 public function appendSourcesParametersToMap(array $parameter)
186 {
187 if (!isset($this->configuration['sourceParameters']))
188 {
189 $this->configuration['sourceParameters'] = [];
190 }
191
192 $this->configuration['sourceParameters'][] = $parameter;
193
194 return $this;
195 }
196
201 final public function invoke()
202 {
203 try
204 {
205 if ($this->reflectionFunctionAbstract instanceof \ReflectionMethod)
206 {
207 return $this->reflectionFunctionAbstract->invokeArgs($this->instance, $this->getArgs());
208 }
209
210 if ($this->reflectionFunctionAbstract instanceof \ReflectionFunction)
211 {
212 return $this->reflectionFunctionAbstract->invokeArgs($this->getArgs());
213 }
214 }
215 catch (\TypeError $exception)
216 {
217 throw $exception;
218// $this->processException($exception);
219 }
220 catch (\ErrorException $exception)
221 {
222 throw $exception;
223// $this->processException($exception);
224 }
225
226 return null;
227 }
228
233 final public function getMethodParams()
234 {
235 if ($this->methodParams === null)
236 {
237 $this->bindParams();
238 }
239
240 return $this->methodParams;
241 }
242
249 final public function setMethodParams(array $params)
250 {
251 $this->methodParams = $params;
252 $this->args = array_values($params);
253
254 return $this;
255 }
256
261 final public function getArgs()
262 {
263 if ($this->args === null)
264 {
265 $this->bindParams();
266 }
267
268 return $this->args;
269 }
270
271 private function bindParams()
272 {
273 $this->args = $this->methodParams = [];
274
275 foreach ($this->reflectionFunctionAbstract->getParameters() as $param)
276 {
277 $value = $this->getParameterValue($param);
278 $this->args[] = $this->methodParams[$param->getName()] = $value;
279 }
280
281 return $this->args;
282 }
283
289 private function getAutoWiredByClass(\ReflectionParameter $reflectionParameter)
290 {
291 $result = new \SplPriorityQueue();
292 foreach ($this->getAllAutoWiredParameters() as $parameter)
293 {
294 if ($parameter->match($reflectionParameter))
295 {
296 $result->insert($parameter, $this->getPriorityByParameter($parameter));
297 }
298 }
299
300 return $result;
301 }
302
306 private function getAllAutoWiredParameters()
307 {
308 $list = $this->getAutoWiredParameters();
309 if (self::$globalAutoWiredParameters)
310 {
311 foreach (self::$globalAutoWiredParameters as $globalAutoWiredParameter)
312 {
313 $list[] = $globalAutoWiredParameter;
314 }
315 }
316
317 return $list;
318 }
319
320 protected function constructValue(\ReflectionParameter $parameter, Parameter $autoWireParameter, Result $captureResult): Result
321 {
322 $result = new Result();
323
324 $constructedValue = $autoWireParameter->constructValue($parameter, $captureResult);
325
326 $result->setData([
327 'value' => $constructedValue,
328 ]);
329
330 return $result;
331 }
332
333 private function getParameterValue(\ReflectionParameter $parameter)
334 {
335 $sourceParameters = $this->getSourcesParametersToMap();
336
337 $reflectionType = $parameter->getType();
338 if (
339 ($reflectionType instanceof \ReflectionUnionType)
340 || ($reflectionType instanceof \ReflectionIntersectionType)
341 )
342 {
343 throw new BinderArgumentException(
344 "Currently there is no support for union or intersection types {{$parameter->getName()}}",
345 $parameter
346 );
347 }
348
349 if (($reflectionType instanceof \ReflectionNamedType) && !$reflectionType->isBuiltin())
350 {
351 foreach ($this->getAutoWiredByClass($parameter) as $autoWireParameter)
352 {
353 $result = $autoWireParameter->captureData($parameter, $sourceParameters, $this->getAllAutoWiredParameters());
354 if (!$result->isSuccess())
355 {
356 continue;
357 }
358
359 $constructedValue = null;
360 $constructResult = $this->constructValue($parameter, $autoWireParameter, $result);
361 if ($constructResult->isSuccess())
362 {
363 ['value' => $constructedValue] = $constructResult->getData();
364 }
365
366 if ($constructedValue === null)
367 {
368 if ($parameter->allowsNull())
369 {
370 return null;
371 }
372
373 if ($parameter->isDefaultValueAvailable())
374 {
375 return $parameter->getDefaultValue();
376 }
377
378 throw new BinderArgumentException(
379 "Could not construct parameter {{$parameter->getName()}}",
380 $parameter,
381 $constructResult->getErrors(),
382 );
383 }
384
385 return $constructedValue;
386 }
387
388 if ($parameter->isDefaultValueAvailable())
389 {
390 return $parameter->getDefaultValue();
391 }
392
393 $exceptionMessage = "Could not find value for parameter to build auto wired argument {{$reflectionType->getName()} \${$parameter->getName()}}";
394 if (isset($result) && ($result instanceof Result) && $result->getErrorMessages())
395 {
396 $exceptionMessage = $result->getErrorMessages()[0];
397 }
398
399 throw new BinderArgumentException(
400 $exceptionMessage,
401 $parameter
402 );
403 }
404
405 $value = $this->findParameterInSourceList($parameter->getName(), $status);
406 if ($status === self::STATUS_NOT_FOUND)
407 {
408 if ($parameter->isDefaultValueAvailable())
409 {
410 return $parameter->getDefaultValue();
411 }
412
413 throw new BinderArgumentException(
414 "Could not find value for parameter {{$parameter->getName()}}",
415 $parameter
416 );
417 }
418 if ($reflectionType instanceof \ReflectionNamedType)
419 {
420 $declarationChecker = new TypeDeclarationChecker($reflectionType, $value);
421 if (!$declarationChecker->isSatisfied())
422 {
423 throw new BinderArgumentException(
424 "Invalid value {{$value}} to match with parameter {{$parameter->getName()}}. Should be value of type {$reflectionType->getName()}.",
425 $parameter
426 );
427 }
428 if ($declarationChecker->isArray())
429 {
430 $value = (array)$value;
431 }
432 }
433
434 return $value;
435 }
436
437 private function findParameterInSourceList($name, &$status)
438 {
439 $status = self::STATUS_FOUND;
440 foreach ($this->getSourcesParametersToMap() as $source)
441 {
442 if (isset($source[$name]))
443 {
444 return $source[$name];
445 }
446
447 if ($source instanceof \ArrayAccess && $source->offsetExists($name))
448 {
449 return $source[$name];
450 }
451
452 if (is_array($source) && array_key_exists($name, $source))
453 {
454 return $source[$name];
455 }
456 }
457
458 $status = self::STATUS_NOT_FOUND;
459
460 return null;
461 }
462}
static unRegisterGlobalAutoWiredParameter(Parameter $parameter)
Definition binder.php:147
appendSourcesParametersToMap(array $parameter)
Definition binder.php:185
appendAutoWiredParameter(Parameter $parameter)
Definition binder.php:118
static registerGlobalAutoWiredParameter(Parameter $parameter)
Definition binder.php:130
setConfiguration($configuration)
Definition binder.php:94
__construct($instance, $method, $configuration=[])
Definition binder.php:27
static buildForFunction($callable, $configuration=[])
Definition binder.php:44
setAutoWiredParameters(array $parameters)
Definition binder.php:106
static buildForMethod($instance, $method, $configuration=[])
Definition binder.php:49
setSourcesParametersToMap(array $parameters)
Definition binder.php:173
constructValue(\ReflectionParameter $parameter, Parameter $autoWireParameter, Result $captureResult)
Definition binder.php:320
constructValue(\ReflectionParameter $parameter, Result $captureResult, $newThis=null)
Definition parameter.php:47