Oct 30 2011

Symfony2: how to redirect user to a previous page correctly (without using HTTP_REFERER)

Category: Articles,Symfony2FractalizeR @ 6:09 pm

I was implementing simple menu, that would allow user to change site language.  The site uses standard symfony2 localized urls like http://www.example.com/en/contact. The problem was to return user to a page, where he previously was, but rendered in a selected language. I didn’t like to do any find/replace on REFERER.

Let me show you my solution. I’ve written kernel event listener and I registered it at my bundle’s Resources/config/services.xml file:

<?xml version="1.0" ?>
 
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <services>
        <service id="twig.extension.getlangarray.expedio_simple" public="false">
            <tag name="twig.extension" />
            <argument type="service" id="service_container" />
        </service>
        <service id="acme.demo.listener">
              <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
              <argument type="service" id="router" />
          </service>
    </services>
</container>

This file is merged into Symfony2 configuration from DependencyInjection/ExpedioSimpleExtension.php:

class ExpedioSimpleExtension extends Extension {
    /**
     * {@inheritDoc}
     * @param array $configs
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
     */
    public function load(array $configs, ContainerBuilder $container) {
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
        $loader->load('services.xml');
    }
 
    public function getAlias() {
        return 'expedio_simple';
    }
}

Listener implementation:

namespace Expedio\SimpleBundle\Listener;
 
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 
    class Kernel {
 
        /**
         * @var \Symfony\Component\DependencyInjection\ContainerInterface
         */
        private $router;
 
        public function __construct(\Symfony\Component\Routing\Router $router) {
            $this->router = $router;
        }
 
        public function onKernelRequest(GetResponseEvent $event) {
            if ($event->getRequestType() !== \Symfony\Component\HttpKernel\HttpKernel::MASTER_REQUEST) {
                return;
            }
 
            /** @var \Symfony\Component\HttpFoundation\Request $request  */
            $request = $event->getRequest();
            /** @var \Symfony\Component\HttpFoundation\Session $session  */
            $session = $request->getSession();
 
            $routeParams = $this->router->match($request->getPathInfo());
            $routeName = $routeParams['_route'];
            if ($routeName[0] == '_') {
                return;
            }
            unset($routeParams['_route']);
            $routeData = array('name' => $routeName, 'params' => $routeParams);
 
            //Skipping duplicates
            $thisRoute = $session->get('this_route', array());
            if ($thisRoute == $routeData) {
                return;
            }
            $session->set('last_route', $thisRoute);
            $session->set('this_route', $routeData);
        }
    }

It just saves last request route data each time user opens a page. And in controller when user wants to change locale I do this:

/**
     * @Route("/setlocale/{locale}", name="set_locale")
     * @param string $locale
     * @return array
     */
    public function setLocaleAction($locale) {
        /** @var \Symfony\Component\HttpFoundation\Session $session  */
        $session = $this->get('session');
        $session->setLocale($locale);
        $last_route = $session->get('last_route', array('name' => 'index'));
        $last_route['params']['_locale'] = $locale;
        return ($this->redirect($this->generateUrl($last_route['name'], $last_route['params'])));
    }

Well, this is how it works 😉

2 Responses to “Symfony2: how to redirect user to a previous page correctly (without using HTTP_REFERER)”

  1. prabhu says:

    Hi, my dis is great when i see the code but when i implement this i cannot get what i am expecting. Actually i have to auto-logout the user who have logged in with same username(i have to logout the first user when another person login with the same username). This check has to happen on every request.Can u please help in giving suggestion upon this…Thanks in advance….

  2. prabhu says:

    Hi another info is i am using pdo session storage to handle the session(to store the session in the database).

Leave a Reply

You must be logged in to post a comment. Login now.