30 private $methodParams;
33 private $listSourceParameters;
35 private $reflectionFunctionAbstract;
37 private static $autoWiredHandlers =
null;
45 public function __construct($instance, $method, array $listSourceParameters)
47 $this->instance = $instance;
48 $this->method = $method;
49 $this->listSourceParameters = $listSourceParameters;
51 self::registerDefaultAutoWirings();
54 if ($instance ===
null)
56 $this->buildReflectionFunction();
60 $this->buildReflectionMethod();
66 private static function registerDefaultAutoWirings()
68 static $isAlreadyRegistered =
false;
69 if ($isAlreadyRegistered)
74 $isAlreadyRegistered =
true;
75 self::registerParameter(
85 return AutoWire\Binder::buildForFunction($callable)
86 ->setSourcesParametersToMap($listSourceParameters);
89 final public static function buildForMethod($instance, $method, array $listSourceParameters)
91 return AutoWire\Binder::buildForMethod($instance, $method)
92 ->setSourcesParametersToMap($listSourceParameters);
95 final public static function registerParameter($className, \Closure $constructObjectByClassAndId)
97 self::registerDefaultAutoWirings();
99 $dependsOnParameter =
new AutoWire\Parameter($className, $constructObjectByClassAndId);
100 AutoWire\Binder::registerGlobalAutoWiredParameter($dependsOnParameter);
102 self::$autoWiredHandlers[$className] = array(
103 'onConstructObjectByClassAndId' => $constructObjectByClassAndId,
104 'onConstructIdParameterName' => self::ANY_PARAMETER_NAME,
110 self::registerDefaultAutoWirings();
113 $className, $constructObjectByClassAndId, $constructIdParameterName
115 AutoWire\Binder::registerGlobalAutoWiredParameter($dependsOnParameter);
117 self::$autoWiredHandlers[$className] = array(
118 'onConstructObjectByClassAndId' => $constructObjectByClassAndId,
119 'onConstructIdParameterName' => $constructIdParameterName,
127 private function buildReflectionMethod()
129 $this->reflectionFunctionAbstract = new \ReflectionMethod($this->instance, $this->method);
130 $this->reflectionFunctionAbstract->setAccessible(
true);
133 private function buildReflectionFunction()
135 $this->reflectionFunctionAbstract = new \ReflectionFunction($this->method);
142 static::EVENT_ON_BUILD_AUTO_WIRED_CLASSES,
147 $autoWiredHandler = array();
148 foreach ($event->getResults() as $eventResult)
150 $parameters = $eventResult->getParameters();
151 foreach ($parameters as $handler)
153 if (empty($handler[
'class']))
158 if (empty($handler[
'onConstructObjectByClassAndId']) || !is_callable($handler[
'onConstructObjectByClassAndId'],
true))
163 if (empty($handler[
'onConstructIdParameterName']))
165 $handler[
'onConstructIdParameterName'] =
function(\ReflectionParameter $parameter){
166 return $parameter->getName() .
'Id';
170 !is_callable($handler[
'onConstructIdParameterName'],
true) &&
171 $handler[
'onConstructIdParameterName'] !== self::ANY_PARAMETER_NAME)
176 $autoWiredHandler[$handler[
'class']] = array(
177 'onConstructObjectByClassAndId' => $handler[
'onConstructObjectByClassAndId'],
178 'onConstructIdParameterName' => $handler[
'onConstructIdParameterName'],
183 return $autoWiredHandler;
192 if ($this->methodParams ===
null)
197 return $this->methodParams;
208 $this->methodParams = $params;
209 $this->args = array_values($params);
220 if ($this->args ===
null)
236 if ($this->reflectionFunctionAbstract instanceof \ReflectionMethod)
238 return $this->reflectionFunctionAbstract->invokeArgs($this->instance, $this->
getArgs());
240 if ($this->reflectionFunctionAbstract instanceof \ReflectionFunction)
242 return $this->reflectionFunctionAbstract->invokeArgs($this->
getArgs());
245 catch (\TypeError $exception)
247 $this->processException($exception);
249 catch (\ErrorException $exception)
251 $this->processException($exception);
257 private function processException($exception)
259 if (!($exception instanceof \TypeError) && !($exception instanceof \ErrorException))
265 mb_stripos($exception->getMessage(),
'must be an instance of') ===
false ||
266 mb_stripos($exception->getMessage(),
'null given') ===
false
272 $message = $this->extractParameterClassName($exception->getMessage());
274 throw new ObjectNotFoundException(
275 "Could not find value for class {{$message}} to build auto wired argument",
276 $exception instanceof \TypeError?
null : $exception
280 private function extractParameterClassName($message)
282 if (preg_match(
'%must be an instance of ([a-zA-Z0-9_\\\\]+), null given%', $message, $m))
290 private function buildReflectionClass(\ReflectionParameter $parameter): ?\ReflectionClass
292 $namedType = $parameter->getType();
293 if (!($namedType instanceof \ReflectionNamedType))
297 if ($namedType->isBuiltin())
302 return new \ReflectionClass($namedType->getName());
305 private function getParameterValue(\ReflectionParameter $parameter)
307 $autoWiredHandler =
null;
308 $reflectionClass = $this->buildReflectionClass($parameter);
309 if ($reflectionClass)
311 $autoWiredHandler = $this->getAutoWiredHandler($reflectionClass);
314 if ($autoWiredHandler && $reflectionClass)
317 if($autoWiredHandler[
'onConstructIdParameterName'] !== self::ANY_PARAMETER_NAME)
319 $parameterName = call_user_func_array($autoWiredHandler[
'onConstructIdParameterName'], array($parameter));
320 $primaryId = $this->findParameterInSourceList($parameterName, $status);
321 if ($status === self::STATUS_NOT_FOUND)
323 if ($parameter->isDefaultValueAvailable())
325 return $parameter->getDefaultValue();
328 throw new ArgumentException(
329 "Could not find value for parameter {{$parameterName}} to build auto wired argument {{$reflectionClass->name} {$parameter->getName()}}",
335 return call_user_func_array(
336 $autoWiredHandler[
'onConstructObjectByClassAndId'],
337 array($reflectionClass->getName(), $primaryId)
341 $value = $this->findParameterInSourceList($parameter->getName(), $status);
342 if ($status === self::STATUS_NOT_FOUND)
344 if ($parameter->isDefaultValueAvailable())
346 $value = $parameter->getDefaultValue();
350 throw new ArgumentException(
351 "Could not find value for parameter {{$parameter->getName()}}",
357 if ($parameter->isArray())
359 $value = (array)$value;
370 $this->listSourceParameters = $listSourceParameters;
371 $this->args = $this->methodParams =
null;
376 private function findParameterInSourceList($name, &$status)
379 foreach ($this->listSourceParameters as $source)
381 if (isset($source[$name]))
383 return $source[$name];
386 if (($source instanceof \ArrayAccess) && $source->offsetExists($name))
388 return $source[$name];
390 if (is_array($source) && array_key_exists($name, $source))
392 return $source[$name];
401 private function bindParams()
403 $this->args = $this->methodParams = array();
405 foreach ($this->reflectionFunctionAbstract->getParameters() as $param)
407 $value = $this->getParameterValue($param);
408 $this->args[] = $this->methodParams[$param->getName()] = $value;
414 private function getAutoWiredHandler(\ReflectionClass $class)
416 foreach (self::$autoWiredHandlers as $autoWiredClass => $handler)
418 if ($class->isSubclassOf($autoWiredClass) || $class->name === ltrim($autoWiredClass,
'\\'))
427 private function isAutoWiredClass(\ReflectionClass $class)
429 return (
bool)$this->getAutoWiredHandler($class);
__construct($instance, $method, array $listSourceParameters)
static buildForFunction($callable, array $listSourceParameters)
static registerParameter($className, \Closure $constructObjectByClassAndId)
static registerParameterDependsOnName($className, \Closure $constructObjectByClassAndId, \Closure $constructIdParameterName=null)
static buildForMethod($instance, $method, array $listSourceParameters)
setListSourceParameters($listSourceParameters)
const EVENT_ON_BUILD_AUTO_WIRED_CLASSES
setMethodParams(array $params)