Symfony: How can I get hold of tagged services and processed configuration at the same time?

坚强是说给别人听的谎言 提交于 2020-01-24 22:10:13

问题


I'm trying to symfony Configuration to determine how to wire some tagged services, but am running into problems. I've tried to boil the problem down into as little code as possible to help explain, but still - sorry for the length!

Here's the configuration part of things...

class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder('acme_test');
        $treeBuilder
            ->getRootNode()
            ->addDefaultsIfNotSet()
            ->children()
                ->scalarNode('email_sender')->isRequired()->end()
                ->scalarNode('email_title')->defaultValue('Notification email')->end()
            ->end();

        return $treeBuilder;
    }
}
acme_test:
    email_sender: 'test@example.com'

I've also got an arbitrary service which takes $emailSender and $emailTitle. It's been tagged with the 'arbitrary-services' tags in services.yaml:

class ArbitraryService
{
    protected $emailSender;

    protected $emailTitle;

    public function __construct(string $emailSender, string $emailTitle)
    {
        $this->emailSender = $emailSender;
        $this->emailTitle = $emailTitle;
    }
}
services:
    App\Acme\TestBundle\ArbitraryService:
        tags: ['arbitrary-services']

The Symfony documentation tells me to do my tagged services finding in a CompilerPass - fair enough:

class AcmeTestCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $configs = $container->getExtensionConfig('acme_test');

        $taggedServices = $container->findTaggedServiceIds('arbitrary-services');

        // Great - got the tagged service definitions
        // Now going to wire things passed via config into those services (e.g. via binding)

        dump('From CompilerPass:');
        dump($taggedServices);
        dump($configs);
    }
}

In my full use-case, I want to tag different directories of services to cause them to receive different params based upon config options (e.g. services tagged with inject.alpha get parameters based upon config keys in acme -> alpha).

The problem tho' is that at this point, whilst the tagged services return fine, the configuration has not been processed, and so we're missing the email_title key which has a defaultValue:

wobble@pop-os:~/test$ bin/console c:c
"From CompilerPass:"
array:1 [
  "App\Acme\TestBundle\ArbitraryService" => array:1 [
    0 => []
  ]
]
array:1 [
  0 => array:1 [
    "email_sender" => "test@example.com"
  ]
]

If I check within the Extension / load() class on the other hand...

class AcmeTestExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $taggedServices = $container->findTaggedServiceIds('arbitrary-services');

        dump('From load()');
        dump($taggedServices);
        dump($config);
    }
}

I'll find that I have the fully-processed configuration (yey!) but no tagged services as presumably I'm too early for that (hence the docs telling me to use a CompilerPass):

wobble@pop-os:~/test$ bin/console c:c
"From load()"
[]
array:2 [
  "email_sender" => "test@example.com"
  "email_title" => "Notification email"
]

Can anyone please tell me if it's possible to get hold of both the processed configuration and the tagged services at the same time? Thanks!

I've pushed the test code that reproduces my problem up on a github repo here: https://github.com/WubbleWobble/symfony-stack-overflow-1


回答1:


Managed to figure a solution. Moved the compiler pass inside the extension class and then shared the processed config across to it via a class property :)

class AcmeTestExtension extends Extension implements CompilerPassInterface
{
    /** @var array */
    protected $processedConfig;

    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $this->processedConfig = $this->processConfiguration($configuration, $configs);
    }

    public function process(ContainerBuilder $container)
    {
        $taggedServices = $container->findTaggedServiceIds('arbitrary-services');

        // Great - got the tagged service definitions
        // Now going to wire things passed via config into those services (e.g. via binding)

        dump('From CompilerPass:');
        dump($taggedServices);
        dump($this->processedConfig);
    }
}
"From CompilerPass:"
array:2 [
    "App\Acme\TestBundle\ArbitraryService" => array:1 [
        0 => []
    ]
]
array:2 [
    "email_sender" => "test@example.com"
    "email_title" => "Notification email"
]


来源:https://stackoverflow.com/questions/58877892/symfony-how-can-i-get-hold-of-tagged-services-and-processed-configuration-at-th

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!