获取控制器中的标记服务列表

时间:2018-05-21 21:46:14

标签: symfony symfony-3.3

我想要的是将服务添加到我希望稍后在我的控制器或服务中使用的服务容器。

所以我使用自定义标记 fbeen.admin

创建了两个服务

这里是:

services:
    app.test:
        class: AppBundle\Admin\TestAdmin
        tags:
            - { name: fbeen.admin }

    fbeen.admin.test:
        class: Fbeen\AdminBundle\Admin\TestAdmin
        tags:
            - { name: fbeen.admin }

现在我想在我的控制器中使用带有标签fbeen.admin的所有服务,但我不知道如何。

我遵循了How to work with service tags教程,但我仍然坚持这条规则:

$definition->addMethodCall('addTransport', array(new Reference($id)));

在某种程度上,应该调用TransportChain类的addTransport方法,但它似乎没有被调用。

即使它被调用,我仍然没有带有fbeen.admin标记的服务列表到我的控制器中。

我确信我错过了一些东西,但谁能解释我的意思呢?

P.S。我知道compilerPass在构建时运行,但是例如,sonata admin知道所有管理类,twig知道所有的枝条扩展。他们怎么知道?

感谢您阅读: - )

3 个答案:

答案 0 :(得分:2)

Symfony 3.3

容器被编译一次(在更频繁的调试中,但在生产中只编译一次)。您使用addMethodCall...管理的内容是,您从容器请求服务后,您将存储在$definition(在本例中为控制器)中。然后,容器将在初始化服务期间调用方法addMethodCall('method'..

它在容器中的样子:

// This is pseudo content of compiled container
$service = new MyController();
// This is what compiler pass addMethodCall will add, now its your 
// responsibility to implement method addAdmin to store admins in for 
// example class variable. This is as well way which sonata is using
$service->addAdmin(new AppBundle\Admin\TestAdmin());
$service->addAdmin(new AppBundle\Admin\TestAdmin());

return $service; // So you get fully initialized service

Symfony 3.4 +

你可以做的是:

// Your services.yaml
services:
    App/MyController/WantToInjectSerivcesController:
        arguments:
            $admins: !tagged fbeen.admin

// Your controller
class WantToInjectSerivcesController {
    public function __construct(iterable $admins) {
        foreach ($admins as $admin) {
            // you hot your services here
        }
    }
}

奖励自动标记您的服务。让我们说所有的控制器实现接口AdminInterface

// In your extension where you building container or your kernel build method
$container->registerForAutoconfiguration(AdminInterface::class)->addTag('fbeen.admin');

这将自动标记使用标记实现接口的所有服务。因此,您无需明确设置标记。

答案 1 :(得分:1)

这里需要注意的是:CompilerPass不会在编译器传递本身中运行'addTransport'(或者你可能称之为的任何东西) - 只是说'当时机正确 - 运行{{1} } class,带有这个数据'。查找发生位置的位置位于缓存目录($definition->addTransport(...))中,用于设置grep -R TransportChain var/cache/

当您第一次使用该服务时 - 只有在从容器中实例化类时才填充数据。

答案 2 :(得分:0)

这对我有用:

使用getTransports方法扩展TransportChain类:

public function getTransports()
{
    return $this->transports;
}

并在我的控制器中使用TransportChain服务:

use AppBundle\Mail\TransportChain;

$transportChain = $this->get(TransportChain::class);
$transports = $transportChain->getTransports();
// $transports is now an array with all the tagged services

感谢 Alister Bulman 推动我前进: - )