用编译器通道覆盖 symfony 服务标签

Override a symfony service tag with a compiler pass

我正在尝试使用编译器通道覆盖 symfony 服务定义中的标记。以服务为例 data_collector.translation.

目标是停用数据收集器服务以禁用 symfony 网络开发人员工具栏中的元素。为此,我必须将 data_collector 标记的 priority 设置为 0

我也可以在我自己的服务定义中覆盖它:

services:

    data_collector.translation:
        class: 'Symfony\Component\Translation\DataCollector\TranslationDataCollector'
        tags:
           - {name: 'data_collector', priority: '0'}
        arguments: [@translator.data_collector]

但是因为我想为一些数据收集器执行此操作,所以我需要知道数据收集器定义的强制参数。优先级对所有收集器都一样,因此我只需要收集器的名称即可禁用它。

所以我写了下面的编译过程:

class DataCollectorCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('data_collector.translation')) {
            return;
        }
        $definition = $container->getDefinition('data_collector.translation');

        $tags = $definition->getTags();

        $tags['data_collector'][0]['priority'] = 0;

        $definition->setTags($tags);

        $container->setDefinition('data_collector.translation', $definition);
    }
}

为了让事情更连贯:当我 运行 这个命令时:

$ php app/console container:debug --show-private --tag='data_collector'

我得到以下输出:

data_collector.translation @WebProfiler/Collector/translation.html.twig translation 0 Symfony\Component\Translation\DataCollector\TranslationDataCollector

因此即使在调试器中的优先级也设置为0

但出于某种原因,该元素仍显示在工具栏中。

我做错了什么?是否有另一种机制可以覆盖编译器过程中的标签?

编译器通过运行(通过打印输出测试)
我正在使用 Symfony 2.7.1

你能试试这个吗?

    if (!$container->hasDefinition('data_collector.form')) {
        return;
    }
    $definition = $container->getDefinition('data_collector.form');

    $definition->clearTags();

    $container->setDefinition('data_collector.form', $definition);

为什么不使用您的编译器传递来直接操作包含所有这些收集器的服务的服务 Definition

如果我查看compiler pass responsible for loading the data collector,似乎它们都是使用方法调用注入进行注入的。

您可以使用编译器传递重写方法调用数组,使用 setMethodCallsremoveMethodCall、... Definition 实体的方法。

方法调用操作文档:link

事实证明代码确实有效,唯一的问题是,CompilerPass 在 FrameworkBundle 的一部分 ProfilerPass 之后 运行。将我的包与 CompilerPass 放在 AppKernel 中的 FrameworkBundle 之前解决了问题(更多 information here)。对于甚至不启动数据收集器,最好删除所有标签,而不是仅将优先级设置为 0.

这就是最终解决方案的样子:

class DataCollectorCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $collectorsToRemove = [
            'data_collector.form',
            'data_collector.translation',
            'data_collector.logger',
            'data_collector.ajax',
            'data_collector.twig'
        ];

        foreach($collectorsToRemove as $dataCollector) {

            if (!$container->hasDefinition($dataCollector)) {
                continue;
            }
            $definition = $container->getDefinition($dataCollector);

            $definition->clearTags();
        }
    }
}