如何使服务像 SwiftMailer 一样在 kernel.terminate 上工作?

How to make a Service works on kernel.terminate like SwiftMailer works?

我想知道如何编写仅在 kernel.terminate 上执行的服务。

例如当我打电话时:

$message = (new \Swift_Message('A new book has been added'))
            ->setFrom('system@example.com')
            ->setTo('contact@les-tilleuls.coop')
            ->setBody(sprintf('The book #%d has been added.', $book->getId()));
$this->mailer->send($message);

我知道内核会向客户端发送响应,然后才会发送电子邮件。

我有很多可以在 kernel.terminate 上调用的服务,但我不知道如何编写它们以便仅在该事件上调用。

现在,我正在订阅者中编写代码:

public static function getSubscribedEvents()
    {
        return [
            KernelEvents::TERMINATE => [['doHeavyStuff', EventPriorities::POST_RESPOND]]
            ];
    }

但以这种方式工作意味着我只需要处理请求和响应,我不想依赖于响应。

if($method===Request::METHOD_PUT && isset($response['@type']) && $response['@type']==='Partner'){
 $this->notificationManager->sendNotificationAboutCart($response['partner']['id'],
                                                       $response['partner']['name']);
}

我不知道是否清楚,但是如果我想在我的代码中的任何地方调用 notificationManager 并且该管理器仅在 kernel.terminate.

上工作,那就太好了

一个简单、天真的实现。

您的服务的 send() 方法实际上并未发送任何内容,只是添加了另一条消息,以便在时机成熟时发送。

class ShinyService {
    private $messages = [];

    public function send($message) {
        $this->messages[] = $message;
    }

    public function processMessages()
    {
        foreach ($this->messages as $message) {
            // do the actual work, e.g. sending the message
        }
    }
}

然后是依赖此服务的订阅者,因此它被注入到订阅者实例中:

class ShinySubscriber implements EventSubscriberInterface
{

    private $service;

    public function __construct(ShinyService $service) {
        $this->service = $service;
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::TERMINATE => [
                ['processMessages', 10]
            ],
        ];
    }

    public function processMessages(TerminateEvent $event)
    {
        $this->service->processMessages();
    }
}

这样你就可以在任何地方注入ShinyService,随时调用ShinyService::send(),消息只会在KernelEvents::TERMINATE发送。

请记住,如果您使用 PHP-FPM,此事件仅在发送响应后运行。来自 docs:

Internally, the HttpKernel makes use of the fastcgi_finish_request PHP function. This means that at the moment, only the PHP FPM server API is able to send a response to the client while the server's PHP process still performs some tasks. With all other server APIs, listeners to kernel.terminate are still executed, but the response is not sent to the client until they are all completed.