7
votes

I'm trying to add a Symfony2 login event listener, the goal is to set a database-stored locale if the user is logged, on each request, and to fallback to a default one of there is no user logged. I use FOSUserBundle, and I'm trying to get the security.interactive_login event to work. I find a lot of code over the internet like this one: http://dev.dbl-a.com/symfony-2-0/how-to-add-a-symfony2-login-event-listener/

I have my own child bundle of the FOSUserBundle and this implementation in services.yml:

my_user.security.interactive_login_listener:
        class: My\UserBundle\EventListener\UserListener
        arguments: [@security.context, @doctrine]
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: setLocaleForAuthenticatedUser }

my_user.security.kernel_request_listener:
        class: My\UserBundle\EventListener\UserListener
        arguments: [@security.context, @doctrine]
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: setLocaleForUnauthenticatedUser }

Problem is, the security.interactive_login event is never triggered, even when logging, even when logged. On the contrary, my setLocaleForUnauthenticatedUser is always trigered. Every code sample I found seems to work fluenty, what's wrong with my app?

2
What is the branch version of symfony2 and the version of the FOSUserBundle ?Rmannn

2 Answers

1
votes

Figured out too, and did more or less the same work around: There is no problem indeed, but there is some kind of redirection after login, so the profiler never show the actual request who trigger the interactive login listener.

use Symfony\Component\Security\Http\Event\InteractiveLoginEvent,
    Symfony\Component\Security\Http\Event\FilterControllerEvent,
    Symfony\Component\HttpKernel\Event\GetResponseEvent,
    Symfony\Component\HttpKernel\HttpKernelInterface;
use FOS\UserBundle\Entity\User as BaseUser;

class LocaleListener {

    protected $container;
    protected $availableLocales;

    public function __construct(\Symfony\Component\DependencyInjection\Container $container, $availableLocales) {
        $this->container = $container;
        $this->availableLocales = $availableLocales;
    }

    public function onKernelRequest(GetResponseEvent $event) {
        $request = $event->getRequest();
        $locale = $request->getPreferredLanguage($this->availableLocales);
        $session = $request->getSession();

        $token = $this->container->get('security.context')->getToken();
        if( is_object( $token ) ) {
            $user = $token->getUser();
            if ($user instanceof BaseUser) {
                $locale = $user->getLocale();
            }
        }

        $session = $this->container->get('session');
        $session->set('_locale', $locale);
        $request->setLocale($locale);
    }
 }

In services.yml:

user.locales.kernel_request_listener:
        class: Acme\UserBundle\EventListener\LocaleListener
        arguments: [ @service_container, [ 'en', 'fr', 'ru' ] ]
        tags: [{ name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: -255 }]
0
votes

same problem here. But the problem is not that event is not triggered. The problem is that after redirecting, the request locale is lost. With the help from this link:

Changing locale with symfony 2.1

(And based on this)

I figured out how to solve it. In the UserListener:

class UserListener
{
    private $session;

    public function setSession($session) {
        $this->session = $session;
    }    

    public function setLocaleForUnauthenticatedUser(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }
        $request = $event->getRequest();
        if ('undefined' == $request->getLocale()) {
            if($locale = $request->getSession()->get('_locale')) {
                $request->setLocale($locale);
            } else {
                $request->setLocale($request->getPreferredLanguage());
            }
        }
    }

    public function setLocaleForAuthenticatedUser(InteractiveLoginEvent $event)
    {
        $user = $event->getAuthenticationToken()->getUser();

        if ($locale = $user->getLocale()) {
//            $event->getRequest()->setLocale($user->getLocale());
            $this->session->set('_locale', $locale);
        }
    }
}

In services.yml, you should declare:

your_listener_name:
    class: ...\UserBundle\EventListener\UserListener
    calls:
        - [ setSession, ['@session'] ]
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: setLocaleForAuthenticatedUser }

Hope this helps.