我试图根据存储在DB中的当前用户的首选项设置区域设置。
我们的User类因此有一个getPreferredLanguage,它返回一个地区标识('en', 'fr_FR'等)。
我考虑过以下方法:
- 注册一个订阅KernelEvents::REQUEST事件的"locale"侦听器服务。
- 这个服务可以访问安全上下文(通过它的构造函数)
- 这个服务的onKernelRequest方法尝试从安全上下文中获取用户,获取用户的首选语言环境,并将其设置为请求的语言环境。
不幸的是,这不起作用。当调用"locale"侦听器服务的onRequestEvent方法时,安全上下文没有令牌。似乎上下文侦听器是在非常晚的阶段调用的(优先级为0),并且不可能告诉我的"locale"侦听器在安全上下文之前运行。
有谁知道如何修复这个方法,或建议另一个?
您可能对语言环境侦听器感兴趣,我在这个答案中发布了:Symfony2语言环境检测:不考虑会话中的_locale
编辑:如果用户在个人资料中更改了他的语言,没有问题。如果你正在使用FOSUserBundle (master),你可以钩入配置文件编辑成功事件。否则在你的配置文件控制器中,如果你使用的是自制系统。下面是FOSUserBundle的一个例子:<?php
namespace Acme'UserBundle'EventListener;
use FOS'UserBundle'Event'FormEvent;
use FOS'UserBundle'FOSUserEvents;
use Symfony'Component'EventDispatcher'EventSubscriberInterface;
class ChangeLanguageListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::PROFILE_EDIT_SUCCESS => 'onProfileEditSuccess',
);
}
public function onProfileEditSuccess(FormEvent $event)
{
$request = $event->getRequest();
$session = $request->getSession();
$form = $event->getForm();
$user = $form->getData();
$lang = $user->getLanguage();
$session->set('_locale', $lang);
$request->setLocale($lang);
}
}
和services.yml
services:
acme.change_language:
class: Acme'UserBundle'EventListener'ChangeLanguageListener
tags:
- { name: kernel.event_subscriber }
对于多个浏览器中的多个会话来说,是没有问题的,因为每个新的会话都需要一个新的登录。嗯,好的,在改变语言之后就不会了,因为只有当前会话才会被更新。但是你可以修改languagellistener来支持这个。
如果管理员更改了语言,这种情况应该是微不足道的。
如果你通过谷歌找到这个答案,我目前正在使用这个解决方案。
<?php
namespace App'EventSubscriber;
use Symfony'Component'EventDispatcher'EventSubscriberInterface;
use Symfony'Component'HttpKernel'KernelEvents;
use Symfony'Component'HttpKernel'Event'ControllerEvent;
use Symfony'Component'Security'Core'Security;
use Symfony'Contracts'Translation'TranslatorInterface;
class SetLocaleEventSubscriber implements EventSubscriberInterface
{
private Security $security;
private TranslatorInterface $translator;
public function __construct(Security $security, TranslatorInterface $translator)
{
$this->security = $security;
$this->translator = $translator;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::CONTROLLER => [
['setLocale', 1]
]
];
}
public function setLocale(ControllerEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
$request = $event->getRequest();
/**
* @var 'App'Entit'User
*/
$user = $this->security->getUser();
if ($user) {;
$request->setLocale($user->getLocale());
$this->translator->setLocale($user->getLocale());
}
}
}
为了实现这一点,需要在Kernel::REQUEST
事件上设置一个事件订阅者,其优先级高于文档
此时,不幸的是,您将无法访问当前登录的用户,因为这是在Locale侦听器之后触发的另一个Symfony事件中设置的。
但是,您可以访问会话。
解决方案是在成功登录后将用户的语言环境保存在会话中,然后在来自会话的请求中设置语言环境。
// src/EventSubscriber/UserLocaleSubscriber.php
namespace App'EventSubscriber;
use Symfony'Component'EventDispatcher'EventSubscriberInterface;
use Symfony'Component'HttpFoundation'RequestStack;
use Symfony'Component'Security'Http'Event'InteractiveLoginEvent;
use Symfony'Component'Security'Http'SecurityEvents;
/**
* Stores the locale of the user in the session after the
* login. This can be used by the LocaleSubscriber afterwards.
*/
class UserLocaleSubscriber implements EventSubscriberInterface
{
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function onInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
if (null !== $user->getLocale()) {
$this->requestStack->getSession()->set('_locale', $user->getLocale());
}
}
public static function getSubscribedEvents()
{
return [
SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin',
];
}
}
// src/EventSubscriber/LocaleSubscriber.php
namespace App'EventSubscriber;
use Symfony'Component'EventDispatcher'EventSubscriberInterface;
use Symfony'Component'HttpKernel'Event'RequestEvent;
use Symfony'Component'HttpKernel'KernelEvents;
class LocaleSubscriber implements EventSubscriberInterface
{
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
if ($request->getSession()) {
// Set user's locale from session
if ($locale = $request->getSession()->get('_locale')) {
$request->setLocale($locale);
}
}
}
public static function getSubscribedEvents()
{
return [
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 20]],
];
}
}