public function completeStatement(Statement $statement)
{
$entity = $this->normalizeEntity($statement->getEntity());
$arguments = $statement->arguments;
if (is_string($entity) && Strings::contains($entity, '?')) {
// PHP literal
} 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);
$entity = '@' . $service;
} elseif ($entity === 'not') {
// operator
} elseif (is_string($entity)) {
// class name
if (!class_exists($entity)) {
throw new ServiceCreationException("Class {$entity} not found.");
} elseif ((new ReflectionClass($entity))->isAbstract()) {
throw new ServiceCreationException("Class {$entity} is abstract.");
} elseif (($rm = (new ReflectionClass($entity))->getConstructor()) !== NULL && !$rm->isPublic()) {
$visibility = $rm->isProtected() ? 'protected' : 'private';
throw new ServiceCreationException("Class {$entity} has {$visibility} constructor.");
} elseif ($constructor = (new ReflectionClass($entity))->getConstructor()) {
$this->addDependency($constructor);
$arguments = Helpers::autowireArguments($constructor, $arguments, $this);
} elseif ($arguments) {
throw new ServiceCreationException("Unable to pass arguments, class {$entity} has no constructor.");
}
} 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
if (!Nette\Utils\Arrays::isList($arguments)) {
throw new ServiceCreationException("Unable to pass specified arguments to {$entity['0']}.");
} elseif (!function_exists($entity[1])) {
throw new ServiceCreationException("Function {$entity['1']} doesn't exist.");
}
$rf = new \ReflectionFunction($entity[1]);
$this->addDependency($rf);
$arguments = Helpers::autowireArguments($rf, $arguments, $this);
} else {
if ($entity[0] instanceof Statement) {
$entity[0] = $this->completeStatement($entity[0]);
} elseif ($service = $this->getServiceName($entity[0])) {
// service method
$entity[0] = '@' . $service;
}
if ($entity[1][0] === '$') {
// property getter, setter or appender
Validators::assert($arguments, 'list:0..1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'");
if (!$arguments && substr($entity[1], -2) === '[]') {
throw new ServiceCreationException("Missing argument for {$entity['1']}.");
}
} elseif ($class = empty($service) || $entity[1] === 'create' ? $this->resolveEntityClass($entity[0]) : $this->definitions[$service]->getClass()) {
$arguments = $this->autowireArguments($class, $entity[1], $arguments);
}
}
array_walk_recursive($arguments, function (&$val) {
if ($val instanceof Statement) {
$val = $this->completeStatement($val);
} elseif ($val === $this) {
trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
$val = self::literal('$this');
} elseif ($val instanceof ServiceDefinition) {
$val = '@' . current(array_keys($this->getDefinitions(), $val, TRUE));
} elseif (is_string($val) && strlen($val) > 1 && $val[0] === '@' && $val[1] !== '@') {
$pair = explode('::', $val, 2);
$name = $this->getServiceName($pair[0]);
if (!isset($pair[1])) {
// @service
$val = '@' . $name;
} elseif (preg_match('#^[A-Z][A-Z0-9_]*\\z#', $pair[1], $m)) {
// @service::CONSTANT
$val = self::literal($this->getDefinition($name)->getClass() . '::' . $pair[1]);
} else {
// @service::property
$val = new Statement(['@' . $name, '$' . $pair[1]]);
}
}
});
return new Statement($entity, $arguments);
}