简体   繁体   中英

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 .

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.

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.

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 .

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.

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 .

Remember that this event only runs after the response is sent if you are using PHP-FPM. From the 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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