Symfony2: Backward Uri (Referrer) during switching locale

后端 未结 4 1907
甜味超标
甜味超标 2021-01-01 08:03

I\'d like to implement locale switcher, but it seems with no luck...

The code below doesn\'t work because the (Referrer) contains the old value of locale...

相关标签:
4条回答
  • 2021-01-01 08:16

    Gilden, thanks a lot for idea, but it's doesn't work anyway...

    Here is the controller LOCALE SWITCHER:

    class LocaleController extends Controller
    {
    public function changeAction($locale, Request $request)
    {
        if ($request->hasSession())
        {
            $session = $request->getSession();
            $session->setLocale($locale);
    
            $route_params = $session->get('jet_referrer');
            $route_name = $route_params['_route'];
    
            // Some parameters are not required to be used, filter them
            // by using an array of ignored elements.
            $ignore_params = array('_route' => true, '_controller' => true,
                                   '_template_default_vars' => true);
            $route_params = array_diff_key($route_params, $ignore_params);
    
            $url = $this->get('router')->generate($route_name, $route_params);
            return $this->redirect($url);
        }
    }
    }
    

    Here is the controller of BUSINESS LOGIC:

    /**
     * @Route("/{_locale}")
     */
    class TestController extends Controller
    {
    /**
     * @Route("/", name="_test")
     * @Template()
     */
    public function indexAction(Request $request)
    {
        $request->getSession()->set('jet_referrer', $request->attributes->all());
        return array();
    }
    
    /**
     * @Route("/hello/{name}", name="_test_hello")
     * @Template()
     */
    public function helloAction($name, Request $request)
    {
        $request->getSession()->set('jet_referrer', $request->attributes->all());
        return array('name' => $name);
    }
    }
    

    Regarding IGNORED params for array_key_diff()...

    _controller
    _locale
    _route
    _template
    _template_default_vars
    _template_vars
    

    I've tried to include few of them for the new route generation, but with no luck... Don't understand what is going on...

    It's seems just a hack... Do we have more sofisticated way to realize this simple feature in Symfony2 ?? RAW PHP allows me to do that much & much more easily...

    Thanks again.

    0 讨论(0)
  • 2021-01-01 08:17

    I provide my solution using the approach with

    $request->headers->get('referer');
    

    as suggested by gilden

    /**
     * Your locale changing controller
     */
    public function localeAction($locale)
    {
        $request = $this->get('request');
        $router = $this->get('router');
        $context = $router->getContext();
        $frontControllerName = basename($_SERVER['SCRIPT_FILENAME']);
    
        if($request->hasSession())
        {
            $session = $request->getSession();
            $session->setLocale($locale);
            $context->setParameter('_locale', $locale);
    
            //reconstructs a routing path and gets a routing array called $route_params
            $url = $request->headers->get('referer');
            $urlElements = parse_url($url);
            $routePath = str_replace('/' . $frontControllerName, '', $urlElements['path']); //eliminates the front controller name from the url path
            $route_params = $router->match($routePath);
    
            // Get the route name
            $route = $route_params['_route'];
    
            // Some parameters are not required to be used, filter them
            // by using an array of ignored elements.
            $ignore_params = array('_route' => true, '_controller' => true, '_locale' => true);
            $route_params = array_diff_key($route_params, $ignore_params);
    
            $url = $this->get('router')->generate($route, $route_params);
    
            return $this->redirect($url);
        }
    }
    
    0 讨论(0)
  • 2021-01-01 08:36

    Let me show you my solution. I've written kernel event listener:

    <service id="expedio.simple.listener" class="Expedio\SimpleBundle\Listener\Kernel">
          <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
          <argument type="service" id="router" />
      </service>
    

    like the following:

    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'])));
    }
    
    0 讨论(0)
  • 2021-01-01 08:42

    You must store an array of your route attributes in the session instead of a single url.

    /**
     * You should set the 'referrer' in every controller in your application. This
     * should probably be handled as an event to save all the hassle.
     */
    public function anyAction(Request $request)
    {
        $request->getSession()->set('referrer', $request->attributes->all());
    
        // ...
    }
    
    /**
     * Your locale changing controller
     */
    public function localeAction($locale, Request $request)
    {
        if($request->hasSession())
        {
            $session = $request->getSession();
            $session->setLocale($locale);
    
            $route_params = $session->get('referrer');
    
            // Get the route name
            $route = $route_params['_route'];
    
            // Some parameters are not required to be used, filter them
            // by using an array of ignored elements.
            $ignore_params = array('_route' => true, '_controller' => true);
            $route_params = array_diff_key($route_params, $ignore_params);
    
            $url = $this->get('router')->generate($route, $route_params);
            return $this->redirect($url);
        }
    }
    

    For future reference and to anyone stumbling over this: you don't have to store the referrer attribute in your session by setting it in EVERY controller. You can retrieve the previous url from the headers property:

    $request->headers->get('referer'); // Single 'r' everywhere!
    

    For additional info, consult:

    • Symfony2 Request class on github
    • Symfony2 ParameterBag class on github
    0 讨论(0)
提交回复
热议问题