Symfony2:切换语言环境期间向后 Uri(Referrer)

发布于 2024-12-04 18:25:33 字数 3761 浏览 0 评论 0原文

我想实现区域设置切换器,但似乎没有运气...

下面的代码不起作用,因为 (Referrer) 包含区域设置的旧值...

我如何使用 a 重定向到旧的 Referrer 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>

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

How can I redirect to the old Referrer URI with a new value of 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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

寂寞陪衬 2024-12-11 18:25:33

让我向您展示我的解决方案。我编写了内核事件监听器:

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

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'])));
}
半枫 2024-12-11 18:25:33

我使用

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

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

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);
    }
}
捂风挽笑 2024-12-11 18:25:33

您必须在会话中存储路由属性的数组,而不是单个 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 属性存储在会话中。您可以从 headers 属性中检索之前的 url:

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

有关其他信息,请参阅:

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
把人绕傻吧 2024-12-11 18:25:33

吉尔登,非常感谢您的想法,但它无论如何都不起作用...

这是控制器 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);
    }
}
}

这是业务逻辑的控制器:

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

关于 array_key_diff() 的忽略参数...

_controller
_locale
_route
_template
_template_default_vars
_template_vars

我尝试包括一些其中有新一代路线,但运气不佳......
不明白发生了什么...

这似乎只是一个 hack...我们是否有更复杂的方法来实现 Symfony2 中的这个简单功能? RAW PHP 允许我做这么多事情&更容易...

再次感谢。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文