In my Symfony project, I've come across a bizarre problem with kernel.request
event listeners firing multiple times when embedded Twig controllers are used.
In my custom event listener I have an event listener that sends a redirect response if a certain condition exists (an expired password in this case). In order to prevent a redirect loop I checked if we were already on the page:
if ($event->getRequest()->get('_route') != 'user_change_password') {
$response = new RedirectResponse($this->router->generate('user_change_password'));
$event->setResponse($response);
}
But that didn't stop the redirect loops. Until I added logging, I had no idea that an embedded controller would fire the kernel.request
event (it's obvious in hindsight, since these embedded controllers work by sending a "sub-request"). I have a single embedded controller in by base twig template that checks for any alert messages and displays them.
Given the above, how can I
kernel.request
event listeners fire multiple times.Even though Symfony suggests inserting that dynamic content into base templates using embedded controllers, is this considered bad practice?
Would it be better to create a Twig extension to solve this problem? From what I've seen, Twig extensions are generally only used for simple stuff, like the price
example in the cookbook, though I can't see why it wouldn't work for more complex, database-connected things. I'm just not sure on how to do that.
Examples are appreciated.
Possible related?: Symfony Controller executed multiple Time
You could do the redirection only if the event listener is executed for the master request:
use Symfony\Component\HttpKernel\HttpKernelInterface;
// ...
if ($event->isMasterRequest() && $event->getRequest()->get('_route') != 'user_change_password') {
$response = new RedirectResponse($this->router->generate('user_change_password'));
$event->setResponse($response);
}
If you are still bound to Symfony 2.3, you can use the getRequestType()
method compare its return value with the MASTER_REQUEST
constant from the HttpKernelInterface
(that's what isMasterRequest()
does internally):
use Symfony\Component\HttpKernel\HttpKernelInterface;
// ...
if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType() && $event->getRequest()->get('_route') != 'user_change_password') {
$response = new RedirectResponse($this->router->generate('user_change_password'));
$event->setResponse($response);
}