将基于参数的服务注入其他服务

Luk*_*uke 5 configuration dependency-injection symfony

我有一个服务,让司机做实际的工作.驱动程序本身是在Symfony 2的上下文中只是另一项服务.

为了说明简化版本:

services:
  # The driver services.
  my_scope.mailer_driver_smtp:
    class: \My\Scope\Service\Driver\SmtpDriver

  my_scope.mailer_driver_mock:
    class: \My\Scope\Service\Driver\MockDriver

  # The actual service.
  my_scope.mailer:
    class: \My\Scope\Service\Mailer
    calls:
      - [setDriver, [@my_scope.mailer_driver_smtp]]
Run Code Online (Sandbox Code Playgroud)

如上所示,我可以将两个驱动程序服务中的任何一个注入到Mailer服务中.问题当然是注入的驱动程序服务是硬编码的.所以,我想参数化@my_scope.mailer_driver_smtp.

我通过添加一个条目来做到这一点 parameters.yml

my_scope_mailer_driver: my_scope.mailer_driver_smtp
Run Code Online (Sandbox Code Playgroud)

然后我可以在my中使用它config.yml并将参数分配给语义暴露配置[1]:

my_scope:
  mailer:
    driver: %my_scope_mailer_driver%
Run Code Online (Sandbox Code Playgroud)

最后,在Configuration我的bundle类中,我在容器上设置了一个参数:

$container->setParameter('my_scope.mailer.driver', $config['mailer']['driver'] );
Run Code Online (Sandbox Code Playgroud)

容器参数的值my_scope.mailer.driver现在等于my_scope.mailer_driver_smtp我在parameters.yml其中设置的值,因为我对它的理解是正确的,只是一个字符串.

如果我现在使用容器中的参数名称,我会收到一个错误,抱怨没有这样的服务.例如:

services:
  my_scope.mailer:
    class: \My\Scope\Service\Mailer
    calls:
      - [setDriver, [@my_scope.mailer.driver]]
Run Code Online (Sandbox Code Playgroud)

以上将导致错误:

[Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException]                                          
The service "my_scope.mailer" has a dependency on a non-existent service "my_scope.mailer.driver"
Run Code Online (Sandbox Code Playgroud)

现在的问题是,注入这个基于容器参数的服务的正确语法是什么?

[1] http://symfony.com/doc/current/cookbook/bundles/extension.html

Tou*_*uki 5

这个问题在这里有类似的答案

我认为使用这种定义的最佳方法是使用服务别名.
这可能看起来像这样

Acme\FooBundle\DependencyInjection\AcmeFooExtension

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');

    $alias = $config['mailer']['driver'];
    $container->setAlias('my_scope.mailer_driver', $alias);
}
Run Code Online (Sandbox Code Playgroud)

这将别名您在定义的服务my_scope.mailer.drivermy_scope.mailer_driver,你可以像任何其他服务中使用

services.yml

services:
    my_scope.mailer_driver:
        alias: my_scope.mailer_driver_smtp # Fallback

    my_scope.mailer_driver_smtp:
        class: My\Scope\Driver\Smtp

    my_scope.mailer_driver_mock:
        class: My\Scope\Driver\Mock

    my_scope.mailer:
        class: My\Scope\Mailer
        arguments:
            - @my_scope.mailer_driver
Run Code Online (Sandbox Code Playgroud)

使用这样的设计,只要更改config.yml中my_scope.mailer_driver参数,服务就会更改. 请注意,如果服务不存在,扩展将抛出异常.


Ale*_*ski 5

使用服务容器表达式语言,您可以访问配置文件中的以下两个函数:

  • service - 返回给定的服务(参见下面的示例);
  • 参数 - 返回特定的参数值(语法就像服务一样)

因此,要将参数名称转换为服务引用,您需要以下内容:

parameters:
  my_scope_mailer_driver: my_scope.mailer_driver_smtp

services:
  my_scope.mailer:
    class: \My\Scope\Service\Mailer
    calls:
      - [setDriver, [@=service(parameter('my_scope_mailer_driver'))]]
Run Code Online (Sandbox Code Playgroud)