Description
Symfony version(s) affected
^6.2.0
Description
Symfony 6.2 introduced enums as service parameters: https://symfony.com/blog/new-in-symfony-6-2-improved-enum-support
One of the examples includes defining an array of enums as a parameter:
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use App\Entity\BlogPost;
return static function (ContainerConfigurator $container) {
$container->parameters()
// ...
->set('app.some_parameter', SomeEnum::Foo)
->set('app.another_parameter', [SomeEnum::Foo, SomeEnum::Bar]);
};
Although, when you try to inject said parameter into a service, the container produces a warning when it's asked to instantiate the service:
Warning: Undefined array key "app.another_parameter"
How to reproduce
- Define an array of enum as a service parameter, as stated in the documentation.
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use App\SomeEnum;
return static function (ContainerConfigurator $container) {
$container->parameters()
// ...
->set('app.some_parameter', SomeEnum::Foo)
->set('app.another_parameter', [SomeEnum::Foo, SomeEnum::Bar]);
};
- Next, create a class and inject both of the parameters into the constructor method:
namespace App\Service;
use App\SomeEnum;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
final class DemoService
{
public function __construct(
#[Autowire('%app.some_parameter%')]
private SomeEnum $enum,
#[Autowire('%app.another_parameter%')]
private array $enums
)
{
dd($this->enum, $this->enums);
}
}
- Ask the container to instantiate
DemoService
. - While
app.some_parameter
can be resolved, the container will warn about the absence ofapp.another_parameter
.
I created a repo demonstrating this issue: See https://github.com/imba28/symfony-enum-array-parameters-bug for a complete example
Possible Solution
I think this is due to a bug in the class PhpDumper
. Whenever a parameter contains an enum, it is marked as a dynamic parameter that must be resolved using $container->getParameter()
:
symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Lines 1516 to 1522 in 1dcb0f9
However, the routine dumping the parameters lacks an equivalent check:
symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Lines 1918 to 1934 in 1dcb0f9
For that reason, the generated file var/cache/dev/ContainerXYZ/getDemoServiceService.php
includes
return $container->privates['App\\Service\\DemoService'] = new \App\Service\DemoService(\App\SomeEnum::Foo, $container->parameters['app.another_parameter']);
instead of
return $container->privates['App\\Service\\DemoService'] = new \App\Service\DemoService(\App\SomeEnum::Foo, $container->getParameter('app.another_parameter'));
which eventually fails, since app.another_parameter
has been previously marked as a dynamic parameter and thus is not part of $container->parameters
.
Possible fix
Recursively traverse $value
and determine if there's an enum hidden somewhere and place the check in this condition: https://github.com/symfony/symfony/blob/6.2/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php#L1928
If it does, dump $this->getParameter(%s)
instead of $this->parameters[%s]
.
Additional Context
No response