简体   繁体   English

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

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

I was wondering how to write a service that is executed only on kernel.terminate .我想知道如何编写仅在kernel.terminate上执行的服务。

For instance when I call:例如,当我打电话时:

$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);

I know that the kernel will send a response to the client and only AFTER that will send the email.我知道 kernel 将向客户端发送响应,并且仅在发送 email 之后。

I have a lot of service that could be called on kernel.terminate but I don't know how to write them in order to be called only on that event.我有很多服务可以在kernel.terminate上调用,但我不知道如何编写它们以便仅在该事件中调用。

For now, I am writing write code in a subscriber:现在,我正在订阅者中编写编写代码:

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

But working this way mean that I have to deal only with the Request and the Response and I do not want to depend on the Response.但是以这种方式工作意味着我必须只处理请求和响应,并且我不想依赖响应。

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

I do not know if it is clear, but it would be great to call the notificationManager wherever I want in my code and that manager works only on kernel.terminate .我不知道这是否清楚,但是在我的代码中我想在任何地方调用notificationManager都会很棒,并且该经理仅适用于kernel.terminate

A simple, naive implementation.一个简单、幼稚的实现。

Your service's send() method doesn't actually send anything, but simply adds another message to be sent when the time is ripe.您的服务的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
        }
    }
}

Then a subscriber that depends on this service, so it gets injected into the subscriber instance:然后是一个依赖于该服务的订阅者,因此它被注入到订阅者实例中:

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();
    }
}

This way you can inject ShinyService anywhere, call ShinyService::send() at any point, and messages will only be sent at KernelEvents::TERMINATE .这样你就可以在任何地方注入ShinyService ,在任何时候调用ShinyService::send() ,消息只会在KernelEvents::TERMINATE发送。

Remember that this event only runs after the response is sent if you are using PHP-FPM.请记住,如果您使用的是 PHP-FPM,则此事件仅在发送响应后运行。 From the docs :文档

Internally, the HttpKernel makes use of the fastcgi_finish_request PHP function.在内部,HttpKernel 使用 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.这意味着目前,只有 PHP FPM 服务器 API 能够向客户端发送响应,而服务器的 PHP 进程仍在执行一些任务。 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.对于所有其他服务器 API,kernel.terminate 的侦听器仍会执行,但在它们全部完成之前不会将响应发送到客户端。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM