private function updateDefinition(DI\ServiceDefinition $def) { $class = $def->getClass(); $setups = $def->getSetup(); foreach (self::getInjectProperties($class) as $property => $type) { $builder = $this->getContainerBuilder(); $inject = new DI\Statement('$' . $property, ['@\\' . ltrim($type, '\\')]); foreach ($setups as $key => $setup) { if ($setup->getEntity() === $inject->getEntity()) { $inject = $setup; $builder = NULL; unset($setups[$key]); } } self::checkType($class, $property, $type, $builder); array_unshift($setups, $inject); } foreach (array_reverse(self::getInjectMethods($def->getClass())) as $method) { $inject = new DI\Statement($method); foreach ($setups as $key => $setup) { if ($setup->getEntity() === $inject->getEntity()) { $inject = $setup; unset($setups[$key]); } } array_unshift($setups, $inject); } $def->setSetup($setups); }
public function process(ServiceDefinition $definition, $methods) { $currentSetupMethods = array_map(function (Statement $statement) { return $statement->getEntity(); }, $definition->getSetup()); Validators::assert($methods, 'array'); foreach ($methods as $setup) { $method = $setup; $args = array(); if ($method instanceof Statement) { $args = $method->arguments; $method = $method->getEntity(); } if (!in_array($method, $currentSetupMethods)) { $definition->addSetup($method, $args); } } }
private function updateDefinition(ServiceDefinition $def) { /** @var Statement[] $injects */ $injects = []; foreach (self::getInjectMethods($def->getClass()) as $method) { $injects[] = new Statement($method); } $setups = $def->getSetup(); foreach ($injects as $inject) { foreach ($setups as $key => $setup) { if ($setup->getEntity() === $inject->getEntity()) { $inject = $setup; unset($setups[$key]); } } array_unshift($setups, $inject); } $def->setSetup($setups); }
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 = array(); if (!$def->getEntity()) { $def->setFactory($def->getClass(), $def->getFactory() ? $def->getFactory()->arguments : array()); } if (($class = $this->resolveEntityClass($def->getFactory(), array($name => 1))) && ($rc = new ReflectionClass($class)) && ($ctor = $rc->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()); } elseif (!$def->getSetup()) { $hint = Nette\Utils\ObjectMixin::getSuggestion(array_keys($ctorParams), $param->getName()); throw new ServiceCreationException("Unused parameter \${$param->getName()} when implementing method {$interface}::{$methodName}()" . ($hint ? ", did you mean \${$hint}?" : '.')); } $paramDef = $hint . ' ' . $param->getName(); if ($param->isOptional()) { $def->parameters[$paramDef] = $param->getDefaultValue(); } else { $def->parameters[] = $paramDef; } } } }
/** * @param \Nette\DI\ContainerBuilder $builder * @param \Nette\DI\ServiceDefinition $manager * @throws AssertionException */ private function validateSubscribers(Nette\DI\ContainerBuilder $builder, Nette\DI\ServiceDefinition $manager) { foreach ($manager->getSetup() as $stt) { if ($stt->getEntity() !== 'addEventSubscriber') { $this->allowedManagerSetup[] = $stt; continue; } try { $serviceName = $builder->getServiceName(reset($stt->arguments)); $def = $builder->getDefinition($serviceName); } catch (\Exception $e) { throw new AssertionException("Please, do not register listeners directly to service '" . $this->prefix('manager') . "'. " . "Use section '" . $this->name . ": subscribers: ', or tag the service as '" . self::SUBSCRIBER_TAG . "'.", 0, $e); } if (!$def->getClass()) { throw new AssertionException("Please, specify existing class for " . (is_numeric($serviceName) ? 'anonymous ' : '') . "service '{$serviceName}' explicitly, " . "and make sure, that the class exists and can be autoloaded."); } elseif (!class_exists($def->getClass())) { throw new AssertionException("Class '" . $def->getClass() . "' of " . (is_numeric($serviceName) ? 'anonymous ' : '') . "service '{$serviceName}' cannot be found. " . "Please make sure, that the class exists and can be autoloaded."); } if (!in_array('Doctrine\\Common\\EventSubscriber', class_implements($def->getClass()))) { // the minimum is Doctrine EventSubscriber, but recommend is Kdyby Subscriber throw new AssertionException("Subscriber '{$serviceName}' doesn't implement Kdyby\\Events\\Subscriber."); } $eventNames = []; $listenerInst = self::createInstanceWithoutConstructor($def->getClass()); foreach ($listenerInst->getSubscribedEvents() as $eventName => $params) { if (is_numeric($eventName) && is_string($params)) { // [EventName, ...] list(, $method) = Kdyby\Events\Event::parseName($params); $eventNames[] = ltrim($params, '\\'); if (!method_exists($listenerInst, $method)) { throw new AssertionException("Event listener " . $def->getClass() . "::{$method}() is not implemented."); } } elseif (is_string($eventName)) { // [EventName => ???, ...] $eventNames[] = ltrim($eventName, '\\'); if (is_string($params)) { // [EventName => method, ...] if (!method_exists($listenerInst, $params)) { throw new AssertionException("Event listener " . $def->getClass() . "::{$params}() is not implemented."); } } elseif (is_string($params[0])) { // [EventName => [method, priority], ...] if (!method_exists($listenerInst, $params[0])) { throw new AssertionException("Event listener " . $def->getClass() . "::{$params[0]}() is not implemented."); } } else { foreach ($params as $listener) { // [EventName => [[method, priority], ...], ...] if (!method_exists($listenerInst, $listener[0])) { throw new AssertionException("Event listener " . $def->getClass() . "::{$listener[0]}() is not implemented."); } } } } } $this->listeners[$serviceName] = array_unique($eventNames); } }