/** * Adds a service. * * @param Definition $definition * @param string $id * @param \DOMElement $parent */ private function addService($definition, $id, \DOMElement $parent) { $service = $this->document->createElement('service'); if (null !== $id) { $service->setAttribute('id', $id); } if ($class = $definition->getClass()) { if ('\\' === substr($class, 0, 1)) { $class = substr($class, 1); } $service->setAttribute('class', $class); } if (!$definition->isShared()) { $service->setAttribute('shared', 'false'); } if (!$definition->isPublic()) { $service->setAttribute('public', 'false'); } if ($definition->isSynthetic()) { $service->setAttribute('synthetic', 'true'); } if ($definition->isLazy()) { $service->setAttribute('lazy', 'true'); } if (null !== ($decorated = $definition->getDecoratedService())) { list($decorated, $renamedId, $priority) = $decorated; $service->setAttribute('decorates', $decorated); if (null !== $renamedId) { $service->setAttribute('decoration-inner-name', $renamedId); } if (0 !== $priority) { $service->setAttribute('decoration-priority', $priority); } } foreach ($definition->getTags() as $name => $tags) { foreach ($tags as $attributes) { $tag = $this->document->createElement('tag'); $tag->setAttribute('name', $name); foreach ($attributes as $key => $value) { $tag->setAttribute($key, $value); } $service->appendChild($tag); } } if ($definition->getFile()) { $file = $this->document->createElement('file'); $file->appendChild($this->document->createTextNode($definition->getFile())); $service->appendChild($file); } if ($parameters = $definition->getArguments()) { $this->convertParameters($parameters, 'argument', $service); } if ($parameters = $definition->getProperties()) { $this->convertParameters($parameters, 'property', $service, 'name'); } $this->addMethodCalls($definition->getMethodCalls(), $service); if ($callable = $definition->getFactory()) { $factory = $this->document->createElement('factory'); if (is_array($callable) && $callable[0] instanceof Definition) { $this->addService($callable[0], null, $factory); $factory->setAttribute('method', $callable[1]); } elseif (is_array($callable)) { $factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); $factory->setAttribute('method', $callable[1]); } else { $factory->setAttribute('function', $callable); } $service->appendChild($factory); } if ($definition->isDeprecated()) { $deprecated = $this->document->createElement('deprecated'); $deprecated->appendChild($this->document->createTextNode($definition->getDeprecationMessage('%service_id%'))); $service->appendChild($deprecated); } if ($definition->isAutowired()) { $service->setAttribute('autowire', 'true'); } foreach ($definition->getAutowiringTypes() as $autowiringTypeValue) { $autowiringType = $this->document->createElement('autowiring-type'); $autowiringType->appendChild($this->document->createTextNode($autowiringTypeValue)); $service->appendChild($autowiringType); } if ($callable = $definition->getConfigurator()) { $configurator = $this->document->createElement('configurator'); if (is_array($callable) && $callable[0] instanceof Definition) { $this->addService($callable[0], null, $configurator); $configurator->setAttribute('method', $callable[1]); } elseif (is_array($callable)) { $configurator->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]); $configurator->setAttribute('method', $callable[1]); } else { $configurator->setAttribute('function', $callable); } $service->appendChild($configurator); } $parent->appendChild($service); }
/** * Creates a service for a service definition. * * @param Definition $definition A service definition instance * @param string $id The service identifier * @param bool $tryProxy Whether to try proxying the service with a lazy proxy * * @return object The service described by the service definition * * @throws RuntimeException When the scope is inactive * @throws RuntimeException When the factory definition is incomplete * @throws RuntimeException When the service is a synthetic service * @throws InvalidArgumentException When configure callable is not callable * * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code */ public function createService(Definition $definition, $id, $tryProxy = true) { if ($definition->isSynthetic()) { throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id)); } if ($definition->isDeprecated()) { @trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED); } if ($tryProxy && $definition->isLazy()) { $container = $this; $proxy = $this->getProxyInstantiator()->instantiateProxy($container, $definition, $id, function () use($definition, $id, $container) { return $container->createService($definition, $id, false); }); $this->shareService($definition, $proxy, $id); return $proxy; } $parameterBag = $this->getParameterBag(); if (null !== $definition->getFile()) { require_once $parameterBag->resolveValue($definition->getFile()); } $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments()))); if (null !== ($factory = $definition->getFactory())) { if (is_array($factory)) { $factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]); } elseif (!is_string($factory)) { throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); } $service = call_user_func_array($factory, $arguments); if (!$definition->isDeprecated() && is_array($factory) && is_string($factory[0])) { $r = new \ReflectionClass($factory[0]); if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) { @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name), E_USER_DEPRECATED); } } } elseif (null !== $definition->getFactoryMethod(false)) { if (null !== $definition->getFactoryClass(false)) { $factory = $parameterBag->resolveValue($definition->getFactoryClass(false)); } elseif (null !== $definition->getFactoryService(false)) { $factory = $this->get($parameterBag->resolveValue($definition->getFactoryService(false))); } else { throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id)); } $service = call_user_func_array(array($factory, $definition->getFactoryMethod(false)), $arguments); } else { $r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass())); $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments); if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) { @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED); } } if ($tryProxy || !$definition->isLazy()) { // share only if proxying failed, or if not a proxy $this->shareService($definition, $service, $id); } foreach ($definition->getMethodCalls() as $call) { $this->callMethod($service, $call); } $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties()))); foreach ($properties as $name => $value) { $service->{$name} = $value; } if ($callable = $definition->getConfigurator()) { if (is_array($callable)) { $callable[0] = $parameterBag->resolveValue($callable[0]); if ($callable[0] instanceof Reference) { $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior()); } elseif ($callable[0] instanceof Definition) { $callable[0] = $this->createService($callable[0], null); } } if (!is_callable($callable)) { throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service))); } call_user_func($callable, $service); } return $service; }
/** * Adds a service. * * @param string $id * @param Definition $definition * * @return string */ private function addService($id, $definition) { $this->definitionVariables = new \SplObjectStorage(); $this->referenceVariables = array(); $this->variableCount = 0; $return = array(); if ($definition->isSynthetic()) { $return[] = '@throws RuntimeException always since this service is expected to be injected dynamically'; } elseif ($class = $definition->getClass()) { $return[] = sprintf('@return %s A %s instance.', 0 === strpos($class, '%') ? 'object' : '\\' . ltrim($class, '\\'), ltrim($class, '\\')); } elseif ($definition->getFactory()) { $factory = $definition->getFactory(); if (is_string($factory)) { $return[] = sprintf('@return object An instance returned by %s().', $factory); } elseif (is_array($factory) && (is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) { if (is_string($factory[0]) || $factory[0] instanceof Reference) { $return[] = sprintf('@return object An instance returned by %s::%s().', (string) $factory[0], $factory[1]); } elseif ($factory[0] instanceof Definition) { $return[] = sprintf('@return object An instance returned by %s::%s().', $factory[0]->getClass(), $factory[1]); } } } if ($definition->isDeprecated()) { if ($return && 0 === strpos($return[count($return) - 1], '@return')) { $return[] = ''; } $return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id)); } $return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return)); $doc = ''; if ($definition->isShared()) { $doc .= <<<'EOF' * * This service is shared. * This method always returns the same instance of the service. EOF; } if (!$definition->isPublic()) { $doc .= <<<'EOF' * * This service is private. * If you want to be able to request this service from the container directly, * make it public, otherwise you might end up with broken code. EOF; } if ($definition->isAutowired()) { $doc = <<<EOF * * This service is autowired. EOF; } if ($definition->isLazy()) { $lazyInitialization = '$lazyLoad = true'; $lazyInitializationDoc = "\n * @param bool \$lazyLoad whether to try lazy-loading the service with a proxy\n *"; } else { $lazyInitialization = ''; $lazyInitializationDoc = ''; } // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition); $visibility = $isProxyCandidate ? 'public' : 'protected'; $methodName = $this->generateMethodName($id); $code = <<<EOF /*{$this->docStar} * Gets the '{$id}' service.{$doc} *{$lazyInitializationDoc} * {$return} */ {$visibility} function {$methodName}({$lazyInitialization}) { EOF; $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id, $methodName) : ''; if ($definition->isSynthetic()) { $code .= sprintf(" throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n }\n", $id); } else { if ($definition->isDeprecated()) { $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", var_export($definition->getDeprecationMessage($id), true)); } $code .= $this->addServiceInclude($id, $definition) . $this->addServiceLocalTempVariables($id, $definition) . $this->addServiceInlinedDefinitions($id, $definition) . $this->addServiceInstance($id, $definition) . $this->addServiceInlinedDefinitionsSetup($id, $definition) . $this->addServiceMethodCalls($id, $definition) . $this->addServiceProperties($id, $definition) . $this->addServiceConfigurator($id, $definition) . $this->addServiceReturn($id, $definition); } $this->definitionVariables = null; $this->referenceVariables = null; return $code; }
/** * Adds a service. * * @param string $id * @param Definition $definition * * @return string */ private function addService($id, $definition) { $code = " {$id}:\n"; if ($class = $definition->getClass()) { if ('\\' === substr($class, 0, 1)) { $class = substr($class, 1); } $code .= sprintf(" class: %s\n", $this->dumper->dump($class)); } if (!$definition->isPublic()) { $code .= " public: false\n"; } $tagsCode = ''; foreach ($definition->getTags() as $name => $tags) { foreach ($tags as $attributes) { $att = array(); foreach ($attributes as $key => $value) { $att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value)); } $att = $att ? ', ' . implode(', ', $att) : ''; $tagsCode .= sprintf(" - { name: %s%s }\n", $this->dumper->dump($name), $att); } } if ($tagsCode) { $code .= " tags:\n" . $tagsCode; } if ($definition->getFile()) { $code .= sprintf(" file: %s\n", $this->dumper->dump($definition->getFile())); } if ($definition->isSynthetic()) { $code .= sprintf(" synthetic: true\n"); } if ($definition->isSynchronized(false)) { $code .= sprintf(" synchronized: true\n"); } if ($definition->isDeprecated()) { $code .= sprintf(" deprecated: %s\n", $definition->getDeprecationMessage('%service_id%')); } if ($definition->isAutowired()) { $code .= " autowire: true\n"; } $autowiringTypesCode = ''; foreach ($definition->getAutowiringTypes() as $autowiringType) { $autowiringTypesCode .= sprintf(" - %s\n", $this->dumper->dump($autowiringType)); } if ($autowiringTypesCode) { $code .= sprintf(" autowiring_types:\n%s", $autowiringTypesCode); } if ($definition->getFactoryClass(false)) { $code .= sprintf(" factory_class: %s\n", $this->dumper->dump($definition->getFactoryClass(false))); } if ($definition->isLazy()) { $code .= sprintf(" lazy: true\n"); } if ($definition->getFactoryMethod(false)) { $code .= sprintf(" factory_method: %s\n", $this->dumper->dump($definition->getFactoryMethod(false))); } if ($definition->getFactoryService(false)) { $code .= sprintf(" factory_service: %s\n", $this->dumper->dump($definition->getFactoryService(false))); } if ($definition->getArguments()) { $code .= sprintf(" arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0)); } if ($definition->getProperties()) { $code .= sprintf(" properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0)); } if ($definition->getMethodCalls()) { $code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12)); } if (!$definition->isShared()) { $code .= " shared: false\n"; } if (ContainerInterface::SCOPE_CONTAINER !== ($scope = $definition->getScope(false))) { $code .= sprintf(" scope: %s\n", $this->dumper->dump($scope)); } if (null !== ($decorated = $definition->getDecoratedService())) { list($decorated, $renamedId, $priority) = $decorated; $code .= sprintf(" decorates: %s\n", $decorated); if (null !== $renamedId) { $code .= sprintf(" decoration_inner_name: %s\n", $renamedId); } if (0 !== $priority) { $code .= sprintf(" decoration_priority: %s\n", $priority); } } if ($callable = $definition->getFactory()) { $code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0)); } if ($callable = $definition->getConfigurator()) { $code .= sprintf(" configurator: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0)); } return $code; }
public function testSetIsDeprecated() { $def = new Definition('stdClass'); $this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default'); $this->assertSame($def, $def->setDeprecated(true), '->setDeprecated() implements a fluent interface'); $this->assertTrue($def->isDeprecated(), '->isDeprecated() returns true if the instance should not be used anymore.'); $this->assertSame('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', $def->getDeprecationMessage('deprecated_service'), '->getDeprecationMessage() should return a formatted message template'); }