6

DBに保存されている現在のユーザーの設定に基づいてロケールを設定しようとしています。

したがって、User クラスには、ロケール識別 (「en」、「fr_FR」など) を返す getPreferredLanguage があります。

次のアプローチを検討しました。

  • KernelEvents::REQUEST イベントをサブスクライブする「ロケール」リスナー サービスを登録します。
  • このサービスは、(コンストラクターを介して) セキュリティ コンテキストにアクセスできます。
  • このサービスの onKernelRequest メソッドは、セキュリティ コンテキストからユーザーを取得し、ユーザーの優先ロケールを取得して、それを要求のロケールとして設定しようとします。

残念ながら、これは機能しません。「locale」リスナー サービスの onRequestEvent メソッドが呼び出されると、セキュリティ コンテキストにはトークンがありません。コンテキスト リスナーが非常に遅い段階で (優先度 0 で) 呼び出されているようで、「ロケール」リスナーにセキュリティ コンテキストの前に実行するように指示することはできません。

このアプローチを修正する方法、または別のアプローチを提案する方法を知っている人はいますか?

4

3 に答える 3

2

この回答に投稿したロケール リスナーに興味があるかもしれません: Symfony2 ロケール検出: セッションで _locale を考慮しない

編集: ユーザーがプロファイルで言語を変更しても問題ありません。FOSUserBundle (マスター) を使用している場合は、プロファイル編集成功イベントにフックできます。それ以外の場合は、プロファイルコントローラーで、自作システムを使用している場合。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 }

新しいセッションごとに新しいログインが必要になるため、複数のブラウザで複数のセッションを行うことは問題ありません。現在のセッションのみが更新されるため、言語を変更した後ではありません。ただし、これをサポートするように LanguageListener を変更できます。
また、管理者が言語を変更した場合は、重要ではありません。

于 2013-05-18T12:36:36.940 に答える
0

これを実現するには、ドキュメントKernel::REQUESTに示されているように、デフォルトの Locale リスナーよりも優先度の高いイベントにイベント サブスクライバーをセットアップする必要があります。

現時点では、残念ながら現在ログインしているユーザーにアクセスすることはできません。これは 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]],
        ];
    }
}
于 2022-01-11T07:28:09.183 に答える
0

Google からこの回答にたどり着いた場合、私は現在このソリューションを使用しています。

    <?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());
        }
    }
}
于 2020-06-04T15:08:59.640 に答える