0

是否可以将一些服务放入另一个容器中,该容器将缩小到特定的一组服务?还是将某些特定服务分离​​到某种子容器中?我问这个问题是因为我需要将一组服务注入另一个服务,而将整个容器投入服务是,我相信,是个坏主意。当然,我可以在我的服务类中为我想要注入的所有服务创建一个属性,但这是我试图避免的解决方案。

我将不胜感激,如果您需要有关该问题的更多信息,请询问。

4

2 回答 2

1

基本上,您可以通过编写一些带有特殊名称的“标记”服务来使用 DIC。
为此,您需要将您的服务定义到一个文件中(遵循 DIC 规范)并以特定方式标记它们(在这种情况下,代码将由 Sonata Admin Bundle 获取,用于解释)

# MyBundle/Resources/config/admin.yml
services:
    sonata.admin.tag:
        class: YourNS\AdminBundle\Admin\BlogAdmin
        tags:
            - { name: sonata.admin, manager_type: orm, group: posts, label: "Blog" }
        arguments:
            - ~
            - YourNS\AdminBundle\Entity\Course
            - 'SonataAdminBundle:CRUD'
        calls:
            - [ setTranslationDomain, [YourNSAdminBundle]]

在这种情况下,我正在定义一个名为sonata.admin.tag标签的服务sonata.admin
我可以定义十几个,所有这些都带有sonata.admin.tag标签名称。

完成此操作后,我必须创建一个“特殊”文件(我将把它放入 bundle 的DependencyInjection文件夹 [用于约定]),它是一个CompilerPass文件.
什么是 CompilerPass 文件?

编译器通道让您有机会操作已在服务容器中注册的其他服务定义。[...] 编译器通道最常见的用例之一是使用标记服务(阅读有关组件中标记的更多信息“使用标记服务”部分)。

这正是您所需要的!

现在您必须搜索(到此文件中)标记为(在此特定示例中)的服务sonata.admin

class AddDependencyCallsCompilerPass implements CompilerPassInterface
{
  /**
  * {@inheritDoc}
  */
    public function process(ContainerBuilder $container)
    {
        $groupDefaults = $admins = $classes = array();

        $pool = $container->getDefinition('sonata.admin.pool');

        foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $tags) {
            foreach ($tags as $attributes) {
                $definition = $container->getDefinition($id);

                $arguments = $definition->getArguments();

                if (strlen($arguments[0]) == 0) {
                    $definition->replaceArgument(0, $id);
                }

                if (strlen($arguments[2]) == 0) {
                    $definition->replaceArgument(2, 'SonataAdminBundle:CRUD');
                }

                $this->applyConfigurationFromAttribute($definition, $attributes);
                $this->applyDefaults($container, $id, $attributes);

                $arguments = $definition->getArguments();

                $admins[] = $id;
                //other logic here
                $pool->addMethodCall('setAdminClasses', array($classes));

正如您在此处看到的,我们正在搜索带有sonata.admin( $container->findTaggedServiceIds('sonata.admin')) 标记的服务,并将这些服务(在这种情况下,是特定于奏鸣曲管理包的)添加$poolContainerBuilder

现在,我们必须将 CompilerPass 注册到我们的捆绑文件中(您在将捆绑注册到应用程序之前创建的那个)

class SonataAdminBundle extends Bundle
{
    /**
    * {@inheritDoc}
    */
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new AddDependencyCallsCompilerPass());
    }
}

现在,您已经为这个捆绑包注册了某种服务。服务工厂更面向

Symfony2 的服务容器提供了一种强大的方法来控制对象的创建,允许您指定传递给构造函数的参数以及调用方法和设置参数。然而,有时这不会为您提供构建对象所需的一切。

或将其视为服务实例化的“入口点”。

于 2013-05-24T13:40:21.197 回答
0

出于性能和可测试性的原因,确实不推荐注入整个容器。

如果所有依赖项的构造函数或 getter/setter 注入不是您想要的方式...

...服务工厂是您正在寻找的。

通过这种方式,您可以构建一个包含其他服务的服务并只注入这个服务。

那将是您正在谈论的“子容器”。

于 2013-05-24T07:14:49.607 回答