diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 1cd1f043f4757..cab370e80feef 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG * Make `ContainerBuilder::registerAttributeForAutoconfiguration()` propagate to attribute classes that extend the registered class * Add argument `$prepend` to `FileLoader::construct()` to prepend loaded configuration instead of appending it * [BC BREAK] When used in the `prependExtension()` method, the `ContainerConfigurator::import()` method now prepends the configuration instead of appending it + * Cast env vars to null or bool when referencing them using `#[Autowire(env: '...')]` depending on the signature of the corresponding parameter 7.0 --- diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 155d1680da961..18cb09d6345ba 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -306,6 +306,17 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a foreach ($attributes as $attribute) { $attribute = $attribute->newInstance(); + $value = $attribute instanceof Autowire ? $attribute->value : null; + + if (\is_string($value) && str_starts_with($value, '%env(') && str_ends_with($value, ')%')) { + if ($parameter->getType() instanceof \ReflectionNamedType && 'bool' === $parameter->getType()->getName() && !str_starts_with($value, '%env(bool:')) { + $attribute = new Autowire(substr_replace($value, 'bool:', 5, 0)); + } + if ($parameter->isDefaultValueAvailable() && $parameter->allowsNull() && null === $parameter->getDefaultValue() && !preg_match('/(^|:)default:/', $value)) { + $attribute = new Autowire(substr_replace($value, 'default::', 5, 0)); + } + } + $invalidBehavior = $parameter->allowsNull() ? ContainerInterface::NULL_ON_INVALID_REFERENCE : ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE; try { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index fc0f057b4b6fe..7b62925c4e6e9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -1397,4 +1397,18 @@ public function testLazyNotCompatibleWithAutowire() $this->assertSame('Using both attributes #[Lazy] and #[Autowire] on an argument is not allowed; use the "lazy" parameter of #[Autowire] instead.', $e->getMessage()); } } + + public function testAutowireAttributeWithEnvVar() + { + $container = new ContainerBuilder(); + + $container->register('foo', AutowireAttributeEnv::class)->setAutowired(true); + + (new AutowirePass())->process($container); + + $definition = $container->getDefinition('foo'); + + $this->assertSame('%env(bool:ENABLED)%', $container->resolveEnvPlaceholders($definition->getArguments()[0])); + $this->assertSame('%env(default::OPTIONAL)%', $container->resolveEnvPlaceholders($definition->getArguments()[1])); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php index e8f8e62a331e8..c249a9e2f19de 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php @@ -81,6 +81,17 @@ public function __construct( } } +class AutowireAttributeEnv +{ + public function __construct( + #[Autowire(env: 'ENABLED')] + public bool $enabled, + #[Autowire(env: 'OPTIONAL')] + public ?string $optional = null, + ) { + } +} + interface AsDecoratorInterface { }