【问题标题】:What is best practice to inject many similar services in symfony?在 symfony 中注入许多类似服务的最佳实践是什么?
【发布时间】:2020-08-07 15:42:33
【问题描述】:

我有许多服务差别很小 - swiftmailer 服务:

swiftmailer:
    default_mailer: default
    mailers:
        default:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_act:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_ACT)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_bbi:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_BBI)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_can:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_CAN)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_ffi:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_FFI)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_flip:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_FLIP)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_hscg:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_HSCG)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_ibn:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_IBN)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_pci:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_PCI)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_vop:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_VOP)%'
            spool:
                type: '%swiftmailer.spool.type%'
        spool_vue:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_VUE)%'
            spool:
                type: '%swiftmailer.spool.type%'

        no_spool_act:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_ACT)%'
        no_spool_bbi:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_BBI)%'
        no_spool_can:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_CAN)%'
        no_spool_ffi:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_FFI)%'
        no_spool_flip:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_FLIP)%'
        no_spool_hscg:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_HSCG)%'
        no_spool_ibn:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_IBN)%'
        no_spool_pci:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_PCI)%'
        no_spool_vop:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_VOP)%'
        no_spool_vue:
            url: '%env(CONFIG__PARAMETERS__MAILER_URL_VUE)%'

所以大概有 16 个服务。我需要在执行期间通过 VOP、VUE 等代码获取它们,就在发送邮件之前。

服务 id 如下所示:swiftmailer.mailer.spool_act

最简单的方法是创建一个包含所有这 16 个注入服务的类。但是不好看。

可以将它们分成 2 类 - 线轴和无线轴。然后每个人将进行 8 次注射。还是不太好,而且不能保证以后不需要更多。

一个人建议标记服务,并从这里通过标记注入集合:https://symfony.com/doc/current/service_container/tags.html#reference-tagged-services

我已经尝试过,但仍然没有找到没有过度设计的好解决方案。一个想法是创建 16 个类,并在每个类中注入 swifmailer 服务,如 swiftmailer.mailer.spool_act。然后在我的课堂上有发送方法,它从 swiftmailer.mailer.spool_act 调用发送。然后标记我创建的服务并像在那个 symfony 文档中那样使用迭代器注入。但这看起来像做简单的事情太复杂的方式和太多的代码。

什么是更好的解决方案?其他人应该也有类似的问题。我不明白我怎么找不到。

更新

我已经尝试过使用 instnacce of 的一个答案。将其调整为 symfony 3。

<services>
    <instanceof id="Swift_Mailer">
        <tag name="app.mailer"/>
    </instanceof>
</services>

<service id="vop.communication.sender.communication" parent="vop.communication.sender.email.abstract" class="Vop\CommunicationBundle\Sender\CommunicationSender" autowire="true">
<!--            todo change args if using autowire-->
            <argument type="service" id="vop_communication.communication_manager"/>
            <argument type="service" id="sonata.notification.backend"/>
            <argument key="$mailers" type="tagged" tag="app.mailer"/>
        </service>

/**
 * CommunicationSender constructor.
 *
 * @param CommunicationHistoryService $communicationHistoryService
 * @param ManagerInterface            $settingManager
 * @param CommunicationManager        $communicationManager
 * @param BackendInterface            $backend
 */
public function __construct(
    CommunicationHistoryService $communicationHistoryService,
    ManagerInterface $settingManager,
    CommunicationManager $communicationManager,
    BackendInterface $backend,
    iterable $mailers,  
    KernelInterface $kernel
) {
    parent::__construct($communicationHistoryService, $settingManager);

    $this->communicationManager = $communicationManager;
    $this->backend = $backend;
    $this->mailers = $mailers;
    $this->kernel = $kernel;
}

但在这种情况下 $this->mailers 是空的。为什么?

更新:

我想要做的是有 send($code) 功能,通过代码选择邮件并发送电子邮件。

【问题讨论】:

  • 我实际上没有在您的基本新问题中看到任何指向可迭代对象的内容。但是,我在下面的回答应该可以准确地告诉您您的要求。它没有工作吗? Here is a second approach 但它需要对服务定位器和标签有更多的了解。

标签: symfony dependency-injection


【解决方案1】:

根据您的代码,我假设您事先知道所有服务的 ID。在这种情况下,服务订阅者可能会工作。这是框架的 AbstractController 用来获取它的服务的东西。比如:

class SomeClass implements ServiceSubscriberInterface 
{
    /**
     * This will actually be a service locator 
     * containing only the services you specify
     *
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @required
     */
    public function setContainer(ContainerInterface $container)
    {
        $this->container = $container;
    }
    public static function getSubscribedServices() : array
    {
        return [
            'ACT' => 'swiftmailer.mailer.spool_act',
            'VOP' => 'swiftmailer.mailer.no_spool_vop',
        ];
    }
    public function someMethod() {
        $vop = $this->container->get('VOP');
        dump(get_class($vop));

此代码有许多可能的变体,但这是我所知道的最直接的一个。

【讨论】:

    【解决方案2】:

    这是一种可用于收集所有快速邮件的技术。我想这就是你所需要的。如果您需要将它们分成两个单独的标签,您可能需要编译器通过。

    services:
        _instanceof:
            Swift_Mailer:
                tags: ['app.mailer']
        App\YourServiceThatNeedsAllMailers:
            arguments:
                $mailers: !tagged_iterator app.mailer
    

    【讨论】:

    • 到目前为止,我还没有通过这个例子让它工作,但即使我找到了一种方法 - 我将如何通过代码识别服务?将有这些服务的实例集合。但是类名将是相同的。因此,据我所知,它是 swiftmailer.mailer.no_spool_act 例如?
    • 你没有在描述中描述你需要为不同的类型做其他事情。就我而言,您希望遍历所有 16 个服务并调用相同的方法。
    • 更新了描述 - 想要一个发送功能,通过代码选择邮件服务并发送邮件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多