我想知道如何编写一个只在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的侦听器仍在执行,但在它们全部完成之前,不会将响应发送到客户端。