Symfony AutoWire 多个服务同一个类

Posted

技术标签:

【中文标题】Symfony AutoWire 多个服务同一个类【英文标题】:Symfony AutoWire multiple services same class 【发布时间】:2019-05-02 12:38:11 【问题描述】:

我正在将一个大型应用程序升级到 4.2

并且控制器内部的$this->get(".....") 已被弃用,应该使用 AutoWire。

我遇到的问题是我有 2 个服务,它们实际上来自同一个类(只是不同的构造函数参数)。

services.yml

services:
  service.a:
    class: Namespace\MyClass
    arguments: [ "argument1" ]

  service.b:
    class: Namespace\MyClass
    arguments: [ "argument2" ]

控制器:

public function demoAction() 
  $serviceA = $this->get("service.a");
  $serviceB = $this->get("service.b");

以及有问题的结果:

public function demoAction(MyClass $serviceA, MyClass $serviceB) 

我们可以使用别名来服务定义,例如:

MyClass: '@service.a'

但我不能使用虚拟/假类,例如(没有现有的):

MyPseudClass: '@service.b'

您如何在自动连线模式下处理此类情况?

我可以创建从基础扩展的“伪”类,只是为了获得不同的类名,但这感觉很奇怪。

【问题讨论】:

你有一些很好的答案。我有时使用的一种方法是再创建两个类 MyClassA 和 MyClassB 都从 MyClass 扩展,否则为空。然后你可以输入提示并使用 autowire 来避免任何 services.yaml 条目。 是的,我知道,试过了,有效,但最好的代码越少! 【参考方案1】:

从 4.2 开始,您可以定义命名的自动装配别名。这应该工作:

services:
    Namespace\MyClass $serviceA: '@service.a'
    Namespace\MyClass $serviceB: '@service.b'

在 Symfony 3.4 和 4.1 中,您可以使用绑定来代替 - 但这不太具体,因为它没有考虑类型:

services:
    _defaults:
        bind:
            $serviceA: '@service.a'
            $serviceB: '@service.b'

【讨论】:

thx - 这行得通,所以我采用别名方式,看起来合法且有效。在某些地方,我依赖于 services_dev.yml 更改某些服务的类的事实,因此“类型”并不稳定,所以我在这些地方使用绑定方式,绑定方式是面向未来的方式吗?还是会很快被弃用? 我想你的意思是services: _defaults: bind: Namespace\MyClass $serviceA: '@service.a' Namespace\MyClass $serviceB: '@service.b':【参考方案2】:

您仍然可以在 service.yml 文件中使用“@servicename”,因此按名称连接它们/这是一个示例,其中我将几个不同的 Logger 连接到服务构造函数中。

# App/Subscribers/WebhookLoggingListener.php file
public function __construct(
    LoggerInterface $logger, 
    LoggerInterface $mailgunLog
 

# services.yml
App\Subscribers\WebhookLoggingListener:
    arguments:
        $logger: "@logger"
        $mailgunLog: "@monolog.logger.mailgun"
    tags:
       -  name: kernel.event_listener, event: kernel.request, method: onKernelRequest

您还可以将它们绑定到变量名(在 services.yaml 文件头部的 services: _defaults: 中,但如果它们不会被重用,我认为最好保持配置更加本地化)。

【讨论】:

【参考方案3】:

另一个选项是实现Factory Pattern。此模式将使您能够根据提供的参数创建服务。

# services.yml
service.a:
    class: App\MyClass
    factory: 'App\Factory\StaticMyClassFactory:createMyClass'
    arguments:
        - ['argument1']

service.b:
    class: App\MyClass
    factory: 'App\Factory\StaticMyClassFactory:createMyClass'
    arguments:
        - ['argument2']

你的 StaticMyClassFactory 看起来像这样

class StaticMyClassFactory
  
    public static function createMyClass($argument)
    
        // Return your class based on the argument passed
        $myClass = new MyClass($argument);

        return $myClass;
    

【讨论】:

以上是关于Symfony AutoWire 多个服务同一个类的主要内容,如果未能解决你的问题,请参考以下文章

Symfony4 使用外部类库作为服务

使用 Symfony 自动装配时是不是可以排除多个目录?

为啥我不能将此 Spring Boot 服务类注入 JUnit 测试类?预计至少有 1 个 bean 有资格作为 autowire 候选者

当我为JAX WS类添加@Autowire注释时,它在spring boot中给出了空指针异常错误

扩展非容器类的 Autowire 类

wicket,spring jpa存储库 - @Autowire上的nullpointer