Symfony2服务容器:使用XML将服务数组参数作为参数注入另一个服务

Sob*_*dov 4 symfony

我有一个参数,应该代表我的services.xml文件中的服务数组:

<parameters>
    <parameter key="decorators.all" type="collection">
        <parameter type="service" id="decorator1" />
        <parameter type="service" id="decorator2" />
        <parameter type="service" id="decorator3" />
    </parameter>
</parameters>

<services>
    <service id="decorator1" class="\FirstDecorator" />
    <service id="decorator2" class="\SecondDecorator" />
    <service id="decorator3" class="\ThirdDecorator" />
</services>
Run Code Online (Sandbox Code Playgroud)

现在我想将此集合作为一组服务注入另一个服务:

<services>
    <service id="notifications_decorator" class="\NotificationsDecorator">
        <argument>%decorators.all%</argument>
    </service>
</services>
Run Code Online (Sandbox Code Playgroud)

但它不起作用.无法理解为什么.我错过了什么?

NHG*_*NHG 5

因此,您注入参数数组没有服务数组.您可以通过以下服务注入服务:

<services>
    <service id="notifications_decorator" class="\NotificationsDecorator">
        <argument type="service" id="decorator1"/>
        <argument type="service" id="decorator2"/>
        <argument type="service" id="decorator3"/>
    </service>
</services>
Run Code Online (Sandbox Code Playgroud)

或者(在我看来更好的方式)标记 decorators服务并notifications_decorator在编译过程中将它们注入.

更新:使用标记服务

在您的情况下,您必须像这样修改您的服务:

<services>
    <service id="decorator1" class="\FirstDecorator">
        <tag name="acme_decorator" />
    </service>
    <service id="decorator2" class="\SecondDecorator">
        <tag name="acme_decorator" />
    </service>
    <service id="decorator3" class="\ThirdDecorator">
        <tag name="acme_decorator" />
    </service>
</services>
Run Code Online (Sandbox Code Playgroud)

另外,您应该decorators.all<parameters>部分中删除参数.接下来,你必须添加类似addDectorator函数\NotificationsDecorator:

class NotificationsDecorator
{
    private $decorators = array();

    public function addDecorator($decorator)
    {
        $this->decorators[] = $decorator;
    }
    // more code
}
Run Code Online (Sandbox Code Playgroud)

如果你为decorators 编写一些接口并将其添加$decoratoraddDecorator函数类型,那将会很棒.

接下来,您必须编写自己的编译器传递并向他们询问标记服务并将此服务添加到另一个(simillarly to doc):

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;

class DecoratorCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('notifications_decorator')) {
            return;
        }

        $definition = $container->getDefinition('notifications_decorator');
        $taggedServices = $container->findTaggedServiceIds('acme_decorator');

        foreach ($taggedServices as $id => $attributes) {
            $definition->addMethodCall(
                'addDecorator',
                array(new Reference($id))
            );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,你应该在你的bundle类中添加你的内容DecoratorCompilerPass,Compiler如:

class AcmeDemoBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->addCompilerPass(new DecoratorCompilerPass());
    }
}
Run Code Online (Sandbox Code Playgroud)

祝好运!