【问题标题】:Symfony 5.3: Async emails sent immediatelySymfony 5.3:立即发送异步电子邮件
【发布时间】:2022-01-21 17:19:34
【问题描述】:

编辑:这个问题是在尝试在同一个应用程序中同时拥有同步和同步电子邮件时出现的。没有说清楚。在撰写本文时,这是不可能的,至少不像这里尝试的那样简单。请参阅下面@msg 的 cmets。

配置为异步发送电子邮件而不是立即发送电子邮件的电子邮件服务。这发生在doctrineamqp 被选为MESSENGER_TRANSPORT_DSN 时。 doctrine 传输成功创建 messenger_messages 表,但没有内容。这告诉我观察到MESSENGER_TRANSPORT_DSN。使用 RabbitMQ 'Hello World' 教程对 amqp 的简单测试表明它已正确配置。

我在下面的代码中遗漏了什么?

如下所示的序列摘要:添加机会 -> OppEmailService 创建电子邮件内容 -> 从 EmailerService 获取 TemplatedEmail() 对象(未显示) -> 将 TemplatedEmail() 对象提交给 LaterEmailService,配置为异步。

messenger.yaml:

framework:
    messenger:
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'
            sync: 'sync://'

        routing:
            'App\Services\NowEmailService': sync
            'App\Services\LaterEmailService': async

OpportunityController:

class OpportunityController extends AbstractController
{

    private $newOpp;
    private $templateSvc;

    public function __construct(OppEmailService $newOpp, TemplateService $templateSvc)
    {
        $this->newOpp = $newOpp;
        $this->templateSvc = $templateSvc;
    }
...
    public function addOpp(Request $request): Response
    {
...
        if ($form->isSubmitted() && $form->isValid()) {
...
            $volunteers = $em->getRepository(Person::class)->opportunityEmails($opportunity);
            $this->newOpp->oppEmail($volunteers, $opportunity);
...
    }

OppEmailService:

class OppEmailService
{

    private $em;
    private $makeMail;
    private $laterMail;

    public function __construct(
            EmailerService $makeMail,
            EntityManagerInterface $em,
            LaterEmailService $laterMail
    )
    {
        $this->makeMail = $makeMail;
        $this->em = $em;
        $this->laterMail = $laterMail;
    }
...
    public function oppEmail($volunteers, $opp): array
    {
...
            $mailParams = [
                'template' => 'Email/volunteer_opportunities.html.twig',
                'context' => ['fname' => $person->getFname(), 'opportunity' => $opp,],
                'recipient' => $person->getEmail(),
                'subject' => 'New volunteer opportunity',
            ];
            $toBeSent = $this->makeMail->assembleEmail($mailParams);
            $this->laterMail->send($toBeSent);
...
    }

}

LaterEmailService:

namespace App\Services;

use Symfony\Component\Mailer\MailerInterface;

class LaterEmailService
{

    private $mailer;

    public function __construct(MailerInterface $mailer)
    {
        $this->mailer = $mailer;
    }

    public function send($email)
    {
        $this->mailer->send($email);
    }

}

【问题讨论】:

  • 在 messenger.yaml 中的“路由”下,您应该将消息类映射到传输,而不是像您所做的那样将服务映射到传输。
  • 我对 Message 类的理解是它期望 $context 是一个字符串。 See this。在symfonycasts 他们只将所有电子邮件显示为异步
  • 消息类是一种 Dto,它保存消息处理程序所需要的数据。它可以包含任何数据,而不是必需的字符串。当推送到消息总线时,消息无论如何都会被序列化。整个过程应该是这样的:你创建一个消息,将它推送到一个消息总线(MessageBusInterface)。收到消息后,处理程序会对其进行处理。
  • 我在您的代码中看不到将消息推送到 MessageBusInterface::dispatch 的部分。在 OpportunityController 中,您调用 OppEmailService,后者又调用 LaterEmailService,后者发送电子邮件。这里不涉及 Symfony Messager。
  • 如前所述,您的framework.messenger.routing 配置错误。您应该映射消息类,而不是服务。

标签: php symfony symfony-messenger


【解决方案1】:

我最终创建了作为每日cron 作业运行的控制台命令。每个命令都会调用一个创建和发送电子邮件的服务。用例是每天发送给注册用户的少量电子邮件,通知他们影响他们的操作。下面是一个例子:

控制台命令:

class NewOppsEmailCommand extends Command
{

    private $mailer;
    private $oppEmail;
    private $twig;

    public function __construct(OppEmailService $oppEmail, EmailerService $mailer, Environment $twig)
    {
        $this->mailer = $mailer;
        $this->oppEmail = $oppEmail;
        $this->twig = $twig;

        parent::__construct();
    }

    protected static $defaultName = 'app:send:newoppsemaiils';

    protected function configure()
    {
        $this->setDescription('Sends email re: new opps to registered');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $emails = $this->oppEmail->oppEmail();

        $output->writeln($emails . ' email(s) were sent');

        return COMMAND::SUCCESS;
    }

}

OppEmailService:

class OppEmailService
{

    private $em;
    private $mailer;

    public function __construct(EmailerService $mailer, EntityManagerInterface $em)
    {
        $this->mailer = $mailer;
        $this->em = $em;
    }

    /**
     * Send new opportunity email to registered volunteers
     */
    public function oppEmail()
    {
        $unsentEmail = $this->em->getRepository(OppEmail::class)->findAll(['sent' => false], ['volunteer' => 'ASC']);
        if (empty($unsentEmail)) {
            return 0;
        }

        $email = 0;
        foreach ($unsentEmail as $recipient) {
            $mailParams = [
                'template' => 'Email/volunteer_opportunities.html.twig',
                'context' => [
                    'fname' => $recipient->getVolunteer()->getFname(),
                    'opps' => $recipient->getOpportunities(),
                ],
                'recipient' => $recipient->getVolunteer()->getEmail(),
                'subject' => 'New opportunities',
            ];
            $this->mailer->assembleEmail($mailParams);
            $recipient->setSent(true);
            $this->em->persist($recipient);
            $email++;
        }
        $this->em->flush();

        return $email;
    }

}

电子邮件服务:

class EmailerService
{

    private $em;
    private $mailer;

    public function __construct(EntityManagerInterface $em, MailerInterface $mailer)
    {
        $this->em = $em;
        $this->mailer = $mailer;
    }

    public function assembleEmail($mailParams)
    {
        $sender = $this->em->getRepository(Person::class)->findOneBy(['mailer' => true]);
        $email = (new TemplatedEmail())
                ->to($mailParams['recipient'])
                ->from($sender->getEmail())
                ->subject($mailParams['subject'])
                ->htmlTemplate($mailParams['template'])
                ->context($mailParams['context'])
        ;

        $this->mailer->send($email);

        return $email;
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-15
    • 2018-04-13
    • 2011-05-06
    • 2015-04-16
    • 2017-07-13
    • 2011-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多