Saving the last matched route

posted 28.08.2014

Scenario

I’d like to redirect to the last request. For example, I have a form accesible from multiple pages and after submission I want to redirect the use to the page where he or she came from.

Solution #1: HTTP Referer

The correct spelling is Referrer, but a small error made in RFC 1945 (HTTP/1.0 specification). Widely used since then, the Referer spelling is the only possible in context of HTTP.

<?php

use Symfony\Component\HttpFoundation\RedirectResponse;

class Controller
{
    public function refererAction()
    {
        $referer = $request->headers->get('referer');
        return new RedirectResponse($referer);
    }
}

The referer might not be available in the request and user agents are not required to pass it along with the request. A safer way is to store the last request in the session.

Solution #2: Saving the last route in the session

Storing the last matched route in the session is more reliable than detecting the HTTP_REFERER header. To store the route, we will create an EventListener, which will be called during each kernel.request event. The same event is used for the RouterListener, which actually matches the path in the URL to a route. To make sure the appropriate route is already found, we have to give our listener a lower priority. RouterListener has priority 32, so we choose a lower number.

services:
    smf_example.last_route_event_listener:
        class: SmfBlog\ExampleBundle\EventListener\LastRouteListener
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 30 }
<?php

namespace SmfBlog\ExampleBundle\EventListener;

use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernel;

class LastRouteListener
{

    public function onKernelRequest(GetResponseEvent $event)
    {
        // Do not save subrequests
        if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
            return;
        }

        $request = $event->getRequest();
        $session = $request->getSession();

        $routeName = $request->get('_route');
        $routeParams = $request->get('_route_params');
        if ($routeName[0] == '_') {
            return;
        }
        $routeData = ['name' => $routeName, 'params' => $routeParams];

        // Do not save same matched route twice
        $thisRoute = $session->get('this_route', []);
        if ($thisRoute == $routeData) {
            return;
        }
        $session->set('last_route', $thisRoute);
        $session->set('this_route', $routeData);
    }
}