Update to Drupal 8.1.0. For more information, see https://www.drupal.org/drupal-8.1.0-release-notes

This commit is contained in:
Pantheon Automation 2016-04-20 09:56:34 -07:00 committed by Greg Anderson
parent b11a755ba8
commit c0a0d5a94c
6920 changed files with 64395 additions and 57312 deletions

View file

@ -1,6 +1,18 @@
CHANGELOG
=========
2.8.0
-----
* deprecated the abstract ContainerAware class in favor of ContainerAwareTrait
* deprecated IntrospectableContainerInterface, to be merged with ContainerInterface in 3.0
* allowed specifying a directory to recursively load all configuration files it contains
* deprecated the concept of scopes
* added `Definition::setShared()` and `Definition::isShared()`
* added ResettableContainerInterface to be able to reset the container to release memory on shutdown
* added a way to define the priority of service decoration
* added support for service autowiring
2.7.0
-----

View file

@ -0,0 +1,252 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Guesses constructor arguments of services definitions and try to instantiate services if necessary.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class AutowirePass implements CompilerPassInterface
{
private $container;
private $reflectionClasses = array();
private $definedTypes = array();
private $types;
private $notGuessableTypes = array();
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isAutowired()) {
$this->completeDefinition($id, $definition);
}
}
// Free memory and remove circular reference to container
$this->container = null;
$this->reflectionClasses = array();
$this->definedTypes = array();
$this->types = null;
$this->notGuessableTypes = array();
}
/**
* Wires the given definition.
*
* @param string $id
* @param Definition $definition
*
* @throws RuntimeException
*/
private function completeDefinition($id, Definition $definition)
{
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
return;
}
$this->container->addClassResource($reflectionClass);
if (!$constructor = $reflectionClass->getConstructor()) {
return;
}
$arguments = $definition->getArguments();
foreach ($constructor->getParameters() as $index => $parameter) {
if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
continue;
}
try {
if (!$typeHint = $parameter->getClass()) {
// no default value? Then fail
if (!$parameter->isOptional()) {
throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id));
}
// specifically pass the default value
$arguments[$index] = $parameter->getDefaultValue();
continue;
}
if (null === $this->types) {
$this->populateAvailableTypes();
}
if (isset($this->types[$typeHint->name])) {
$value = new Reference($this->types[$typeHint->name]);
} else {
try {
$value = $this->createAutowiredDefinition($typeHint, $id);
} catch (RuntimeException $e) {
if ($parameter->allowsNull()) {
$value = null;
} elseif ($parameter->isDefaultValueAvailable()) {
$value = $parameter->getDefaultValue();
} else {
throw $e;
}
}
}
} catch (\ReflectionException $reflectionException) {
// Typehint against a non-existing class
if (!$parameter->isDefaultValueAvailable()) {
throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $reflectionException->getMessage()), 0, $reflectionException);
}
$value = $parameter->getDefaultValue();
}
$arguments[$index] = $value;
}
// it's possible index 1 was set, then index 0, then 2, etc
// make sure that we re-order so they're injected as expected
ksort($arguments);
$definition->setArguments($arguments);
}
/**
* Populates the list of available types.
*/
private function populateAvailableTypes()
{
$this->types = array();
foreach ($this->container->getDefinitions() as $id => $definition) {
$this->populateAvailableType($id, $definition);
}
}
/**
* Populates the list of available types for a given definition.
*
* @param string $id
* @param Definition $definition
*/
private function populateAvailableType($id, Definition $definition)
{
// Never use abstract services
if ($definition->isAbstract()) {
return;
}
foreach ($definition->getAutowiringTypes() as $type) {
$this->definedTypes[$type] = true;
$this->types[$type] = $id;
}
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
return;
}
foreach ($reflectionClass->getInterfaces() as $reflectionInterface) {
$this->set($reflectionInterface->name, $id);
}
do {
$this->set($reflectionClass->name, $id);
} while ($reflectionClass = $reflectionClass->getParentClass());
}
/**
* Associates a type and a service id if applicable.
*
* @param string $type
* @param string $id
*/
private function set($type, $id)
{
if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypes[$type])) {
return;
}
if (isset($this->types[$type])) {
if ($this->types[$type] === $id) {
return;
}
unset($this->types[$type]);
$this->notGuessableTypes[$type] = true;
return;
}
$this->types[$type] = $id;
}
/**
* Registers a definition for the type if possible or throws an exception.
*
* @param \ReflectionClass $typeHint
* @param string $id
*
* @return Reference A reference to the registered definition
*
* @throws RuntimeException
*/
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
{
if (isset($this->notGuessableTypes[$typeHint->name]) || !$typeHint->isInstantiable()) {
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s".', $typeHint->name, $id));
}
$argumentId = sprintf('autowired.%s', $typeHint->name);
$argumentDefinition = $this->container->register($argumentId, $typeHint->name);
$argumentDefinition->setPublic(false);
$this->populateAvailableType($argumentId, $argumentDefinition);
$this->completeDefinition($argumentId, $argumentDefinition);
return new Reference($argumentId);
}
/**
* Retrieves the reflection class associated with the given service.
*
* @param string $id
* @param Definition $definition
*
* @return \ReflectionClass|null
*/
private function getReflectionClass($id, Definition $definition)
{
if (isset($this->reflectionClasses[$id])) {
return $this->reflectionClasses[$id];
}
// Cannot use reflection if the class isn't set
if (!$class = $definition->getClass()) {
return;
}
$class = $this->container->getParameterBag()->resolveValue($class);
try {
return $this->reflectionClasses[$id] = new \ReflectionClass($class);
} catch (\ReflectionException $reflectionException) {
// return null
}
}
}

View file

@ -25,6 +25,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
* - non synthetic, non abstract services always have a class set
* - synthetic services are always public
* - synthetic services are always of non-prototype scope
* - shared services are always of non-prototype scope
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
@ -46,10 +47,15 @@ class CheckDefinitionValidityPass implements CompilerPassInterface
}
// synthetic service has non-prototype scope
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A synthetic service ("%s") cannot be of scope "prototype".', $id));
}
// shared service has non-prototype scope
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A shared service ("%s") cannot be of scope "prototype".', $id));
}
if ($definition->getFactory() && ($definition->getFactoryClass(false) || $definition->getFactoryService(false) || $definition->getFactoryMethod(false))) {
throw new RuntimeException(sprintf('A service ("%s") can use either the old or the new factory syntax, not both.', $id));
}

View file

@ -46,10 +46,10 @@ class CheckReferenceValidityPass implements CompilerPassInterface
{
$this->container = $container;
$children = $this->container->getScopeChildren();
$children = $this->container->getScopeChildren(false);
$ancestors = array();
$scopes = $this->container->getScopes();
$scopes = $this->container->getScopes(false);
foreach ($scopes as $name => $parent) {
$ancestors[$name] = array($parent);
@ -64,7 +64,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
}
$this->currentId = $id;
$this->currentScope = $scope = $definition->getScope();
$this->currentScope = $scope = $definition->getScope(false);
if (ContainerInterface::SCOPE_CONTAINER === $scope) {
$this->currentScopeChildren = array_keys($scopes);
@ -124,7 +124,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
return;
}
if (!$reference->isStrict()) {
if (!$reference->isStrict(false)) {
return;
}
@ -132,7 +132,7 @@ class CheckReferenceValidityPass implements CompilerPassInterface
return;
}
if ($this->currentScope === $scope = $definition->getScope()) {
if ($this->currentScope === $scope = $definition->getScope(false)) {
return;
}

View file

@ -19,18 +19,28 @@ use Symfony\Component\DependencyInjection\Alias;
*
* @author Christophe Coevoet <stof@notk.org>
* @author Fabien Potencier <fabien@symfony.com>
* @author Diego Saint Esteben <diego@saintesteben.me>
*/
class DecoratorServicePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definitions = new \SplPriorityQueue();
$order = PHP_INT_MAX;
foreach ($container->getDefinitions() as $id => $definition) {
if (!$decorated = $definition->getDecoratedService()) {
continue;
}
$definitions->insert(array($id, $definition), array($decorated[2], --$order));
}
foreach ($definitions as $arr) {
list($id, $definition) = $arr;
list($inner, $renamedId) = $definition->getDecoratedService();
$definition->setDecoratedService(null);
list($inner, $renamedId) = $decorated;
if (!$renamedId) {
$renamedId = $id.'.inner';
}

View file

@ -48,27 +48,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
$this->formatter = $this->compiler->getLoggingFormatter();
$this->graph = $this->compiler->getServiceReferenceGraph();
foreach ($container->getDefinitions() as $id => $definition) {
$this->currentId = $id;
$definition->setArguments(
$this->inlineArguments($container, $definition->getArguments())
);
$definition->setMethodCalls(
$this->inlineArguments($container, $definition->getMethodCalls())
);
$definition->setProperties(
$this->inlineArguments($container, $definition->getProperties())
);
$configurator = $this->inlineArguments($container, array($definition->getConfigurator()));
$definition->setConfigurator($configurator[0]);
$factory = $this->inlineArguments($container, array($definition->getFactory()));
$definition->setFactory($factory[0]);
}
$container->setDefinitions($this->inlineArguments($container, $container->getDefinitions(), true));
}
/**
@ -76,12 +56,16 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
*
* @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments
* @param bool $isRoot If we are processing the root definitions or not
*
* @return array
*/
private function inlineArguments(ContainerBuilder $container, array $arguments)
private function inlineArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
{
foreach ($arguments as $k => $argument) {
if ($isRoot) {
$this->currentId = $k;
}
if (is_array($argument)) {
$arguments[$k] = $this->inlineArguments($container, $argument);
} elseif ($argument instanceof Reference) {
@ -92,7 +76,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
$this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false)) {
$arguments[$k] = $definition;
} else {
$arguments[$k] = clone $definition;
@ -102,6 +86,12 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
$argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
$argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
$argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
$configurator = $this->inlineArguments($container, array($argument->getConfigurator()));
$argument->setConfigurator($configurator[0]);
$factory = $this->inlineArguments($container, array($argument->getFactory()));
$argument->setFactory($factory[0]);
}
}
@ -119,7 +109,7 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
*/
private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
{
if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
if (!$definition->isShared() || ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
return true;
}
@ -152,6 +142,6 @@ class InlineServiceDefinitionsPass implements RepeatablePassInterface
return false;
}
return $container->getDefinition(reset($ids))->getScope() === $definition->getScope();
return $container->getDefinition(reset($ids))->getScope(false) === $definition->getScope(false);
}
}

View file

@ -20,7 +20,7 @@ class LoggingFormatter
{
public function formatRemoveService(CompilerPassInterface $pass, $id, $reason)
{
return $this->format($pass, sprintf('Removed service "%s"; reason: %s', $id, $reason));
return $this->format($pass, sprintf('Removed service "%s"; reason: %s.', $id, $reason));
}
public function formatInlineService(CompilerPassInterface $pass, $id, $target)

View file

@ -50,6 +50,7 @@ class PassConfig
new CheckDefinitionValidityPass(),
new ResolveReferencesToAliasesPass(),
new ResolveInvalidReferencesPass(),
new AutowirePass(),
new AnalyzeServiceReferencesPass(true),
new CheckCircularReferencesPass(),
new CheckReferenceValidityPass(),

View file

@ -45,7 +45,7 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
try {
$definition = $container->getDefinition($aliasId);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with "%s".', $alias, $id), null, $e);
throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e);
}
if ($definition->isPublic()) {
@ -95,6 +95,9 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
$definition->setProperties(
$this->updateArgumentReferences($definition->getProperties(), $currentId, $newId)
);
$definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(false), $currentId, $newId), false);
$definition->setFactory($this->updateFactoryReference($definition->getFactory(), $currentId, $newId));
}
}
@ -122,4 +125,26 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
return $arguments;
}
private function updateFactoryServiceReference($factoryService, $currentId, $newId)
{
if (null === $factoryService) {
return;
}
return $currentId === $factoryService ? $newId : $factoryService;
}
private function updateFactoryReference($factory, $currentId, $newId)
{
if (null === $factory || !is_array($factory) || !$factory[0] instanceof Reference) {
return $factory;
}
if ($currentId === (string) $factory[0]) {
$factory[0] = new Reference($newId, $factory[0]->getInvalidBehavior());
}
return $factory;
}
}

View file

@ -21,12 +21,13 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
* merged Definition instance.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*/
class ResolveDefinitionTemplatesPass implements CompilerPassInterface
{
private $container;
private $compiler;
private $formatter;
private $currentId;
/**
* Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
@ -35,44 +36,80 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
foreach ($container->getDefinitions() as $id => $definition) {
// yes, we are specifically fetching the definition from the
// container to ensure we are not operating on stale data
$definition = $container->getDefinition($id);
if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
continue;
}
$container->setDefinitions($this->resolveArguments($container, $container->getDefinitions(), true));
}
$this->resolveDefinition($id, $definition);
/**
* Resolves definition decorator arguments.
*
* @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments
* @param bool $isRoot If we are processing the root definitions or not
*
* @return array
*/
private function resolveArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
{
foreach ($arguments as $k => $argument) {
if ($isRoot) {
// yes, we are specifically fetching the definition from the
// container to ensure we are not operating on stale data
$arguments[$k] = $argument = $container->getDefinition($k);
$this->currentId = $k;
}
if (is_array($argument)) {
$arguments[$k] = $this->resolveArguments($container, $argument);
} elseif ($argument instanceof Definition) {
if ($argument instanceof DefinitionDecorator) {
$arguments[$k] = $argument = $this->resolveDefinition($container, $argument);
if ($isRoot) {
$container->setDefinition($k, $argument);
}
}
$argument->setArguments($this->resolveArguments($container, $argument->getArguments()));
$argument->setMethodCalls($this->resolveArguments($container, $argument->getMethodCalls()));
$argument->setProperties($this->resolveArguments($container, $argument->getProperties()));
$configurator = $this->resolveArguments($container, array($argument->getConfigurator()));
$argument->setConfigurator($configurator[0]);
$factory = $this->resolveArguments($container, array($argument->getFactory()));
$argument->setFactory($factory[0]);
}
}
return $arguments;
}
/**
* Resolves the definition.
*
* @param string $id The definition identifier
* @param ContainerBuilder $container The ContainerBuilder
* @param DefinitionDecorator $definition
*
* @return Definition
*
* @throws \RuntimeException When the definition is invalid
*/
private function resolveDefinition($id, DefinitionDecorator $definition)
private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
{
if (!$this->container->hasDefinition($parent = $definition->getParent())) {
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id));
if (!$container->hasDefinition($parent = $definition->getParent())) {
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
}
$parentDef = $this->container->getDefinition($parent);
$parentDef = $container->getDefinition($parent);
if ($parentDef instanceof DefinitionDecorator) {
$parentDef = $this->resolveDefinition($parent, $parentDef);
$id = $this->currentId;
$this->currentId = $parent;
$parentDef = $this->resolveDefinition($container, $parentDef);
$container->setDefinition($parent, $parentDef);
$this->currentId = $id;
}
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent));
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $this->currentId, $parent));
$def = new Definition();
// merge in parent definition
@ -81,6 +118,7 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
$def->setArguments($parentDef->getArguments());
$def->setMethodCalls($parentDef->getMethodCalls());
$def->setProperties($parentDef->getProperties());
$def->setAutowiringTypes($parentDef->getAutowiringTypes());
if ($parentDef->getFactoryClass(false)) {
$def->setFactoryClass($parentDef->getFactoryClass(false));
}
@ -90,6 +128,9 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
if ($parentDef->getFactoryService(false)) {
$def->setFactoryService($parentDef->getFactoryService(false));
}
if ($parentDef->isDeprecated()) {
$def->setDeprecated(true, $parentDef->getDeprecationMessage('%service_id%'));
}
$def->setFactory($parentDef->getFactory());
$def->setConfigurator($parentDef->getConfigurator());
$def->setFile($parentDef->getFile());
@ -125,6 +166,9 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
if (isset($changes['lazy'])) {
$def->setLazy($definition->isLazy());
}
if (isset($changes['deprecated'])) {
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
}
if (isset($changes['decorated_service'])) {
$decoratedService = $definition->getDecoratedService();
if (null === $decoratedService) {
@ -159,14 +203,17 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
}
// merge autowiring types
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$def->addAutowiringType($autowiringType);
}
// these attributes are always taken from the child
$def->setAbstract($definition->isAbstract());
$def->setScope($definition->getScope());
$def->setScope($definition->getScope(false), false);
$def->setShared($definition->isShared());
$def->setTags($definition->getTags());
// set new definition on container
$this->container->setDefinition($id, $def);
return $def;
}
}

View file

@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -42,6 +43,8 @@ class ResolveReferencesToAliasesPass implements CompilerPassInterface
$definition->setArguments($this->processArguments($definition->getArguments()));
$definition->setMethodCalls($this->processArguments($definition->getMethodCalls()));
$definition->setProperties($this->processArguments($definition->getProperties()));
$definition->setFactory($this->processFactory($definition->getFactory()));
$definition->setFactoryService($this->processFactoryService($definition->getFactoryService(false)), false);
}
foreach ($container->getAliases() as $id => $alias) {
@ -68,7 +71,7 @@ class ResolveReferencesToAliasesPass implements CompilerPassInterface
$defId = $this->getDefinitionId($id = (string) $argument);
if ($defId !== $id) {
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict());
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict(false));
}
}
}
@ -76,6 +79,30 @@ class ResolveReferencesToAliasesPass implements CompilerPassInterface
return $arguments;
}
private function processFactoryService($factoryService)
{
if (null === $factoryService) {
return;
}
return $this->getDefinitionId($factoryService);
}
private function processFactory($factory)
{
if (null === $factory || !is_array($factory) || !$factory[0] instanceof Reference) {
return $factory;
}
$defId = $this->getDefinitionId($id = (string) $factory[0]);
if ($defId !== $id) {
$factory[0] = new Reference($defId, $factory[0]->getInvalidBehavior(), $factory[0]->isStrict(false));
}
return $factory;
}
/**
* Resolves an alias into a definition id.
*

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
@ -58,7 +59,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class Container implements IntrospectableContainerInterface
class Container implements IntrospectableContainerInterface, ResettableContainerInterface
{
/**
* @var ParameterBagInterface
@ -164,6 +165,8 @@ class Container implements IntrospectableContainerInterface
* Setting a service to null resets the service: has() returns false and get()
* behaves in the same way as if the service was never created.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
@ -173,6 +176,10 @@ class Container implements IntrospectableContainerInterface
*/
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{
if (!in_array($scope, array('container', 'request')) || ('request' === $scope && 'request' !== $id)) {
@trigger_error('The concept of container scopes is deprecated since version 2.8 and will be removed in 3.0. Omit the third parameter.', E_USER_DEPRECATED);
}
if (self::SCOPE_PROTOTYPE === $scope) {
throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id));
}
@ -193,6 +200,10 @@ class Container implements IntrospectableContainerInterface
$this->scopedServices[$scope][$id] = $service;
}
if (isset($this->aliases[$id])) {
unset($this->aliases[$id]);
}
$this->services[$id] = $service;
if (method_exists($this, $method = 'synchronize'.strtr($id, $this->underscoreMap).'Service')) {
@ -305,10 +316,7 @@ class Container implements IntrospectableContainerInterface
$service = $this->$method();
} catch (\Exception $e) {
unset($this->loading[$id]);
if (array_key_exists($id, $this->services)) {
unset($this->services[$id]);
}
unset($this->services[$id]);
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
@ -347,6 +355,18 @@ class Container implements IntrospectableContainerInterface
return isset($this->services[$id]) || array_key_exists($id, $this->services);
}
/**
* {@inheritdoc}
*/
public function reset()
{
if (!empty($this->scopedServices)) {
throw new LogicException('Resetting the container is not allowed when a scope is active.');
}
$this->services = array();
}
/**
* Gets all service ids.
*
@ -355,9 +375,8 @@ class Container implements IntrospectableContainerInterface
public function getServiceIds()
{
$ids = array();
$r = new \ReflectionClass($this);
foreach ($r->getMethods() as $method) {
if (preg_match('/^get(.+)Service$/', $method->name, $match)) {
foreach (get_class_methods($this) as $method) {
if (preg_match('/^get(.+)Service$/', $method, $match)) {
$ids[] = self::underscore($match[1]);
}
}
@ -373,9 +392,15 @@ class Container implements IntrospectableContainerInterface
*
* @throws RuntimeException When the parent scope is inactive
* @throws InvalidArgumentException When the scope does not exist
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function enterScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (!isset($this->scopes[$name])) {
throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
}
@ -419,9 +444,15 @@ class Container implements IntrospectableContainerInterface
* @param string $name The name of the scope to leave
*
* @throws InvalidArgumentException if the scope is not active
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function leaveScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (!isset($this->scopedServices[$name])) {
throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
}
@ -464,12 +495,17 @@ class Container implements IntrospectableContainerInterface
* @param ScopeInterface $scope
*
* @throws InvalidArgumentException
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function addScope(ScopeInterface $scope)
{
$name = $scope->getName();
$parentScope = $scope->getParentName();
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
}
@ -496,9 +532,15 @@ class Container implements IntrospectableContainerInterface
* @param string $name The name of the scope
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function hasScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return isset($this->scopes[$name]);
}
@ -510,9 +552,13 @@ class Container implements IntrospectableContainerInterface
* @param string $name
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isScopeActive($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
return isset($this->scopedServices[$name]);
}
@ -537,6 +583,10 @@ class Container implements IntrospectableContainerInterface
*/
public static function underscore($id)
{
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.')));
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), str_replace('_', '.', $id)));
}
private function __clone()
{
}
}

View file

@ -15,6 +15,8 @@ namespace Symfony\Component\DependencyInjection;
* A simple implementation of ContainerAwareInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since version 2.8, to be removed in 3.0. Use the ContainerAwareTrait instead.
*/
abstract class ContainerAware implements ContainerAwareInterface
{
@ -24,9 +26,9 @@ abstract class ContainerAware implements ContainerAwareInterface
protected $container;
/**
* Sets the Container associated with this Controller.
* Sets the container.
*
* @param ContainerInterface $container A ContainerInterface instance
* @param ContainerInterface|null $container A ContainerInterface instance or null
*/
public function setContainer(ContainerInterface $container = null)
{

View file

@ -19,7 +19,7 @@ namespace Symfony\Component\DependencyInjection;
interface ContainerAwareInterface
{
/**
* Sets the Container.
* Sets the container.
*
* @param ContainerInterface|null $container A ContainerInterface instance or null
*/

View file

@ -24,9 +24,9 @@ trait ContainerAwareTrait
protected $container;
/**
* Sets the Container associated with this Controller.
* Sets the container.
*
* @param ContainerInterface $container A ContainerInterface instance
* @param ContainerInterface|null $container A ContainerInterface instance or null
*/
public function setContainer(ContainerInterface $container = null)
{

View file

@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Resource\ResourceInterface;
@ -88,6 +90,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private $expressionLanguageProviders = array();
/**
* @var string[] with tag names used by findTaggedServiceIds
*/
private $usedTags = array();
/**
* Sets the track resources flag.
*
@ -255,7 +262,9 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
do {
$this->addResource(new FileResource($class->getFileName()));
if (is_file($class->getFileName())) {
$this->addResource(new FileResource($class->getFileName()));
}
} while ($class = $class->getParentClass());
return $this;
@ -330,9 +339,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* Returns all Scopes.
*
* @return array An array of scopes
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScopes()
public function getScopes($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopes;
}
@ -340,15 +355,23 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* Returns all Scope children.
*
* @return array An array of scope children.
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScopeChildren()
public function getScopeChildren($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopeChildren;
}
/**
* Sets a service.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope
@ -417,9 +440,9 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*
* @return object The associated service
*
* @throws InvalidArgumentException when no definitions are available
* @throws InactiveScopeException when the current scope is not active
* @throws LogicException when a circular dependency is detected
* @throws InvalidArgumentException when no definitions are available
* @throws ServiceCircularReferenceException When a circular reference is detected
* @throws ServiceNotFoundException When the service is not defined
* @throws \Exception
*
* @see Reference
@ -438,7 +461,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
try {
$definition = $this->getDefinition($id);
} catch (InvalidArgumentException $e) {
} catch (ServiceNotFoundException $e) {
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
}
@ -786,14 +809,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*
* @return Definition A Definition instance
*
* @throws InvalidArgumentException if the service definition does not exist
* @throws ServiceNotFoundException if the service definition does not exist
*/
public function getDefinition($id)
{
$id = strtolower($id);
if (!array_key_exists($id, $this->definitions)) {
throw new InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id));
throw new ServiceNotFoundException($id);
}
return $this->definitions[$id];
@ -808,7 +831,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*
* @return Definition A Definition instance
*
* @throws InvalidArgumentException if the service definition does not exist
* @throws ServiceNotFoundException if the service definition does not exist
*/
public function findDefinition($id)
{
@ -843,6 +866,10 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
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;
@ -876,6 +903,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
$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));
@ -890,6 +925,10 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$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()) {
@ -901,7 +940,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$this->callMethod($service, $call);
}
$properties = $this->resolveServices($parameterBag->resolveValue($definition->getProperties()));
$properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())));
foreach ($properties as $name => $value) {
$service->$name = $value;
}
@ -972,6 +1011,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
public function findTaggedServiceIds($name)
{
$this->usedTags[] = $name;
$tags = array();
foreach ($this->getDefinitions() as $id => $definition) {
if ($definition->hasTag($name)) {
@ -997,6 +1037,16 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return array_unique($tags);
}
/**
* Returns all tags not queried by findTaggedServiceIds.
*
* @return string[] An array of tags
*/
public function findUnusedTags()
{
return array_values(array_diff($this->findTags(), $this->usedTags));
}
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
{
$this->expressionLanguageProviders[] = $provider;
@ -1088,7 +1138,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
}
}
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->resolveValue($call[1])));
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
}
/**
@ -1102,7 +1152,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private function shareService(Definition $definition, $service, $id)
{
if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
if ($definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
throw new InactiveScopeException($id, $scope);
}

View file

@ -32,6 +32,8 @@ interface ContainerInterface
/**
* Sets a service.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
@ -94,6 +96,8 @@ interface ContainerInterface
* Enters the given scope.
*
* @param string $name
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function enterScope($name);
@ -101,6 +105,8 @@ interface ContainerInterface
* Leaves the current scope, and re-enters the parent scope.
*
* @param string $name
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function leaveScope($name);
@ -108,6 +114,8 @@ interface ContainerInterface
* Adds a scope to the container.
*
* @param ScopeInterface $scope
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function addScope(ScopeInterface $scope);
@ -117,6 +125,8 @@ interface ContainerInterface
* @param string $name
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function hasScope($name);
@ -128,6 +138,8 @@ interface ContainerInterface
* @param string $name
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isScopeActive($name);
}

View file

@ -27,6 +27,9 @@ class Definition
private $factoryClass;
private $factoryMethod;
private $factoryService;
private $shared = true;
private $deprecated = false;
private $deprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.';
private $scope = ContainerInterface::SCOPE_CONTAINER;
private $properties = array();
private $calls = array();
@ -38,6 +41,8 @@ class Definition
private $synchronized = false;
private $lazy = false;
private $decoratedService;
private $autowired = false;
private $autowiringTypes = array();
protected $arguments;
@ -139,12 +144,13 @@ class Definition
*
* @param null|string $id The decorated service id, use null to remove decoration
* @param null|string $renamedId The new decorated service id
* @param int $priority The priority of decoration
*
* @return Definition The current instance
*
* @throws InvalidArgumentException In case the decorated service id and the new decorated service id are equals.
*/
public function setDecoratedService($id, $renamedId = null)
public function setDecoratedService($id, $renamedId = null, $priority = 0)
{
if ($renamedId && $id == $renamedId) {
throw new \InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
@ -153,7 +159,7 @@ class Definition
if (null === $id) {
$this->decoratedService = null;
} else {
$this->decoratedService = array($id, $renamedId);
$this->decoratedService = array($id, $renamedId, (int) $priority);
}
return $this;
@ -162,7 +168,7 @@ class Definition
/**
* Gets the service that decorates this service.
*
* @return null|array An array composed of the decorated service id and the new id for it, null if no service is decorated
* @return null|array An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated
*/
public function getDecoratedService()
{
@ -194,9 +200,11 @@ class Definition
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryService($factoryService)
public function setFactoryService($factoryService, $triggerDeprecationError = true)
{
@trigger_error(sprintf('%s(%s) is deprecated since version 2.6 and will be removed in 3.0. Use Definition::setFactory() instead.', __METHOD__, $factoryService), E_USER_DEPRECATED);
if ($triggerDeprecationError) {
@trigger_error(sprintf('%s(%s) is deprecated since version 2.6 and will be removed in 3.0. Use Definition::setFactory() instead.', __METHOD__, $factoryService), E_USER_DEPRECATED);
}
$this->factoryService = $factoryService;
@ -495,9 +503,7 @@ class Definition
*/
public function clearTag($name)
{
if (isset($this->tags[$name])) {
unset($this->tags[$name]);
}
unset($this->tags[$name]);
return $this;
}
@ -538,15 +544,49 @@ class Definition
return $this->file;
}
/**
* Sets if the service must be shared or not.
*
* @param bool $shared Whether the service must be shared or not
*
* @return Definition The current instance
*/
public function setShared($shared)
{
$this->shared = (bool) $shared;
return $this;
}
/**
* Whether this service is shared.
*
* @return bool
*/
public function isShared()
{
return $this->shared;
}
/**
* Sets the scope of the service.
*
* @param string $scope Whether the service must be shared or not
*
* @return Definition The current instance
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function setScope($scope)
public function setScope($scope, $triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (ContainerInterface::SCOPE_PROTOTYPE === $scope) {
$this->setShared(false);
}
$this->scope = $scope;
return $this;
@ -556,9 +596,15 @@ class Definition
* Returns the scope of the service.
*
* @return string
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScope()
public function getScope($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scope;
}
@ -698,6 +744,59 @@ class Definition
return $this->abstract;
}
/**
* Whether this definition is deprecated, that means it should not be called
* anymore.
*
* @param bool $status
* @param string $template Template message to use if the definition is deprecated
*
* @return Definition the current instance
*
* @throws InvalidArgumentException When the message template is invalid.
*/
public function setDeprecated($status = true, $template = null)
{
if (null !== $template) {
if (preg_match('#[\r\n]|\*/#', $template)) {
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
}
if (false === strpos($template, '%service_id%')) {
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
}
$this->deprecationTemplate = $template;
}
$this->deprecated = (bool) $status;
return $this;
}
/**
* Whether this definition is deprecated, that means it should not be called
* anymore.
*
* @return bool
*/
public function isDeprecated()
{
return $this->deprecated;
}
/**
* Message to use if this definition is deprecated.
*
* @param string $id Service id relying on this definition
*
* @return string
*/
public function getDeprecationMessage($id)
{
return str_replace('%service_id%', $id, $this->deprecationTemplate);
}
/**
* Sets a configurator to call after the service is fully initialized.
*
@ -721,4 +820,96 @@ class Definition
{
return $this->configurator;
}
/**
* Sets types that will default to this definition.
*
* @param string[] $types
*
* @return Definition The current instance
*/
public function setAutowiringTypes(array $types)
{
$this->autowiringTypes = array();
foreach ($types as $type) {
$this->autowiringTypes[$type] = true;
}
return $this;
}
/**
* Is the definition autowired?
*
* @return bool
*/
public function isAutowired()
{
return $this->autowired;
}
/**
* Sets autowired.
*
* @param $autowired
*
* @return Definition The current instance
*/
public function setAutowired($autowired)
{
$this->autowired = $autowired;
return $this;
}
/**
* Gets autowiring types that will default to this definition.
*
* @return string[]
*/
public function getAutowiringTypes()
{
return array_keys($this->autowiringTypes);
}
/**
* Adds a type that will default to this definition.
*
* @param string $type
*
* @return Definition The current instance
*/
public function addAutowiringType($type)
{
$this->autowiringTypes[$type] = true;
return $this;
}
/**
* Removes a type.
*
* @param string $type
*
* @return Definition The current instance
*/
public function removeAutowiringType($type)
{
unset($this->autowiringTypes[$type]);
return $this;
}
/**
* Will this definition default for the given type?
*
* @param string $type
*
* @return bool
*/
public function hasAutowiringType($type)
{
return isset($this->autowiringTypes[$type]);
}
}

View file

@ -78,7 +78,6 @@ class DefinitionDecorator extends Definition
/**
* {@inheritdoc}
*
*/
public function setFactoryClass($class)
{
@ -100,11 +99,11 @@ class DefinitionDecorator extends Definition
/**
* {@inheritdoc}
*/
public function setFactoryService($service)
public function setFactoryService($service, $triggerDeprecationError = true)
{
$this->changes['factory_service'] = true;
return parent::setFactoryService($service);
return parent::setFactoryService($service, $triggerDeprecationError);
}
/**
@ -150,11 +149,21 @@ class DefinitionDecorator extends Definition
/**
* {@inheritdoc}
*/
public function setDecoratedService($id, $renamedId = null)
public function setDecoratedService($id, $renamedId = null, $priority = 0)
{
$this->changes['decorated_service'] = true;
return parent::setDecoratedService($id, $renamedId);
return parent::setDecoratedService($id, $renamedId, $priority);
}
/**
* {@inheritdoc}
*/
public function setDeprecated($boolean = true, $template = null)
{
$this->changes['deprecated'] = true;
return parent::setDeprecated($boolean, $template);
}
/**

View file

@ -177,7 +177,7 @@ class GraphvizDumper extends Dumper
} catch (ParameterNotFoundException $e) {
}
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $class), 'attributes' => array_merge($this->options['node.definition'], array('style' => ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope() ? 'filled' : 'dotted')));
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $class), 'attributes' => array_merge($this->options['node.definition'], array('style' => $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false) ? 'filled' : 'dotted')));
$container->setDefinition($id, new Definition('stdClass'));
}
@ -205,7 +205,7 @@ class GraphvizDumper extends Dumper
$container->setDefinitions($this->container->getDefinitions());
$container->setAliases($this->container->getAliases());
$container->setResources($this->container->getResources());
foreach ($this->container->getScopes() as $scope => $parentScope) {
foreach ($this->container->getScopes(false) as $scope => $parentScope) {
$container->addScope(new Scope($scope, $parentScope));
}
foreach ($this->container->getExtensions() as $extension) {

View file

@ -26,6 +26,7 @@ use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
use Symfony\Component\DependencyInjection\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\HttpKernel\Kernel;
/**
* PhpDumper dumps a service container as a PHP class.
@ -57,6 +58,7 @@ class PhpDumper extends Dumper
private $expressionLanguage;
private $targetDirRegex;
private $targetDirMaxMatches;
private $docStar;
/**
* @var ExpressionFunctionProviderInterface[]
@ -108,7 +110,9 @@ class PhpDumper extends Dumper
'class' => 'ProjectServiceContainer',
'base_class' => 'Container',
'namespace' => '',
'debug' => true,
), $options);
$this->docStar = $options['debug'] ? '*' : '';
if (!empty($options['file']) && is_dir($dir = dirname($options['file']))) {
// Build a regexp where the first root dirs are mandatory,
@ -233,9 +237,15 @@ class PhpDumper extends Dumper
array($this->getProxyDumper(), 'isProxyCandidate')
);
$code = '';
$strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments');
foreach ($definitions as $definition) {
$code .= "\n".$this->getProxyDumper()->getProxyCode($definition);
$proxyCode = "\n".$this->getProxyDumper()->getProxyCode($definition);
if ($strip) {
$proxyCode = "<?php\n".$proxyCode;
$proxyCode = substr(Kernel::stripComments($proxyCode), 5);
}
$code .= $proxyCode;
}
return $code;
@ -382,9 +392,9 @@ class PhpDumper extends Dumper
$isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
$instantiation = '';
if (!$isProxyCandidate && ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
if (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
$instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
} elseif (!$isProxyCandidate && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
} elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
$instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
} elseif (!$simple) {
$instantiation = '$instance';
@ -578,7 +588,7 @@ class PhpDumper extends Dumper
$return[] = sprintf('@return object An instance returned by %s::%s().', $definition->getFactoryService(false), $definition->getFactoryMethod(false));
}
$scope = $definition->getScope();
$scope = $definition->getScope(false);
if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
$return[] = '';
@ -586,11 +596,19 @@ class PhpDumper extends Dumper
$return[] = sprintf("@throws InactiveScopeException when the '%s' service is requested while the '%s' scope is not active", $id, $scope);
}
$return = implode("\n * ", $return);
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 (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
$doc .= <<<EOF
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
$doc .= <<<'EOF'
*
* This service is shared.
@ -599,7 +617,7 @@ EOF;
}
if (!$definition->isPublic()) {
$doc .= <<<EOF
$doc .= <<<'EOF'
*
* This service is private.
@ -608,6 +626,14 @@ EOF;
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 *";
@ -621,7 +647,7 @@ EOF;
$visibility = $isProxyCandidate ? 'public' : 'protected';
$code = <<<EOF
/**
/*{$this->docStar}
* Gets the '$id' service.$doc
*$lazyInitializationDoc
* $return
@ -646,6 +672,10 @@ EOF;
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).
@ -737,7 +767,7 @@ EOF;
return <<<EOF
/**
/*{$this->docStar}
* Updates the '$id' service.
*/
protected function synchronize{$this->camelize($id)}Service()
@ -759,6 +789,10 @@ EOF;
if (null !== $definition->getFactory()) {
$callable = $definition->getFactory();
if (is_array($callable)) {
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a'));
}
if ($callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
@ -825,7 +859,7 @@ use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
$bagClass
/**
/*{$this->docStar}
* $class.
*
* This class has been auto-generated
@ -851,7 +885,7 @@ EOF;
$code = <<<EOF
/**
/*{$this->docStar}
* Constructor.
*/
public function __construct()
@ -860,16 +894,16 @@ EOF;
EOF;
if (count($scopes = $this->container->getScopes()) > 0) {
if (count($scopes = $this->container->getScopes(false)) > 0) {
$code .= "\n";
$code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
$code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren()).";\n";
$code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
}
$code .= $this->addMethodMap();
$code .= $this->addAliases();
$code .= <<<EOF
$code .= <<<'EOF'
}
EOF;
@ -888,7 +922,7 @@ EOF;
$code = <<<EOF
/**
/*{$this->docStar}
* Constructor.
*/
public function __construct()
@ -899,17 +933,17 @@ EOF;
$code .= "\n \$this->parameters = \$this->getDefaultParameters();\n";
}
$code .= <<<EOF
$code .= <<<'EOF'
\$this->services =
\$this->scopedServices =
\$this->scopeStacks = array();
$this->services =
$this->scopedServices =
$this->scopeStacks = array();
EOF;
$code .= "\n";
if (count($scopes = $this->container->getScopes()) > 0) {
if (count($scopes = $this->container->getScopes(false)) > 0) {
$code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
$code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren()).";\n";
$code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
} else {
$code .= " \$this->scopes = array();\n";
$code .= " \$this->scopeChildren = array();\n";
@ -918,7 +952,7 @@ EOF;
$code .= $this->addMethodMap();
$code .= $this->addAliases();
$code .= <<<EOF
$code .= <<<'EOF'
}
EOF;
@ -935,7 +969,7 @@ EOF;
{
return <<<EOF
/**
/*{$this->docStar}
* {@inheritdoc}
*/
public function compile()
@ -1009,36 +1043,36 @@ EOF;
$code = '';
if ($this->container->isFrozen()) {
$code .= <<<EOF
$code .= <<<'EOF'
/**
* {@inheritdoc}
*/
public function getParameter(\$name)
public function getParameter($name)
{
\$name = strtolower(\$name);
$name = strtolower($name);
if (!(isset(\$this->parameters[\$name]) || array_key_exists(\$name, \$this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', \$name));
if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
}
return \$this->parameters[\$name];
return $this->parameters[$name];
}
/**
* {@inheritdoc}
*/
public function hasParameter(\$name)
public function hasParameter($name)
{
\$name = strtolower(\$name);
$name = strtolower($name);
return isset(\$this->parameters[\$name]) || array_key_exists(\$name, \$this->parameters);
return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters);
}
/**
* {@inheritdoc}
*/
public function setParameter(\$name, \$value)
public function setParameter($name, $value)
{
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
}
@ -1048,19 +1082,22 @@ EOF;
*/
public function getParameterBag()
{
if (null === \$this->parameterBag) {
\$this->parameterBag = new FrozenParameterBag(\$this->parameters);
if (null === $this->parameterBag) {
$this->parameterBag = new FrozenParameterBag($this->parameters);
}
return \$this->parameterBag;
return $this->parameterBag;
}
EOF;
if ('' === $this->docStar) {
$code = str_replace('/**', '/*', $code);
}
}
$code .= <<<EOF
/**
/*{$this->docStar}
* Gets the default parameters.
*
* @return array An array of the default parameters
@ -1117,7 +1154,7 @@ EOF;
*/
private function endClass()
{
return <<<EOF
return <<<'EOF'
}
EOF;
@ -1310,8 +1347,12 @@ EOF;
}
if (is_array($factory)) {
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a'));
}
if (is_string($factory[0])) {
return sprintf('\\%s::%s(%s)', $factory[0], $factory[1], implode(', ', $arguments));
return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments));
}
if ($factory[0] instanceof Definition) {
@ -1342,12 +1383,8 @@ EOF;
if (null === $class) {
throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
}
$class = $this->dumpValue($class);
if (false !== strpos($class, '$')) {
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
}
return sprintf('new \\%s(%s)', substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
} elseif ($value instanceof Variable) {
return '$'.$value;
} elseif ($value instanceof Reference) {
@ -1388,9 +1425,18 @@ EOF;
* @param string $class
*
* @return string
*
* @throws RuntimeException
*/
private function dumpLiteralClass($class)
{
if (false !== strpos($class, '$')) {
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
}
if (0 !== strpos($class, "'") || !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
}
return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1);
}

View file

@ -126,7 +126,10 @@ class XmlDumper extends Dumper
if ($definition->getFactoryService(false)) {
$service->setAttribute('factory-service', $definition->getFactoryService(false));
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
if (!$definition->isShared()) {
$service->setAttribute('shared', 'false');
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$service->setAttribute('scope', $scope);
}
if (!$definition->isPublic()) {
@ -142,11 +145,14 @@ class XmlDumper extends Dumper
$service->setAttribute('lazy', 'true');
}
if (null !== $decorated = $definition->getDecoratedService()) {
list($decorated, $renamedId) = $decorated;
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) {
@ -191,6 +197,24 @@ class XmlDumper extends Dumper
$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');
@ -283,7 +307,7 @@ class XmlDumper extends Dumper
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
$element->setAttribute('on-invalid', 'ignore');
}
if (!$value->isStrict()) {
if (!$value->isStrict(false)) {
$element->setAttribute('strict', 'false');
}
} elseif ($value instanceof Definition) {

View file

@ -65,7 +65,7 @@ class YamlDumper extends Dumper
$class = substr($class, 1);
}
$code .= sprintf(" class: %s\n", $class);
$code .= sprintf(" class: %s\n", $this->dumper->dump($class));
}
if (!$definition->isPublic()) {
@ -89,7 +89,7 @@ class YamlDumper extends Dumper
}
if ($definition->getFile()) {
$code .= sprintf(" file: %s\n", $definition->getFile());
$code .= sprintf(" file: %s\n", $this->dumper->dump($definition->getFile()));
}
if ($definition->isSynthetic()) {
@ -100,8 +100,24 @@ class YamlDumper extends Dumper
$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", $definition->getFactoryClass(false));
$code .= sprintf(" factory_class: %s\n", $this->dumper->dump($definition->getFactoryClass(false)));
}
if ($definition->isLazy()) {
@ -109,11 +125,11 @@ class YamlDumper extends Dumper
}
if ($definition->getFactoryMethod(false)) {
$code .= sprintf(" factory_method: %s\n", $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", $definition->getFactoryService(false));
$code .= sprintf(" factory_service: %s\n", $this->dumper->dump($definition->getFactoryService(false)));
}
if ($definition->getArguments()) {
@ -128,16 +144,23 @@ class YamlDumper extends Dumper
$code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
$code .= sprintf(" scope: %s\n", $scope);
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) = $decorated;
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()) {

View file

@ -91,9 +91,7 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn
$container->addResource(new FileResource($r->getFileName()));
if (!method_exists($class, '__construct')) {
$configuration = new $class();
return $configuration;
return new $class();
}
}
}

View file

@ -23,12 +23,12 @@ interface ExtensionInterface
/**
* Loads a specific configuration.
*
* @param array $config An array of configuration values
* @param array $configs An array of configuration values
* @param ContainerBuilder $container A ContainerBuilder instance
*
* @throws \InvalidArgumentException When provided tag is not defined in this extension
*/
public function load(array $config, ContainerBuilder $container);
public function load(array $configs, ContainerBuilder $container);
/**
* Returns the namespace to be used for this extension (XML namespace).

View file

@ -16,6 +16,8 @@ namespace Symfony\Component\DependencyInjection;
* for containers, allowing logic to be implemented based on a Container's state.
*
* @author Evan Villemez <evillemez@gmail.com>
*
* @deprecated since version 2.8, to be merged with ContainerInterface in 3.0.
*/
interface IntrospectableContainerInterface extends ContainerInterface
{

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\Resource\DirectoryResource;
/**
* DirectoryLoader is a recursive loader to go through directories.
*
* @author Sebastien Lavoie <seb@wemakecustom.com>
*/
class DirectoryLoader extends FileLoader
{
/**
* {@inheritdoc}
*/
public function load($file, $type = null)
{
$file = rtrim($file, '/');
$path = $this->locator->locate($file);
$this->container->addResource(new DirectoryResource($path));
foreach (scandir($path) as $dir) {
if ('.' !== $dir[0]) {
if (is_dir($path.'/'.$dir)) {
$dir .= '/'; // append / to allow recursion
}
$this->setCurrentDir($path);
$this->import($dir, null, false, $path);
}
}
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
if ('directory' === $type) {
return true;
}
return null === $type && is_string($resource) && '/' === substr($resource, -1);
}
}

View file

@ -93,8 +93,9 @@ class XmlFileLoader extends FileLoader
return;
}
$defaultDirectory = dirname($file);
foreach ($imports as $import) {
$this->setCurrentDir(dirname($file));
$this->setCurrentDir($defaultDirectory);
$this->import($import->getAttribute('resource'), null, (bool) XmlUtils::phpize($import->getAttribute('ignore-errors')), $file);
}
}
@ -147,7 +148,7 @@ class XmlFileLoader extends FileLoader
$definition = new Definition();
}
foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
if ($value = $service->getAttribute($key)) {
if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
@trigger_error(sprintf('The "%s" attribute of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
@ -157,6 +158,20 @@ class XmlFileLoader extends FileLoader
}
}
if ($value = $service->getAttribute('autowire')) {
$definition->setAutowired(XmlUtils::phpize($value));
}
if ($value = $service->getAttribute('scope')) {
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
if ($triggerDeprecation) {
@trigger_error(sprintf('The "scope" attribute of service "%s" in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
}
$definition->setScope(XmlUtils::phpize($value), false);
}
if ($value = $service->getAttribute('synchronized')) {
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
@ -171,6 +186,10 @@ class XmlFileLoader extends FileLoader
$definition->setFile($files[0]->nodeValue);
}
if ($deprecated = $this->getChildren($service, 'deprecated')) {
$definition->setDeprecated(true, $deprecated[0]->nodeValue);
}
$definition->setArguments($this->getArgumentsAsPhp($service, 'argument'));
$definition->setProperties($this->getArgumentsAsPhp($service, 'property'));
@ -230,12 +249,21 @@ class XmlFileLoader extends FileLoader
$parameters[$name] = XmlUtils::phpize($node->nodeValue);
}
if ('' === $tag->getAttribute('name')) {
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', (string) $service->getAttribute('id'), $file));
}
$definition->addTag($tag->getAttribute('name'), $parameters);
}
foreach ($this->getChildren($service, 'autowiring-type') as $type) {
$definition->addAutowiringType($type->textContent);
}
if ($value = $service->getAttribute('decorates')) {
$renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
$definition->setDecoratedService($value, $renameId);
$priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0;
$definition->setDecoratedService($value, $renameId, $priority);
}
return $definition;

View file

@ -95,12 +95,13 @@ class YamlFileLoader extends FileLoader
throw new InvalidArgumentException(sprintf('The "imports" key should contain an array in %s. Check your YAML syntax.', $file));
}
$defaultDirectory = dirname($file);
foreach ($content['imports'] as $import) {
if (!is_array($import)) {
throw new InvalidArgumentException(sprintf('The values in the "imports" key should be arrays in %s. Check your YAML syntax.', $file));
}
$this->setCurrentDir(dirname($file));
$this->setCurrentDir($defaultDirectory);
$this->import($import['resource'], null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file);
}
}
@ -164,8 +165,15 @@ class YamlFileLoader extends FileLoader
$definition->setClass($service['class']);
}
if (isset($service['shared'])) {
$definition->setShared($service['shared']);
}
if (isset($service['scope'])) {
$definition->setScope($service['scope']);
if ('request' !== $id) {
@trigger_error(sprintf('The "scope" key of service "%s" in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
}
$definition->setScope($service['scope'], false);
}
if (isset($service['synthetic'])) {
@ -189,6 +197,10 @@ class YamlFileLoader extends FileLoader
$definition->setAbstract($service['abstract']);
}
if (array_key_exists('deprecated', $service)) {
$definition->setDeprecated(true, $service['deprecated']);
}
if (isset($service['factory'])) {
if (is_string($service['factory'])) {
if (strpos($service['factory'], ':') !== false && strpos($service['factory'], '::') === false) {
@ -269,6 +281,10 @@ class YamlFileLoader extends FileLoader
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
}
if (!is_string($tag['name']) || '' === $tag['name']) {
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file));
}
$name = $tag['name'];
unset($tag['name']);
@ -283,8 +299,35 @@ class YamlFileLoader extends FileLoader
}
if (isset($service['decorates'])) {
if ('' !== $service['decorates'] && '@' === $service['decorates'][0]) {
throw new InvalidArgumentException(sprintf('The value of the "decorates" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['decorates'], substr($service['decorates'], 1)));
}
$renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
$definition->setDecoratedService($service['decorates'], $renameId);
$priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
$definition->setDecoratedService($service['decorates'], $renameId, $priority);
}
if (isset($service['autowire'])) {
$definition->setAutowired($service['autowire']);
}
if (isset($service['autowiring_types'])) {
if (is_string($service['autowiring_types'])) {
$definition->addAutowiringType($service['autowiring_types']);
} else {
if (!is_array($service['autowiring_types'])) {
throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
}
foreach ($service['autowiring_types'] as $autowiringType) {
if (!is_string($autowiringType)) {
throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file));
}
$definition->addAutowiringType($autowiringType);
}
}
}
$this->container->setDefinition($id, $definition);

View file

@ -81,12 +81,15 @@
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="configurator" type="callable" minOccurs="0" maxOccurs="1" />
<xsd:element name="factory" type="callable" minOccurs="0" maxOccurs="1" />
<xsd:element name="deprecated" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="autowiring-type" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" />
<xsd:attribute name="shared" type="boolean" />
<xsd:attribute name="scope" type="xsd:string" />
<xsd:attribute name="public" type="boolean" />
<xsd:attribute name="synthetic" type="boolean" />
@ -100,10 +103,12 @@
<xsd:attribute name="parent" type="xsd:string" />
<xsd:attribute name="decorates" type="xsd:string" />
<xsd:attribute name="decoration-inner-name" type="xsd:string" />
<xsd:attribute name="decoration-priority" type="xsd:integer" />
<xsd:attribute name="autowire" type="boolean" />
</xsd:complexType>
<xsd:complexType name="tag">
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:anyAttribute namespace="##any" processContents="lax" />
</xsd:complexType>

View file

@ -1,80 +1,14 @@
DependencyInjection Component
=============================
DependencyInjection manages your services via a robust and flexible Dependency
Injection Container.
Here is a simple example that shows how to register services and parameters:
```php
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
$sc = new ContainerBuilder();
$sc
->register('foo', '%foo.class%')
->addArgument(new Reference('bar'))
;
$sc->setParameter('foo.class', 'Foo');
$sc->get('foo');
```
Method Calls (Setter Injection):
```php
$sc = new ContainerBuilder();
$sc
->register('bar', '%bar.class%')
->addMethodCall('setFoo', array(new Reference('foo')))
;
$sc->setParameter('bar.class', 'Bar');
$sc->get('bar');
```
Factory Class:
If your service is retrieved by calling a static method:
```php
$sc = new ContainerBuilder();
$sc
->register('bar', '%bar.class%')
->setFactory(array('%bar.class%', 'getInstance'))
->addArgument('Aarrg!!!')
;
$sc->setParameter('bar.class', 'Bar');
$sc->get('bar');
```
File Include:
For some services, especially those that are difficult or impossible to
autoload, you may need the container to include a file before
instantiating your class.
```php
$sc = new ContainerBuilder();
$sc
->register('bar', '%bar.class%')
->setFile('/path/to/file')
->addArgument('Aarrg!!!')
;
$sc->setParameter('bar.class', 'Bar');
$sc->get('bar');
```
The DependencyInjection component allows you to standardize and centralize the
way objects are constructed in your application.
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/DependencyInjection/
$ composer install
$ phpunit
* [Documentation](https://symfony.com/doc/current/components/dependency_injection/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View file

@ -25,6 +25,8 @@ class Reference
/**
* Constructor.
*
* Note: The $strict parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param int $invalidBehavior The behavior when the service does not exist
* @param bool $strict Sets how this reference is validated
@ -62,9 +64,15 @@ class Reference
* Returns true when this Reference is strict.
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isStrict()
public function isStrict($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->strict;
}
}

View file

@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection;
/**
* ResettableContainerInterface defines additional resetting functionality
* for containers, allowing to release shared services when the container is
* not needed anymore.
*
* @author Christophe Coevoet <stof@notk.org>
*/
interface ResettableContainerInterface extends ContainerInterface
{
/**
* Resets shared services from the container.
*
* The container is not intended to be used again after being reset in a normal workflow. This method is
* meant as a way to release references for ref-counting.
* A subsequent call to ContainerInterface::get will recreate a new instance of the shared service.
*/
public function reset();
}

View file

@ -15,6 +15,8 @@ namespace Symfony\Component\DependencyInjection;
* Scope class.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
class Scope implements ScopeInterface
{

View file

@ -15,6 +15,8 @@ namespace Symfony\Component\DependencyInjection;
* Scope Interface.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
interface ScopeInterface
{

View file

@ -11,7 +11,7 @@
namespace Symfony\Component\DependencyInjection;
@trigger_error('The '.__NAMESPACE__.'\SimpleXMLElement method is deprecated since version 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
@trigger_error('The '.__NAMESPACE__.'\SimpleXMLElement class is deprecated since version 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\ExpressionLanguage\Expression;

View file

@ -19,9 +19,9 @@
"php": ">=5.3.9"
},
"require-dev": {
"symfony/yaml": "~2.1",
"symfony/config": "~2.2",
"symfony/expression-language": "~2.6"
"symfony/yaml": "~2.1|~3.0.0",
"symfony/config": "~2.2|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0"
},
"conflict": {
"symfony/expression-language": "<2.6"
@ -32,12 +32,15 @@
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
},
"autoload": {
"psr-4": { "Symfony\\Component\\DependencyInjection\\": "" }
"psr-4": { "Symfony\\Component\\DependencyInjection\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.8-dev"
}
}
}