Usually, when you want to redirect your users to a different URL, you use the redirect()
or redirectToRoute()
methods from the controller, but sometimes you need to redirect your users from outside of the controller, if certain conditions are met.
Unfortunately this cannot be done out of the box, but it's fairly easy to do.
I personally prefer to do this using exceptions and a kernel exception listener because they can bubble up and be caught by an event listener.
In Symfony, when you throw an exception, it gets caught internally by a try/catch which then creates an instance of Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent
and passes it along to each of the registered kernel exception listeners until one of them returns a response.
With that in mind, we start by defining a simple RedirectException
class that will carry an instance of Symfony\Component\HttpFoundation\RedirectResponse
from any service to the listener that will then return the response to the user:
<?php
namespace AppBundle\Exception;
use Symfony\Component\HttpFoundation\RedirectResponse;
class RedirectException extends \Exception
{
private $redirectResponse;
public function __construct(
RedirectResponse $redirectResponse,
$message = '',
$code = 0,
\Exception $previousException = null
) {
$this->redirectResponse = $redirectResponse;
parent::__construct($message, $code, $previousException);
}
public function getRedirectResponse()
{
return $this->redirectResponse;
}
}
The listener that will handle the redirecting is really simple, all it has to do, is to check that the exception carried by the Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent
is an instance of RedirectException
and if that's true, we call setResponse()
with the redirect response.
<?php
namespace AppBundle\EventListener;
use AppBundle\Exception\RedirectException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
class RedirectExceptionListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($event->getException() instanceof RedirectException) {
$event->setResponse($event->getException()->getRedirectResponse());
}
}
}
The config file for this listener looks something like this:
services:
app.redirect_exception_listener:
class: AppBundle\EventListener\RedirectExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }
In order for us to actually use this now, we only have to throw the exception from any place during a request with something like this:
throw new \AppBundle\Exception\RedirectException(
new \Symfony\Component\HttpFoundation\RedirectResponse(
$event->getRequest()->query->get('goTo')
)
);
Happy coding!