diff --git a/.appveyor.yml b/.appveyor.yml index 34d3a70333..4b417c5dfc 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -54,6 +54,7 @@ test_script: - SET X=0 - SET SYMFONY_PHPUNIT_SKIPPED_TESTS=phpunit.skipped - copy /Y c:\php\php.ini-min c:\php\php.ini + - IF %APPVEYOR_REPO_BRANCH% neq master (rm -Rf src\Symfony\Bridge\PhpUnit) - php phpunit src\Symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! - copy /Y c:\php\php.ini-max c:\php\php.ini - php phpunit src\Symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! diff --git a/.travis.yml b/.travis.yml index 191da7d344..9b87cfd534 100644 --- a/.travis.yml +++ b/.travis.yml @@ -200,6 +200,12 @@ install: SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*') fi + - | + # Skip the phpunit-bridge on not-master branches when $deps is empty + if [[ ! $deps && $TRAVIS_BRANCH != master ]]; then + COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n') + fi + - | # Install symfony/flex if [[ $deps = low ]]; then diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php index a3c8acaf56..2efffa1b98 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php @@ -60,6 +60,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe $analyzedContainer = $container; } try { + $remainingInlinedIds = []; $this->connectedIds = $this->notInlinedIds = $container->getDefinitions(); do { if ($this->analyzingPass) { @@ -83,8 +84,10 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe } } - foreach ($this->inlinedIds as $id => $isPublic) { - if (!$isPublic) { + foreach ($this->inlinedIds as $id => $isPublicOrNotShared) { + if ($isPublicOrNotShared) { + $remainingInlinedIds[$id] = $id; + } else { $container->removeDefinition($id); $analyzedContainer->removeDefinition($id); } @@ -94,6 +97,14 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe if ($this->inlinedIds && $this->repeatedPass) { $this->repeatedPass->setRepeat(); } + + foreach ($remainingInlinedIds as $id) { + $definition = $container->getDefinition($id); + + if (!$definition->isShared() && !$definition->isPublic()) { + $container->removeDefinition($id); + } + } } finally { $this->container = null; $this->connectedIds = $this->notInlinedIds = $this->inlinedIds = []; @@ -131,7 +142,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe } $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); - $this->inlinedIds[$id] = $definition->isPublic(); + $this->inlinedIds[$id] = $definition->isPublic() || !$definition->isShared(); $this->notInlinedIds[$this->currentId] = true; if ($definition->isShared()) { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php index 5cee002306..23fe4cabab 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php @@ -34,6 +34,8 @@ class ResolveBindingsPass extends AbstractRecursivePass */ public function process(ContainerBuilder $container) { + $this->usedBindings = $container->getRemovedBindingIds(); + try { parent::process($container); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 2baa632adc..2246965bf8 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -124,6 +124,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface private $removedIds = []; + private $removedBindingIds = []; + private static $internalTypes = [ 'int' => true, 'float' => true, @@ -1483,6 +1485,35 @@ class ContainerBuilder extends Container implements TaggedContainerInterface $this->getCompiler()->log($pass, $this->resolveEnvPlaceholders($message)); } + /** + * Gets removed binding ids. + * + * @return array + * + * @internal + */ + public function getRemovedBindingIds() + { + return $this->removedBindingIds; + } + + /** + * Adds a removed binding id. + * + * @param int $id + * + * @internal + */ + public function addRemovedBindingIds($id) + { + if ($this->hasDefinition($id)) { + foreach ($this->getDefinition($id)->getBindings() as $key => $binding) { + list(, $bindingId) = $binding->getValues(); + $this->removedBindingIds[(int) $bindingId] = true; + } + } + } + /** * Returns the Service Conditionals. * diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php index 13584973af..9dd7ce4112 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php @@ -61,6 +61,8 @@ class ServiceConfigurator extends AbstractServiceConfigurator { parent::__destruct(); + $this->container->addRemovedBindingIds($this->id); + if (!$this->definition instanceof ChildDefinition) { $this->container->setDefinition($this->id, $this->definition->setInstanceofConditionals($this->instanceof)); } else { diff --git a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php index 62ebbde7f5..0ccaf22e39 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php @@ -91,6 +91,8 @@ abstract class FileLoader extends BaseFileLoader */ protected function setDefinition($id, Definition $definition) { + $this->container->addRemovedBindingIds($id); + if ($this->isLoadingInstanceof) { if (!$definition instanceof ChildDefinition) { throw new InvalidArgumentException(sprintf('Invalid type definition "%s": ChildDefinition expected, "%s" given.', $id, \get_class($definition))); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php index 83f2da12a7..1aaca2f156 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Bar.php @@ -13,8 +13,11 @@ namespace Symfony\Component\DependencyInjection\Tests\Fixtures; class Bar implements BarInterface { + public $quz; + public function __construct($quz = null, \NonExistent $nonExistent = null, BarInterface $decorated = null, array $foo = []) { + $this->quz = $quz; } public static function create(\NonExistent $nonExistent = null, $factory = null) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/defaults_bindings.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/defaults_bindings.xml new file mode 100644 index 0000000000..d943dfad2d --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/defaults_bindings.xml @@ -0,0 +1,15 @@ + + + + + value + + value + + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/defaults_bindings2.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/defaults_bindings2.xml new file mode 100644 index 0000000000..db41330f85 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/defaults_bindings2.xml @@ -0,0 +1,10 @@ + + + + + overridden + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/defaults_bindings.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/defaults_bindings.yml new file mode 100644 index 0000000000..ca5e5048de --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/defaults_bindings.yml @@ -0,0 +1,11 @@ +services: + _defaults: + bind: + $quz: value + $foo: [value] + + bar: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\Bar + + foo: + class: stdClass diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/defaults_bindings2.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/defaults_bindings2.yml new file mode 100644 index 0000000000..01fc5af624 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/defaults_bindings2.yml @@ -0,0 +1,7 @@ +services: + _defaults: + bind: + $quz: overridden + + bar: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\Bar diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index b3d3943a10..b57f10c597 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; @@ -898,4 +899,20 @@ class XmlFileLoaderTest extends TestCase $dump = $dumper->dump(); $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_tsantos.php', $dumper->dump()); } + + /** + * The pass may throw an exception, which will cause the test to fail. + */ + public function testOverriddenDefaultsBindings() + { + $container = new ContainerBuilder(); + + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('defaults_bindings.xml'); + $loader->load('defaults_bindings2.xml'); + + (new ResolveBindingsPass())->process($container); + + $this->assertSame('overridden', $container->get('bar')->quz); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 804ae7f976..609a54d0fd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; @@ -823,4 +824,20 @@ class YamlFileLoaderTest extends TestCase $tagged = $container->findTaggedServiceIds('bar'); $this->assertCount(1, $tagged); } + + /** + * The pass may throw an exception, which will cause the test to fail. + */ + public function testOverriddenDefaultsBindings() + { + $container = new ContainerBuilder(); + + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('defaults_bindings.yml'); + $loader->load('defaults_bindings2.yml'); + + (new ResolveBindingsPass())->process($container); + + $this->assertSame('overridden', $container->get('bar')->quz); + } }