Symfony2: обратный Uri (Referrer) во время переключения локали

Я бы хотел реализовать языковой коммутатор, но, похоже, ему не повезло …

Код ниже не работает, потому что (Referrer) содержит старое значение locale …

Как я могу перенаправить на старый URI реферера с новым значением locale?

– routing.yml

hello: pattern: /{_locale}/hello/{name} defaults: { _controller: JetInformBundle:Default:index, name: 'alexander' } requirements: _locale: ^en|de|ru|uk$ about: pattern: /{_locale}/about defaults: { _controller: JetInformBundle:Default:about } requirements: _locale: ^en|de|ru|uk$ locale: pattern: /locale/{locale} defaults: { _controller: JetInformBundle:Locale:index } 

– DefaultController.php

 <?php namespace Jet\InformBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\Request; class DefaultController extends Controller { public function indexAction($name, Request $request) { $request->getSession()->set('referrer', $request->getRequestUri()); return $this->render('JetInformBundle:Default:index.html.twig', array('name' => $name)); } public function aboutAction(Request $request) { $request->getSession()->set('referrer', $request->getRequestUri()); return $this->render('JetInformBundle:Default:about.html.twig')); } } 

– LocaleController.php

 <?php namespace Jet\InformBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\Request; class LocaleController extends Controller { public function indexAction($locale, Request $request) { $session = $request->getSession(); if ($request->hasSession()) $session->setLocale($locale); return $this->redirect($session->get('referrer')); } } 

– index.html.twig

 {% extends '::base.html.twig' %} {% block body %} <h1>{% trans %}hello.name{% endtrans %} {{ name }}!</h1> <h3>{% trans %}your.locale{% endtrans %} [{{ app.request.get('_locale') }}]</h3> {% include 'JetInformBundle:Default:locales.html.twig' %} <div> <p>{% trans%}return.to{% endtrans%} <a href="{{ path('about', { '_locale': app.request.get('_locale') }) }}">About</a></p> </div> {% endblock %} -- locales.html.twig <div class="langs"> <ul> <li> {% if app.request.get('_locale') == 'ru' %} Русский {% else %} <a href="{{ path('locale', { 'locale': 'ru' }) }}">Русский</a> {% endif %} </li> <li> {% if app.request.get('_locale') == 'en' %} English {% else %} <a href="{{ path('locale', { 'locale': 'en' }) }}">English</a> {% endif %} </li> <li> {% if app.request.get('_locale') == 'uk' %} Украiнська {% else %} <a href="{{ path('locale', { 'locale': 'uk' }) }}">Украiнська</a> {% endif %} </li> <li> {% if app.request.get('_locale') == 'de' %} Deutsch {% else %} <a href="{{ path('locale', { 'locale': 'de' }) }}">Deutsch</a> {% endif %} </li> </ul> </div> 

Позвольте мне показать вам мое решение. Я написал прослушиватель событий ядра:

 <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> 

как показано ниже:

 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); } } не 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); } } 

Он просто сохраняет последние данные маршрута запроса каждый раз, когда пользователь открывает страницу. И в контроллере, когда пользователь хочет изменить локаль, я делаю это:

 /** * @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']))); } 

Я предоставляю свое решение, используя подход с

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

как было предложено гельденом

 /** * 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); } } 

Вы должны сохранить массив атрибутов маршрута в сеансе вместо одного 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); } } 

Для справок в будущем и для тех, кто наткнулся на это: вам не нужно хранить атрибут referrer в своем сеансе, установив его в КАЖДОМ контроллере. Вы можете вернуть предыдущий URL-адрес из свойства headers :

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

За дополнительной информацией обращайтесь:

  • Symfony2 класс Request на github
  • Класс Symfony2 ParameterBag на github

Гильден, большое спасибо за идею, но это все равно не работает …

Вот контроллер 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); } } } 

Вот контроллер 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); } } 

Относительно параметров IGNORED для array_key_diff () …

 _controller _locale _route _template _template_default_vars _template_vars 

Я попытался включить несколько из них для нового поколения маршрутов, но не повезло … Не понимаю, что происходит …

Кажется, это просто хак … У нас есть более простой способ реализовать эту простую функцию в Symfony2? RAW PHP позволяет мне делать многое и многое другое …

Еще раз спасибо.