Я хотел бы реализовать языковой коммутатор, но, похоже, ему не повезло...
Код ниже не работает, потому что (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);
}
}
Он просто сохраняет последние данные маршрута запроса каждый раз, когда пользователь открывает страницу. И в контроллере, когда пользователь хочет изменить локаль, я делаю это:
/**
* @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!
Дополнительную информацию см. в разделе
Гильден, большое спасибо за идею, но она все равно не работает...
Вот контроллер 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 позволяет мне делать многое и многое другое...
Еще раз спасибо.