private function resolveImplement(ServiceDefinition $def, $name)
{
$interface = $def->getImplement();
if (!interface_exists($interface)) {
throw new ServiceCreationException("Interface {$interface} used in service '{$name}' not found.");
}
self::checkCase($interface);
$rc = new ReflectionClass($interface);
$method = $rc->hasMethod('create') ? $rc->getMethod('create') : ($rc->hasMethod('get') ? $rc->getMethod('get') : NULL);
if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) {
throw new ServiceCreationException("Interface {$interface} used in service '{$name}' must have just one non-static method create() or get().");
}
$def->setImplementType($methodName = $rc->hasMethod('create') ? 'create' : 'get');
if (!$def->getClass() && !$def->getEntity()) {
$returnType = PhpReflection::getReturnType($method);
if (!$returnType) {
throw new ServiceCreationException("Method {$interface}::{$methodName}() used in service '{$name}' has no @return annotation.");
} elseif (!class_exists($returnType)) {
throw new ServiceCreationException("Check a @return annotation of the {$interface}::{$methodName}() method used in service '{$name}', class '{$returnType}' cannot be found.");
}
$def->setClass($returnType);
}
if ($methodName === 'get') {
if ($method->getParameters()) {
throw new ServiceCreationException("Method {$interface}::get() used in service '{$name}' must have no arguments.");
}
if (!$def->getEntity()) {
$def->setFactory('@\\' . ltrim($def->getClass(), '\\'));
} elseif (!$this->getServiceName($def->getFactory()->getEntity())) {
throw new ServiceCreationException("Invalid factory in service '{$name}' definition.");
}
}
if (!$def->parameters) {
$ctorParams = [];
if (!$def->getEntity()) {
$def->setFactory($def->getClass(), $def->getFactory() ? $def->getFactory()->arguments : []);
}
if (($class = $this->resolveEntityClass($def->getFactory(), [$name => 1])) && ($ctor = (new ReflectionClass($class))->getConstructor())) {
foreach ($ctor->getParameters() as $param) {
$ctorParams[$param->getName()] = $param;
}
}
foreach ($method->getParameters() as $param) {
$hint = PhpReflection::getParameterType($param);
if (isset($ctorParams[$param->getName()])) {
$arg = $ctorParams[$param->getName()];
if ($hint !== PhpReflection::getParameterType($arg)) {
throw new ServiceCreationException("Type hint for \${$param->getName()} in {$interface}::{$methodName}() doesn't match type hint in {$class} constructor.");
}
$def->getFactory()->arguments[$arg->getPosition()] = self::literal('$' . $arg->getName());
}
$paramDef = $hint . ' ' . $param->getName();
if ($param->isOptional()) {
$def->parameters[$paramDef] = $param->getDefaultValue();
} else {
$def->parameters[] = $paramDef;
}
}
}
}