diff --git a/src/Symfony/Component/Config/Definition/BaseNode.php b/src/Symfony/Component/Config/Definition/BaseNode.php index f3ae891bad392..3d7fd85603355 100644 --- a/src/Symfony/Component/Config/Definition/BaseNode.php +++ b/src/Symfony/Component/Config/Definition/BaseNode.php @@ -26,7 +26,7 @@ abstract class BaseNode implements NodeInterface { const DEFAULT_PATH_SEPARATOR = '.'; - private static $placeholderUniquePrefix; + private static $placeholderUniquePrefixes = []; private static $placeholders = []; protected $name; @@ -74,7 +74,7 @@ public static function setPlaceholder(string $placeholder, array $values): void } /** - * Sets a common prefix for dynamic placeholder values. + * Adds a common prefix for dynamic placeholder values. * * Matching configuration values will be skipped from being processed and are returned as is, thus preserving the * placeholder. An exact match provided by {@see setPlaceholder()} might take precedence. @@ -83,7 +83,7 @@ public static function setPlaceholder(string $placeholder, array $values): void */ public static function setPlaceholderUniquePrefix(string $prefix): void { - self::$placeholderUniquePrefix = $prefix; + self::$placeholderUniquePrefixes[] = $prefix; } /** @@ -93,7 +93,7 @@ public static function setPlaceholderUniquePrefix(string $prefix): void */ public static function resetPlaceholders(): void { - self::$placeholderUniquePrefix = null; + self::$placeholderUniquePrefixes = []; self::$placeholders = []; } @@ -513,8 +513,10 @@ private static function resolvePlaceholderValue($value) return self::$placeholders[$value]; } - if (self::$placeholderUniquePrefix && 0 === strpos($value, self::$placeholderUniquePrefix)) { - return []; + foreach (self::$placeholderUniquePrefixes as $placeholderUniquePrefix) { + if (0 === strpos($value, $placeholderUniquePrefix)) { + return []; + } } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php index 264dd8046c819..7fe14a9f4ccd0 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php @@ -79,11 +79,11 @@ public function process(ContainerBuilder $container) $container->getParameterBag()->mergeEnvPlaceholders($resolvingBag); } - throw $e; - } finally { if ($configAvailable) { BaseNode::resetPlaceholders(); } + + throw $e; } if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) { @@ -95,6 +95,10 @@ public function process(ContainerBuilder $container) $container->getParameterBag()->add($parameters); } + if ($configAvailable) { + BaseNode::resetPlaceholders(); + } + $container->addDefinitions($definitions); $container->addAliases($aliases); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php index d5db48cc30645..a2cb3bda5ed96 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/MergeExtensionConfigurationPassTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; use PHPUnit\Framework\TestCase; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Resource\FileResource; @@ -128,6 +129,23 @@ public function testThrowingExtensionsGetMergedBag() $this->assertSame(['FOO'], array_keys($container->getParameterBag()->getEnvPlaceholders())); } + + public function testReuseEnvPlaceholderGeneratedByPreviousExtension() + { + if (!property_exists(BaseNode::class, 'placeholderUniquePrefixes')) { + $this->markTestSkipped('This test requires symfony/config ^4.4.11|^5.0.11|^5.1.3'); + } + + $container = new ContainerBuilder(); + $container->registerExtension(new FooExtension()); + $container->registerExtension(new TestCccExtension()); + $container->prependExtensionConfig('foo', ['bool_node' => '%env(bool:MY_ENV_VAR)%']); + $container->prependExtensionConfig('test_ccc', ['bool_node' => '%env(bool:MY_ENV_VAR)%']); + + (new MergeExtensionConfigurationPass())->process($container); + + $this->addToAssertionCount(1); + } } class FooConfiguration implements ConfigurationInterface @@ -139,6 +157,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->children() ->scalarNode('bar')->end() ->scalarNode('baz')->end() + ->booleanNode('bool_node')->end() ->end(); return $treeBuilder; @@ -166,6 +185,8 @@ public function load(array $configs, ContainerBuilder $container) $container->getParameterBag()->get('env(BOZ)'); $container->resolveEnvPlaceholders($config['baz']); } + + $container->setParameter('foo.param', 'ccc'); } } @@ -194,3 +215,36 @@ public function load(array $configs, ContainerBuilder $container) throw new \Exception(); } } + +final class TestCccConfiguration implements ConfigurationInterface +{ + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('test_ccc'); + $treeBuilder->getRootNode() + ->children() + ->booleanNode('bool_node')->end() + ->end(); + + return $treeBuilder; + } +} + +final class TestCccExtension extends Extension +{ + public function getAlias(): string + { + return 'test_ccc'; + } + + public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface + { + return new TestCccConfiguration(); + } + + public function load(array $configs, ContainerBuilder $container) + { + $configuration = $this->getConfiguration($configs, $container); + $this->processConfiguration($configuration, $configs); + } +}