我实现了一个在每次内核终止后触发的事件.到目前为止一切都那么好,但我想要的是它在CERTAIN终止后,在特定的控制器动作中触发,例如在发送表单之后,而不是每次请求时.那是因为我想在某些时候做一些繁重的任务,并且不希望最终用户等待页面加载.
不知道怎么能这样做?
<?PHP namespace MedAppBundle\Event; use JMS\DiExtraBundle\Annotation\InjectParams; use JMS\DiExtraBundle\Annotation\Service; use JMS\DiExtraBundle\Annotation\Tag; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use JMS\DiExtraBundle\Annotation\Inject; /** * Class MedicListener * @package MedAppBundle\EventListener * @Service("medapp_test.listener") * @Tag(name="kernel.event_subscriber") */ class TestListener implements EventSubscriberInterface { private $container; private $logger; /** * Constructor. * * @param ContainerInterface $container A ContainerInterface instance * @param LoggerInterface $logger A LoggerInterface instance * @InjectParams({ * "container" = @Inject("service_container"),* "logger" = @Inject("logger") * }) */ public function __construct(ContainerInterface $container,LoggerInterface $logger = null) { $this->container = $container; $this->logger = $logger; } public function onTerminate() { $this->logger->notice('fired'); } public static function getSubscribedEvents() { $listeners = array(KernelEvents::TERMINATE => 'onTerminate'); if (class_exists('Symfony\Component\Console\ConsoleEvents')) { $listeners[ConsoleEvents::TERMINATE] = 'onTerminate'; } return $listeners; } }
到目前为止,我已经将事件订阅到kernel.terminate一个,但显然这会在每次请求时触发它.我把它变成了Swiftmailer的EmailSenderListener
内核必须每次都听这个事件,即使它没有被触发也感觉有点奇怪.我宁愿只在需要时解雇它,但不知道该怎么做.
然后,您应该能够决定是否要运行实际的终止代码.
您还可以将自定义数据存储在请求的属性包中.看到这个链接:Symfony and HTTP Fundamentals
The Request class also has a public attributes property,which holds special data related to how the application works internally. For the Symfony Framework,the attributes holds the values returned by the matched route,like _controller,id (if you have an {id} wildcard),and even the name of the matched route (_route). The attributes property exists entirely to be a place where you can prepare and store context-specific information about the request.
您的代码可能如下所示:
// ... class TestListener implements EventSubscriberInterface { // ... public function onTerminate(PostResponseEvent $event) { $request = $event->getRequest(); if ($request->attributes->get('_route') == 'some_route_name') { // do stuff } } // ... }
编辑:
kernel.terminate事件旨在在发送响应后运行.但是symfony文档说的如下(摘自here):
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.
编辑2:
要使用here中的解决方案,您可以直接编辑web / app.PHP文件以将其添加到那里(但这是某种“黑客核心”imo,即使它比以下更容易使用).或者你可以这样做:
>向具有高优先级的kernel.request事件添加侦听器并启动输出缓冲(ob_start).
>向kernel.response添加一个侦听器,并将标头值添加到响应中.
>将另一个具有最高优先级的侦听器添加到kernel.terminate并执行刷新(ob_flush,flush).
>在kernel.terminate的优先级较低的单独侦听器中运行代码
我没试过,但它确实应该有效.