4

我有一个参数应该代表我的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>

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

<services>
    <service id="notifications_decorator" class="\NotificationsDecorator">
        <argument>%decorators.all%</argument>
    </service>
</services>

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

4

4 回答 4

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>

或者(在我看来更好的方式)标记 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>

另外,您应该从部分中删除decorators.all参数。<parameters>接下来,您必须为以下添加类似addDectorator功能\NotificationsDecorator

class NotificationsDecorator
{
    private $decorators = array();

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

如果您为decorator's 编写一些接口并将其添加为$decoratorforaddDecorator函数的类型,那就太好了。

接下来,您必须编写自己的编译器通行证并询问他们有关标记服务的信息,并将此服务添加到另一个服务(类似于 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))
            );
        }
    }
}

最后,您应该将您的添加DecoratorCompilerPassCompiler您的捆绑类中,例如:

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

        $container->addCompilerPass(new DecoratorCompilerPass());
    }
}

祝你好运!

于 2013-09-05T06:51:14.203 回答
2

CompilerPassInterface标记服务(或任何您需要的)和使用服务数组而不是方法调用的方法略有不同。以下是与@NHG 答案的不同之处:

<!-- Service definition (factory in my case) -->
<service id="example.factory" class="My\Example\SelectorFactory">
    <argument type="collection" /> <!-- list of services to be inserted by compiler pass -->
</service>

编译器通行证:

/*
 * Used to build up factory with array of tagged services definition
 */
class ExampleCompilerPass implements CompilerPassInterface
{
    const SELECTOR_TAG = 'tagged_service';

    public function process(ContainerBuilder $container)
    {
        $selectorFactory = $container->getDefinition('example.factory');
        $selectors = [];
        foreach ($container->findTaggedServiceIds(self::SELECTOR_TAG) as $selectorId => $tags) {
            $selectors[] = $container->getDefinition($selectorId);
        }

        $selectorFactory->replaceArgument(0, $selectors);
    }
}
于 2015-06-16T08:15:38.067 回答
1

在 yaml 中,您可以执行以下操作:

app.example_conditions:
    class: AppBundle\Example\Conditions
    arguments:
        [[ "@app.example_condition_1", "@app.example_condition_2", "@app.example_condition_3",  "@app.example_condition_4" ]]

并在AppBundle\Example\Conditions您收到数组...

于 2017-03-13T21:52:58.617 回答
-1

Symfony 5.3+ 和 php 8.0+

class NotificationsDecorator
{
    private $decorators;

    public function __construct(
        #[TaggedIterator('app.notifications_decorators')] iterable $decorators
    ) {
        $this->decorators = $decorators;
    }
}

#[Autoconfigure(tags: ['app.notifications_decorators'])]
interface DecoratorInterface
{
}

class FirstDecorator implements DecoratorInterface
{
}
于 2022-01-31T13:47:51.317 回答