From 80eb60974da1e7dde9214e644ca668342364ceff Mon Sep 17 00:00:00 2001 From: Thomas Bibaut Date: Thu, 19 Dec 2024 14:46:32 +0100 Subject: [PATCH] [DependencyInjection] Fix env default processor with scalar node --- .../Compiler/ValidateEnvPlaceholdersPass.php | 59 +++++++++++++++---- .../ValidateEnvPlaceholdersPassTest.php | 30 ++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php index 2d6542660b39c..75bd6097deee6 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php @@ -49,17 +49,8 @@ public function process(ContainerBuilder $container) $defaultBag = new ParameterBag($resolvingBag->all()); $envTypes = $resolvingBag->getProvidedTypes(); foreach ($resolvingBag->getEnvPlaceholders() + $resolvingBag->getUnusedEnvPlaceholders() as $env => $placeholders) { - $values = []; - if (false === $i = strpos($env, ':')) { - $default = $defaultBag->has("env($env)") ? $defaultBag->get("env($env)") : self::TYPE_FIXTURES['string']; - $defaultType = null !== $default ? get_debug_type($default) : 'string'; - $values[$defaultType] = $default; - } else { - $prefix = substr($env, 0, $i); - foreach ($envTypes[$prefix] ?? ['string'] as $type) { - $values[$type] = self::TYPE_FIXTURES[$type] ?? null; - } - } + $values = $this->getPlaceholderValues($env, $defaultBag, $envTypes); + foreach ($placeholders as $placeholder) { BaseNode::setPlaceholder($placeholder, $values); } @@ -100,4 +91,50 @@ public function getExtensionConfig(): array $this->extensionConfig = []; } } + + /** + * @param array> $envTypes + * + * @return array + */ + private function getPlaceholderValues(string $env, ParameterBag $defaultBag, array $envTypes): array + { + if (false === $i = strpos($env, ':')) { + [$default, $defaultType] = $this->getParameterDefaultAndDefaultType("env($env)", $defaultBag); + + return [$defaultType => $default]; + } + + $prefix = substr($env, 0, $i); + if ('default' === $prefix) { + $parts = explode(':', $env); + array_shift($parts); // Remove 'default' prefix + $parameter = array_shift($parts); // Retrieve and remove parameter + + [$defaultParameter, $defaultParameterType] = $this->getParameterDefaultAndDefaultType($parameter, $defaultBag); + + return [ + $defaultParameterType => $defaultParameter, + ...$this->getPlaceholderValues(implode(':', $parts), $defaultBag, $envTypes), + ]; + } + + $values = []; + foreach ($envTypes[$prefix] ?? ['string'] as $type) { + $values[$type] = self::TYPE_FIXTURES[$type] ?? null; + } + + return $values; + } + + /** + * @return array{0: string, 1: string} + */ + private function getParameterDefaultAndDefaultType(string $name, ParameterBag $defaultBag): array + { + $default = $defaultBag->has($name) ? $defaultBag->get($name) : self::TYPE_FIXTURES['string']; + $defaultType = null !== $default ? get_debug_type($default) : 'string'; + + return [$default, $defaultType]; + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php index 8c5c4cc32323e..17ef87c3fffad 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php @@ -73,6 +73,36 @@ public function testDefaultEnvWithoutPrefixIsValidatedInConfig() $this->doProcess($container); } + public function testDefaultProcessorWithScalarNode() + { + $container = new ContainerBuilder(); + $container->setParameter('parameter_int', 12134); + $container->setParameter('env(FLOATISH)', 4.2); + $container->registerExtension($ext = new EnvExtension()); + $container->prependExtensionConfig('env_extension', $expected = [ + 'scalar_node' => '%env(default:parameter_int:FLOATISH)%', + ]); + + $this->doProcess($container); + $this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig())); + } + + public function testDefaultProcessorAndAnotherProcessorWithScalarNode() + { + $this->expectException(InvalidTypeException::class); + $this->expectExceptionMessageMatches('/^Invalid type for path "env_extension\.scalar_node"\. Expected one of "bool", "int", "float", "string", but got one of "int", "array"\.$/'); + + $container = new ContainerBuilder(); + $container->setParameter('parameter_int', 12134); + $container->setParameter('env(JSON)', '{ "foo": "bar" }'); + $container->registerExtension($ext = new EnvExtension()); + $container->prependExtensionConfig('env_extension', [ + 'scalar_node' => '%env(default:parameter_int:json:JSON)%', + ]); + + $this->doProcess($container); + } + public function testEnvsAreValidatedInConfigWithInvalidPlaceholder() { $this->expectException(InvalidTypeException::class);