From baaff20f4aa3b587617c05e201208527922871fd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 28 Aug 2017 17:40:54 +0200 Subject: [PATCH] [DI] Fix tracking env vars when merging configs (bis) --- .../MergeExtensionConfigurationPass.php | 62 +++++++------------ .../DependencyInjection/ContainerBuilder.php | 6 ++ .../MergeExtensionConfigurationPassTest.php | 11 +++- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php index 041d2215bad1f..3e4acf5664e76 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php @@ -45,12 +45,14 @@ public function process(ContainerBuilder $container) // this extension was not called continue; } - // EnvPlaceholderParameterBag tracks env vars when calling resolveValue(). - // Clone so that tracking is done in a dedicated bag. - $resolvingBag = clone $container->getParameterBag(); + $resolvingBag = $container->getParameterBag(); + if ($resolvingBag instanceof EnvPlaceholderParameterBag && $extension instanceof Extension) { + // create a dedicated bag so that we can track env vars per-extension + $resolvingBag = new MergeExtensionConfigurationParameterBag($resolvingBag); + } $config = $resolvingBag->resolveValue($config); - $tmpContainer = new ContainerBuilder($container->getParameterBag()); + $tmpContainer = new ContainerBuilder($resolvingBag); $tmpContainer->setResourceTracking($container->isTrackingResources()); $tmpContainer->addObjectResource($extension); if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) { @@ -63,13 +65,9 @@ public function process(ContainerBuilder $container) $extension->load($config, $tmpContainer); - if ($resolvingBag instanceof EnvPlaceholderParameterBag) { - // $resolvingBag keeps track of env vars encoutered *before* merging configs - if ($extension instanceof Extension) { - // but we don't want to keep track of env vars that are *overridden* when configs are merged - $resolvingBag = new MergeExtensionConfigurationParameterBag($extension, $resolvingBag); - } - $container->getParameterBag()->mergeEnvPlaceholders($resolvingBag); + if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) { + // don't keep track of env vars that are *overridden* when configs are merged + $resolvingBag->freezeAfterProcessing($extension); } $container->merge($tmpContainer); @@ -86,21 +84,18 @@ public function process(ContainerBuilder $container) */ class MergeExtensionConfigurationParameterBag extends EnvPlaceholderParameterBag { - private $beforeProcessingEnvPlaceholders; + private $processedEnvPlaceholders; - public function __construct(Extension $extension, parent $resolvingBag) + public function __construct(parent $parameterBag) { - $this->beforeProcessingEnvPlaceholders = $resolvingBag->getEnvPlaceholders(); - $config = $this->resolveEnvPlaceholders($extension->getProcessedConfigs()); - parent::__construct($this->resolveValue($config)); + parent::__construct($parameterBag->all()); + $this->mergeEnvPlaceholders($parameterBag); } - /** - * {@inheritdoc} - */ - public function get($name) + public function freezeAfterProcessing(Extension $extension) { - return $this->has($name) || (0 === strpos($name, 'env(') && ')' === substr($name, -1) && 'env()' !== $name) ? parent::get($name) : ''; + $this->processedEnvPlaceholders = array(); + $this->processMergedConfig($extension->getProcessedConfigs(), parent::getEnvPlaceholders()); } /** @@ -108,33 +103,22 @@ public function get($name) */ public function getEnvPlaceholders() { - // contains the list of env vars that are still used after configs have been merged - $envPlaceholders = parent::getEnvPlaceholders(); - - foreach ($envPlaceholders as $env => $placeholders) { - if (isset($this->beforeProcessingEnvPlaceholders[$env])) { - // for still-used env vars, keep track of their before-processing placeholders - $envPlaceholders[$env] += $this->beforeProcessingEnvPlaceholders[$env]; - } - } - - return $envPlaceholders; + return null !== $this->processedEnvPlaceholders ? $this->processedEnvPlaceholders : parent::getEnvPlaceholders(); } - /** - * Replaces-back env placeholders to their original "%env(FOO)%" version. - */ - private function resolveEnvPlaceholders($value) + private function processMergedConfig($value, array $envPlaceholders) { if (is_array($value)) { foreach ($value as $k => $v) { - $value[$this->resolveEnvPlaceholders($k)] = $this->resolveEnvPlaceholders($v); + $this->processMergedConfig($k, $envPlaceholders); + $this->processMergedConfig($v, $envPlaceholders); } } elseif (is_string($value)) { - foreach ($this->beforeProcessingEnvPlaceholders as $env => $placeholders) { + foreach ($envPlaceholders as $env => $placeholders) { foreach ($placeholders as $placeholder) { if (false !== stripos($value, $placeholder)) { - $value = str_ireplace($placeholder, "%env($env)%", $value); + $this->processedEnvPlaceholders[$env] = $placeholders; + break; } } } diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 2e8afa6545414..698080b9715e8 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -641,10 +641,16 @@ public function merge(ContainerBuilder $container) } if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) { + $envPlaceholders = $container->getParameterBag()->getEnvPlaceholders(); $this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag()); + } else { + $envPlaceholders = array(); } foreach ($container->envCounters as $env => $count) { + if (!$count && !isset($envPlaceholders[$env])) { + continue; + } if (!isset($this->envCounters[$env])) { $this->envCounters[$env] = $count; } else { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php index 3934418474bd6..033e6c00fc342 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php @@ -76,12 +76,13 @@ public function testOverriddenEnvsAreMerged() $container = new ContainerBuilder(); $container->registerExtension(new FooExtension()); $container->prependExtensionConfig('foo', array('bar' => '%env(FOO)%')); - $container->prependExtensionConfig('foo', array('bar' => '%env(BAR)%')); + $container->prependExtensionConfig('foo', array('bar' => '%env(BAR)%', 'baz' => '%env(BAZ)%')); $pass = new MergeExtensionConfigurationPass(); $pass->process($container); - $this->assertSame(array('FOO'), array_keys($container->getParameterBag()->getEnvPlaceholders())); + $this->assertSame(array('FOO', 'BAZ'), array_keys($container->getParameterBag()->getEnvPlaceholders())); + $this->assertSame(array('BAZ' => 1, 'FOO' => 0), $container->getEnvCounters()); } } @@ -94,6 +95,7 @@ public function getConfigTreeBuilder() $rootNode ->children() ->scalarNode('bar')->end() + ->scalarNode('baz')->end() ->end(); return $treeBuilder; @@ -116,5 +118,10 @@ public function load(array $configs, ContainerBuilder $container) { $configuration = $this->getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); + + if (isset($config['baz'])) { + $container->getParameterBag()->get('env(BOZ)'); + $container->resolveEnvPlaceholders($config['baz']); + } } }