Symfony2依赖注入容器子容器

时间:2013-05-24 06:56:40

标签: symfony service dependency-injection

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

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

2 个答案:

答案 0 :(得分: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标记名称。

一旦我完成了这个,我必须创建一个“特殊”文件(我将放入捆绑的DependencyInjection文件夹[for convention]),这是CompilerPass file
什么是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'))标记的服务,我们将这些服务(在这种情况下,特定于奏鸣曲管理包)添加到{{1这是一个$pool

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

ContainerBuilder

现在,您已经为此捆绑包注册了某种服务。

更专注于服务工厂
  

Symfony2的Service Container提供了一种强大的控制方式   对象的创建,允许您指定传递给的参数   构造函数以及调用方法和设置参数。   但是,有时候,这并不能为您提供所需的一切   构建你的对象。

或者更像是服务实例化的“入口点”。

答案 1 :(得分:0)

出于性能和可测试性的原因,确实没有建议注入整个容器。

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

... Service Factory是您正在寻找的。

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

那就是你所说的“子容器”。