Symfony 3:如何根据某些运行时变量动态注入服务

Symfony 3: How can I inject a service dynamically depending on some runtime variable

假设我有以下 interface/concrete 类:

interface EmailFormatter

class CvEmailFormatter implements EmailFormatter
class RegistrationEmailFormatter implements EmailFormatter
class LostPasswordEmailFormatter implements EmailFormatter

然后我有一个自定义 'mailer' 服务,该服务从我的控制器操作中调用以发送电子邮件。

根据发送的电子邮件类型,我有哪些选项可以将 EmailFormatter 的正确实现注入到我的邮件程序服务中?

我会创建一个服务,在运行时选择正确的格式化程序,或者是某种工厂,或者如果你的格式化程序有依赖关系,也许是你从容器中注入格式化程序的服务。像这样:

class MailController extends AbstractController
{
    private $mailer;
    private $mailFormatterSelector;

    public function __construct(...) { ... }

    public function someAction()
    {
        // Do stuff ...

        if (...some condition) {
            $formatter = $this->mailFormatterSelector->getRegisterMailFormatter();
        } else {
            $formatter = $this->mailFormatterSelector->getLostPasswordEmailFormatter();
        }
        $mailer->sendEmail($formatter);

        // Do more stuff ...
    }
}

class MailFormatterSelector()
{
    private $registrationFormatter;

    public function __construct(EmailFormatter $registrationFormatter, ...)
    {
        $this->registrationFormatter = $registrationFormatter;
        ...
    }

    public function getRegisterMailFormatter(): EmailFormatter
    {
        return $this->registrationFormatter;
    }

    // ...
}

或者,如果您必须在构造期间将格式化程序传递到您的邮件程序中,您还可以创建多个具有不同别名的不同设置实例,然后根据需要将它们注入到服务和控制器中,如下所示:

# config/services.yaml
mailer1:
    class: MyMailler
    arguments:
        $formatter: '@formatter1'
mailer2:
    class: MyMailler
    arguments:
        $formatter: '@formatter2'

MyMailController:
    arguments:
        $mailer: '@mailer2'

然后在您的控制器或操作中,您可以通过以下方式传入 mailer1、mailer2、...(可能使用更好的名称)。