From 679f25eaceeecd319229032183953fdbbe479e2b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Sep 2021 11:29:28 +0200 Subject: [PATCH] [DependencyInjection] Make auto-aliases private by default --- .../DependencyInjection/CHANGELOG.md | 1 + .../Compiler/AutoAliasServicePass.php | 21 +++++++++++++- .../Compiler/PassConfig.php | 4 +-- .../ReplaceAliasByActualDefinitionPass.php | 29 ++++++++++++++++++- ...ReplaceAliasByActualDefinitionPassTest.php | 6 ++-- 5 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index d2fa12a70e7d..46cd7f69ded0 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add `service_closure()` to the PHP-DSL * Add support for autoconfigurable attributes on methods, properties and parameters + * Make auto-aliases private by default 5.3 --- diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutoAliasServicePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutoAliasServicePass.php index 03420683a205..b150e70e6d5b 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutoAliasServicePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutoAliasServicePass.php @@ -20,6 +20,8 @@ */ class AutoAliasServicePass implements CompilerPassInterface { + private $privateAliases = []; + /** * {@inheritdoc} */ @@ -33,9 +35,26 @@ public function process(ContainerBuilder $container) $aliasId = $container->getParameterBag()->resolveValue($tag['format']); if ($container->hasDefinition($aliasId) || $container->hasAlias($aliasId)) { - $container->setAlias($serviceId, new Alias($aliasId, true)); + $alias = new Alias($aliasId, $container->getDefinition($serviceId)->isPublic()); + $container->setAlias($serviceId, $alias); + + if (!$alias->isPublic()) { + $alias->setPublic(true); + $this->privateAliases[] = $alias; + } } } } } + + /** + * @internal to be removed in Symfony 6.0 + */ + public function getPrivateAliases(): array + { + $privateAliases = $this->privateAliases; + $this->privateAliases = []; + + return $privateAliases; + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 47f51c247894..b850e36c0f2e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -51,7 +51,7 @@ public function __construct() ]; $this->optimizationPasses = [[ - new AutoAliasServicePass(), + $autoAliasServicePass = new AutoAliasServicePass(), new ValidateEnvPlaceholdersPass(), new ResolveDecoratorStackPass(), new ResolveChildDefinitionsPass(), @@ -78,7 +78,7 @@ public function __construct() $this->removingPasses = [[ new RemovePrivateAliasesPass(), - new ReplaceAliasByActualDefinitionPass(), + (new ReplaceAliasByActualDefinitionPass())->setAutoAliasServicePass($autoAliasServicePass), new RemoveAbstractDefinitionsPass(), new RemoveUnusedDefinitionsPass(), new AnalyzeServiceReferencesPass(), diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php index 18e69fdcb762..bb2ba0d54073 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -25,6 +25,19 @@ class ReplaceAliasByActualDefinitionPass extends AbstractRecursivePass { private $replacements; + private $autoAliasServicePass; + + /** + * @internal to be removed in Symfony 6.0 + * + * @return $this + */ + public function setAutoAliasServicePass(AutoAliasServicePass $autoAliasServicePass): self + { + $this->autoAliasServicePass = $autoAliasServicePass; + + return $this; + } /** * Process the Container to replace aliases with service definitions. @@ -36,15 +49,25 @@ public function process(ContainerBuilder $container) // First collect all alias targets that need to be replaced $seenAliasTargets = []; $replacements = []; + + $privateAliases = $this->autoAliasServicePass ? $this->autoAliasServicePass->getPrivateAliases() : []; + foreach ($privateAliases as $target) { + $target->setDeprecated('symfony/dependency-injection', '5.4', 'Accessing the "%alias_id%" service directly from the container is deprecated, use dependency injection instead.'); + } + foreach ($container->getAliases() as $definitionId => $target) { $targetId = (string) $target; // Special case: leave this target alone if ('service_container' === $targetId) { continue; } - // Check if target needs to be replaces + // Check if target needs to be replaced if (isset($replacements[$targetId])) { $container->setAlias($definitionId, $replacements[$targetId])->setPublic($target->isPublic()); + + if ($target->isDeprecated()) { + $container->getAlias($definitionId)->setDeprecated(...array_values($target->getDeprecation('%alias_id%'))); + } } // No need to process the same target twice if (isset($seenAliasTargets[$targetId])) { @@ -69,6 +92,10 @@ public function process(ContainerBuilder $container) $container->setDefinition($definitionId, $definition); $container->removeDefinition($targetId); $replacements[$targetId] = $definitionId; + + if ($target->isPublic() && $target->isDeprecated()) { + $definition->addTag('container.private', $target->getDeprecation('%service_id%')); + } } $this->replacements = $replacements; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php index d7b0a280c146..7e398bf7ffe1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php @@ -31,8 +31,8 @@ public function testProcess() $bDefinition = new Definition('\stdClass'); $container->setDefinition('b', $bDefinition); - $container->setAlias('a_alias', 'a')->setPublic(true); - $container->setAlias('b_alias', 'b')->setPublic(true); + $container->setAlias('a_alias', 'a')->setPublic(true)->setDeprecated('foo/bar', '1.2', '%alias_id%'); + $container->setAlias('b_alias', 'b')->setPublic(true)->setDeprecated('foo/bar', '1.2', '%alias_id%'); $container->setAlias('container', 'service_container'); @@ -40,11 +40,13 @@ public function testProcess() $this->assertTrue($container->has('a'), '->process() does nothing to public definitions.'); $this->assertTrue($container->hasAlias('a_alias')); + $this->assertTrue($container->getAlias('a_alias')->isDeprecated()); $this->assertFalse($container->has('b'), '->process() removes non-public definitions.'); $this->assertTrue( $container->has('b_alias') && !$container->hasAlias('b_alias'), '->process() replaces alias to actual.' ); + $this->assertTrue($container->getDefinition('b_alias')->hasTag('container.private')); $this->assertTrue($container->has('container'));