Generates list of arguments using autowiring.
public static autowireArguments ( ReflectionFunctionAbstract $method, array $arguments, $container ) : array | ||
$method | ReflectionFunctionAbstract | |
$arguments | array | |
return | array |
/** * @return Nette\Application\IResponse */ public function run(Application\Request $request) { $this->request = $request; if ($this->httpRequest && $this->router && !$this->httpRequest->isAjax() && ($request->isMethod('get') || $request->isMethod('head'))) { $refUrl = clone $this->httpRequest->getUrl(); $url = $this->router->constructUrl($request, $refUrl->setPath($refUrl->getScriptPath())); if ($url !== NULL && !$this->httpRequest->getUrl()->isEqual($url)) { return new Responses\RedirectResponse($url, Http\IResponse::S301_MOVED_PERMANENTLY); } } $params = $request->getParameters(); if (!isset($params['callback'])) { throw new Application\BadRequestException('Parameter callback is missing.'); } $params['presenter'] = $this; $callback = $params['callback']; $reflection = Nette\Utils\Callback::toReflection(Nette\Utils\Callback::check($callback)); $params = Application\UI\PresenterComponentReflection::combineArgs($reflection, $params); if ($this->context) { foreach ($reflection->getParameters() as $param) { if ($param->getClassName()) { unset($params[$param->getPosition()]); } } $params = Nette\DI\Helpers::autowireArguments($reflection, $params, $this->context); $params['presenter'] = $this; } $response = call_user_func_array($callback, $params); if (is_string($response)) { $response = array($response, array()); } if (is_array($response)) { list($templateSource, $templateParams) = $response; $response = $this->createTemplate()->setParameters($templateParams); if (!$templateSource instanceof \SplFileInfo) { $response->getLatte()->setLoader(new Latte\Loaders\StringLoader); } $response->setFile($templateSource); } if ($response instanceof Application\UI\ITemplate) { return new Responses\TextResponse($response); } else { return $response; } }
/** * @param $name * @return Nette\ComponentModel\IComponent * @throws Nette\UnexpectedValueException */ public function createComponent($name) { $sl = $this->getServiceLocatorForFactories(); $ucname = ucfirst($name); $method = 'createComponent' . $ucname; if ($ucname !== $name && method_exists($this, $method)) { $reflection = $this->getReflection()->getMethod($method); if ($reflection->getName() !== $method) { return; } $parameters = $reflection->parameters; $args = array(); if (($first = reset($parameters)) && !$first->className) { $args[] = $name; } $args = Nette\DI\Helpers::autowireArguments($reflection, $args, $sl); $component = call_user_func_array(array($this, $method), $args); if (!$component instanceof Nette\ComponentModel\IComponent && !isset($this->components[$name])) { throw new Nette\UnexpectedValueException("Method {$reflection} did not return or create the desired component."); } return $component; } }
/** * Formats PHP code for class instantiating, function calling or property setting in PHP. * @return string * @internal */ public function formatStatement(Statement $statement) { $entity = $this->normalizeEntity($statement->getEntity()); $arguments = $statement->arguments; if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal return $this->formatPhp($entity, $arguments); } elseif ($service = $this->getServiceName($entity)) { // factory calling $params = []; foreach ($this->definitions[$service]->parameters as $k => $v) { $params[] = preg_replace('#\\w+\\z#', '\\$$0', is_int($k) ? $v : $k) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v)); } $rm = new \ReflectionFunction(create_function(implode(', ', $params), '')); $arguments = Helpers::autowireArguments($rm, $arguments, $this); return $this->formatPhp('$this->?(?*)', [Container::getMethodName($service), $arguments]); } elseif ($entity === 'not') { // operator return $this->formatPhp('!?', [$arguments[0]]); } elseif (is_string($entity)) { // class name if ($constructor = (new ReflectionClass($entity))->getConstructor()) { $this->addDependency((string) $constructor->getFileName()); $arguments = Helpers::autowireArguments($constructor, $arguments, $this); } elseif ($arguments) { throw new ServiceCreationException("Unable to pass arguments, class {$entity} has no constructor."); } return $this->formatPhp("new {$entity}" . ($arguments ? '(?*)' : ''), [$arguments]); } elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) { throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity))); } elseif (!preg_match('#^\\$?' . PhpHelpers::PHP_IDENT . '\\z#', $entity[1])) { throw new ServiceCreationException("Expected function, method or property name, '{$entity['1']}' given."); } elseif ($entity[0] === '') { // globalFunc return $this->formatPhp("{$entity['1']}(?*)", [$arguments]); } elseif ($entity[0] instanceof Statement) { $inner = $this->formatPhp('?', [$entity[0]]); if (substr($inner, 0, 4) === 'new ') { $inner = "({$inner})"; } return $this->formatPhp("{$inner}->?(?*)", [$entity[1], $arguments]); } elseif (Strings::contains($entity[1], '$')) { // property setter Validators::assert($arguments, 'list:1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'"); if ($this->getServiceName($entity[0])) { return $this->formatPhp('?->? = ?', [$entity[0], substr($entity[1], 1), $arguments[0]]); } else { return $this->formatPhp($entity[0] . '::$? = ?', [substr($entity[1], 1), $arguments[0]]); } } elseif ($service = $this->getServiceName($entity[0])) { // service method $class = $this->definitions[$service]->getImplement(); if (!$class || !method_exists($class, $entity[1])) { $class = $this->definitions[$service]->getClass(); } if ($class) { $arguments = $this->autowireArguments($class, $entity[1], $arguments); } return $this->formatPhp('?->?(?*)', [$entity[0], $entity[1], $arguments]); } else { // static method $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments); return $this->formatPhp("{$entity['0']}::{$entity['1']}(?*)", [$arguments]); } }
/** * Calls method using autowiring. * @return mixed */ public function callMethod($function, array $args = array()) { return call_user_func_array($function, Helpers::autowireArguments(Nette\Utils\Callback::toReflection($function), $args, $this)); }
/** * Calls method using autowiring. * @param mixed class, object, function, callable * @param array arguments * @return mixed */ public function callMethod($function, array $args = array()) { $callback = new Nette\Callback($function); return $callback->invokeArgs(Helpers::autowireArguments($callback->toReflection(), $args, $this)); }
/** * Formats PHP code for class instantiating, function calling or property setting in PHP. * @return string * @internal */ public function formatStatement(Statement $statement, $self = NULL) { $entity = $this->normalizeEntity($statement->entity); $arguments = $statement->arguments; if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal return $this->formatPhp($entity, $arguments, $self); } elseif ($service = $this->getServiceName($entity)) { // factory calling or service retrieving if ($this->definitions[$service]->shared) { if ($arguments) { throw new ServiceCreationException("Unable to call service '{$entity}'."); } return $this->formatPhp('$this->getService(?)', array($service)); } $params = array(); foreach ($this->definitions[$service]->parameters as $k => $v) { $params[] = preg_replace('#\\w+$#', '\\$$0', is_int($k) ? $v : $k) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v)); } $rm = new Nette\Reflection\GlobalFunction(create_function(implode(', ', $params), '')); $arguments = Helpers::autowireArguments($rm, $arguments, $this); return $this->formatPhp('$this->?(?*)', array(Container::getMethodName($service, FALSE), $arguments), $self); } elseif ($entity === 'not') { // operator return $this->formatPhp('!?', array($arguments[0])); } elseif (is_string($entity)) { // class name if ($constructor = Nette\Reflection\ClassType::from($entity)->getConstructor()) { $this->addDependency($constructor->getFileName()); $arguments = Helpers::autowireArguments($constructor, $arguments, $this); } elseif ($arguments) { throw new ServiceCreationException("Unable to pass arguments, class {$entity} has no constructor."); } return $this->formatPhp("new {$entity}" . ($arguments ? '(?*)' : ''), array($arguments), $self); } elseif (!Validators::isList($entity) || count($entity) !== 2) { throw new Nette\InvalidStateException("Expected class, method or property, " . PhpHelpers::dump($entity) . " given."); } elseif ($entity[0] === '') { // globalFunc return $this->formatPhp("{$entity['1']}(?*)", array($arguments), $self); } elseif (Strings::contains($entity[1], '$')) { // property setter Validators::assert($arguments, 'list:1', "setup arguments for '" . Nette\Callback::create($entity) . "'"); if ($this->getServiceName($entity[0], $self)) { return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), $arguments[0]), $self); } else { return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), $arguments[0]), $self); } } elseif ($service = $this->getServiceName($entity[0], $self)) { // service method if ($this->definitions[$service]->class) { $arguments = $this->autowireArguments($this->definitions[$service]->class, $entity[1], $arguments); } return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments), $self); } else { // static method $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments); return $this->formatPhp("{$entity['0']}::{$entity['1']}(?*)", array($arguments), $self); } }
/** * Creates a list of arguments using autowiring. * * @return array */ public function autowireArguments($class, $method, array $arguments) { $rc = Nette\Reflection\ClassType::from($class); if (!$rc->hasMethod($method)) { if (!Nette\Utils\Validators::isList($arguments)) { throw new ServiceCreationException("Unable to pass specified arguments to {$class}::{$method}()."); } return $arguments; } $rm = $rc->getMethod($method); if ($rm->isAbstract() || !$rm->isPublic()) { throw new ServiceCreationException("{$rm} is not callable."); } $this->addDependency($rm->getFileName()); return Helpers::autowireArguments($rm, $arguments, $this); }
/** * Calls method using autowiring. * @return mixed */ public function callMethod(callable $function, array $args = []) { return $function(...Helpers::autowireArguments(Nette\Utils\Callback::toReflection($function), $args, $this)); }
/** * Formats PHP code for class instantiating, function calling or property setting in PHP. * @return string * @internal */ public function formatStatement(Statement $statement) { $entity = $this->normalizeEntity($statement->entity); $arguments = $statement->arguments; if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal return $this->formatPhp($entity, $arguments); } elseif ($service = $this->getServiceName($entity)) { // factory calling $params = array(); foreach ($this->definitions[$service]->parameters as $k => $v) { $params[] = preg_replace('#\w+\z#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v)); } $rm = new Reflection\GlobalFunction(create_function(implode(', ', $params), '')); $arguments = Helpers::autowireArguments($rm, $arguments, $this); return $this->formatPhp('$this->?(?*)', array(Container::getMethodName($service), $arguments)); } elseif ($entity === 'not') { // operator return $this->formatPhp('!?', array($arguments[0])); } elseif (is_string($entity)) { // class name if ($constructor = Reflection\ClassType::from($entity)->getConstructor()) { $this->addDependency($constructor->getFileName()); $arguments = Helpers::autowireArguments($constructor, $arguments, $this); } elseif ($arguments) { throw new ServiceCreationException("Unable to pass arguments, class $entity has no constructor."); } return $this->formatPhp("new $entity" . ($arguments ? '(?*)' : ''), array($arguments)); } elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) { throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity))); } elseif ($entity[0] === '') { // globalFunc return $this->formatPhp("$entity[1](?*)", array($arguments)); } elseif (Strings::contains($entity[1], '$')) { // property setter Validators::assert($arguments, 'list:1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'"); if ($this->getServiceName($entity[0])) { return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), $arguments[0])); } else { return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), $arguments[0])); } } elseif ($service = $this->getServiceName($entity[0])) { // service method $class = $this->definitions[$service]->implement; if (!$class || !method_exists($class, $entity[1])) { $class = $this->definitions[$service]->class; } if ($class) { $arguments = $this->autowireArguments($class, $entity[1], $arguments); } return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments)); } else { // static method $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments); return $this->formatPhp("$entity[0]::$entity[1](?*)", array($arguments)); } }
/** * Creates a list of arguments using autowiring. * @return array * @internal */ public function autowireArguments($class, $method, array $arguments) { $rc = new ReflectionClass($class); if (!$rc->hasMethod($method)) { if (!Nette\Utils\Arrays::isList($arguments)) { throw new ServiceCreationException("Unable to pass specified arguments to {$class}::{$method}()."); } return $arguments; } $rm = $rc->getMethod($method); if (!$rm->isPublic()) { throw new ServiceCreationException("{$class}::{$method}() is not callable."); } $this->addDependency($rm); return Helpers::autowireArguments($rm, $arguments, $this); }
function formatStatement(Statement $statement, $self = NULL) { $arguments = (array) $statement->arguments; if ($statement->entity instanceof PhpLiteral) { return $this->formatPhp('call_user_func_array(?, ?)', array($statement->entity, $arguments)); } $entity = explode('::', $statement->entity); if (strpos($statement->entity, '::') === FALSE && ($service = $this->getServiceName($statement->entity))) { if ($this->definitions[$service]->shared) { throw new ServiceCreationException("Unable to call service '{$statement->entity}'."); } $params = array(); foreach ($this->definitions[$service]->parameters as $k => $v) { $params[] = preg_replace('#\\w+$#', '\\$$0', is_int($k) ? $v : $k) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v)); } $rm = new \ReflectionFunction(create_function(implode(', ', $params), '')); $arguments = Helpers::autowireArguments($rm, $arguments, $this); return $this->formatPhp('$this->?(?*)', array('create' . ucfirst($service), $arguments), $self); } elseif (strpos($statement->entity, '::') === FALSE) { if ($constructor = Nette\Reflection\ClassType::from($statement->entity)->getConstructor()) { $this->addDependency($constructor->getFileName()); $arguments = Helpers::autowireArguments($constructor, $arguments, $this); } elseif ($arguments) { throw new ServiceCreationException("Unable to pass arguments, class {$statement->entity} has no constructor."); } return $this->formatPhp("new {$statement->entity}" . ($arguments ? '(?*)' : ''), array($arguments)); } elseif (!Validators::isList($entity) || count($entity) !== 2) { throw new Nette\InvalidStateException("Expected class, method or property, {$statement->entity} given."); } elseif ($entity[0] === '') { return $this->formatPhp("{$entity['1']}(?*)", array($arguments), $self); } elseif (strpos($statement->entity, '$') !== FALSE) { if ($this->getServiceName($entity[0], $self)) { return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), reset($arguments)), $self); } else { return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), reset($arguments)), $self); } } elseif ($service = $this->getServiceName($entity[0], $self)) { if ($this->definitions[$service]->class) { $arguments = $this->autowireArguments($this->expand($this->definitions[$service]->class), $entity[1], $arguments); } return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments), $self); } else { $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments); return $this->formatPhp("{$entity['0']}::{$entity['1']}(?*)", array($arguments), $self); } }