简体   繁体   English

如何在Symfony2扩展程序中通过setter注入来注入服务?

[英]How can I inject service with setter injection in my Symfony2 extension?

I defined some configuration in my bundle extension: 我在捆绑扩展中定义了一些配置:

public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $config = $this->processConfiguration($configuration, $configs);

    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
    $loader->load('services.yml');

    if (!empty($config['my_config'])) {
        $my_config = $config['my_config'];
        if (is_array($my_config)) {
            $service_definition = $container->getDefinition('my_service');
            foreach ($my_config as $name => $class) {
                $reflection_class = new \ReflectionClass($class);

                if (!$reflection_class->implementsInterface('MyInterface')) {
                    throw new \Exception(
                        "'$class' must implement MyInterface'"
                    );
                }

                $service_definition->addMethodCall('addElement', array($name, $class));
            }
        }
    }
}

And then in MyService I have: 然后在MyService我有:

public function addElement($name, $class_name) {
    $this->elements[$name] = new $class_name();
}

All these elements implement MyInterface and all is fine until I have new elements that has some dependencies on other services or parameters. 所有这些元素都实现MyInterface并且在我拥有对其他服务或参数有一定依赖性的新元素之前,一切都很好。 These new classes can be defined as services to benefit from DI. 这些新类可以定义为可以从DI中受益的服务。 But now I need to rewrite MyExtension and MyService to meet new requirements. 但是现在我需要重写MyExtensionMyService以满足新的要求。

How can I get services from container in setter injection that is invoked this way? 如何通过以这种方式调用的setter注入从容器中获取服务?

I found a solution. 我找到了解决方案。 I can just test my $class variable: 我可以测试$class变量:

  • If it is classname of POPO then just use constructor of it in setter injection as I already do 如果它是POPO的类名,那么就像我已经在setter注入中使用它的构造函数
  • If it is a name of service I can provide service object to my setter injection by wrapping $class in Symfony\\Component\\DependencyInjection\\Reference object. 如果它是服务的名称,则可以通过将$class包装在Symfony\\Component\\DependencyInjection\\Reference对象中来为setter注入提供服务对象。

In the MyExtension I need next line: MyExtension我需要下一行:

$service_definition->addMethodCall('addElement', array($name, new Reference($class)));

and in MyService : 并在MyService

public function addElement($name, $object) {
    if (class_exist($object)) {
        $this->elements[$name] = new $object();
    }
    elseif ($object instanceof MyInterface) {
        $this->elements[$name] = $object;
    } else {
        // throw an exception
    }
}

But if you don't have a lot of POPO you can register all your objects as services and as mentioned by @Marino Di Clemente you can just use tagging for getting all the services that can do the work for you. 但是,如果您没有很多POPO,则可以将所有对象注册为服务,就像@Marino Di Clemente提到的那样,您可以使用标记来获取所有可以为您完成工作的服务。

In this case you will have to define all objects as services and add appropriate tags in its configs. 在这种情况下,您将必须将所有对象定义为服务,并在其配置中添加适当的标签。 Then you need get it in extension and pass to the setter injection. 然后,您需要扩展它并传递给setter注入。 Code will be similar as mine but instead of parsing config you will need to get tagged services: 代码将与我的相似,但是除了解析配置之外,您还需要获取带标签的服务:

public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();
    $config = $this->processConfiguration($configuration, $configs);

    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
    $loader->load('services.yml');

    $service_definition = $container->getDefinition('my_service');
    $taggedServices = $container->findTaggedServiceIds(
        'my_tag'
    );
    foreach ($taggedServices as $id => $tags) {
        $service_definition->addMethodCall(
            'addElement',
            array(new Reference($id))
        );
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM