/** * @param ServiceDefinition * @return string|null */ protected static function detectClass(ServiceDefinition $def) { if ($def->getClass()) { return $def->getClass(); } elseif ($interface = $def->getImplement()) { $rc = Reflection\ClassType::from($interface); $method = $rc->hasMethod('create') ? 'create' : ($rc->hasMethod('get') ? 'get' : NULL); if ($method === NULL) { return NULL; } if (!($returnType = $rc->getMethod($method)->getAnnotation('return'))) { return NULL; } return Reflection\AnnotationsParser::expandClassName(preg_replace('#[|\\s].*#', '', $returnType), $rc); } return NULL; }
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; } } } }