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



我想知道如何编写一个只在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,则此事件仅在发送响应后运行。来自文档:

在内部,HttpKernel使用fastcgi_finish_request PHP函数。这意味着目前只有PHP FPM服务器API能够向客户端发送响应,而服务器的PHP进程仍在执行一些任务。对于所有其他服务器API,kernel.ternate的侦听器仍在执行,但在它们全部完成之前,不会将响应发送到客户端。

相关内容

  • 没有找到相关文章

最新更新