CoKe
CoKe

Reputation: 639

Symfony2 store user related things on every request

I want to store the last locale used by a user on every Request the user makes. I already created a Field in the Database and only need the best practice way without big modifications in every Controller.

Thank you all.

Upvotes: 0

Views: 1240

Answers (2)

CoKe
CoKe

Reputation: 639

That is my implementation to save the locale on each request in the database. It is necessary for me because i need the locale persisted for the newsletter.

LocaleListener:

namespace MyApp\MyBundle\EventListener;

use \Symfony\Component\HttpKernel\Event\GetResponseEvent;

use \Symfony\Component\HttpKernel\KernelEvents;
use \Symfony\Component\EventDispatcher\EventSubscriberInterface;
use \FOS\UserBundle\Model\UserManagerInterface;
use \Symfony\Component\Security\Core\SecurityContext;
use \MyApp\MyBundle\Entity\User;

class LocaleListener implements EventSubscriberInterface
{
    private $userManager;
    private $securityContext;
    private $defaultLocale;

    public function __construct(UserManagerInterface $userManager, SecurityContext $securityContext, $defaultLocale = 'en')
    {
        $this->userManager = $userManager;
        $this->securityContext = $securityContext;
        $this->defaultLocale = $defaultLocale;
    }

    public function onKernelRequest17(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        if (!$request->hasPreviousSession()) {
            return;
        }

       // try to see if the locale has been set as a _locale routing parameter
       $locale = $request->attributes->get('_locale');
       if ($locale !== null) 
       {
            $request->getSession()->set('_locale', $locale);
       }
       else 
       {
            // if no explicit locale has been set on this request, use one from the session
           $locale = $request->getSession()->get('_locale', $this->defaultLocale);
           $request->setLocale($locale);
       }

       // save last locale to the user if he is logged in
       $user = $this->getUser();
       if($user instanceof User)
       {
           $user->setDefaultLanguage($locale);
           $this->userManager->updateUser($user);
       }

    }

    private function getUser()
    {
        $token = $this->securityContext->getToken();
        if($token !== null)
            return $this->securityContext->getToken()->getUser();
    }

    public static function getSubscribedEvents()
    {
        return array(
            // must be registered before the default Locale listener
        KernelEvents::REQUEST => array(array('onKernelRequest17', 17)),
        );
    }
}

services.yml:

myApp_myBundle.locale_listener:
    class: MyApp\MyBundle\EventListener\LocaleListener
    arguments: [@fos_user.user_manager, @security.context, "%kernel.default_locale%"]
    tags:
        - { name: kernel.event_subscriber }

Upvotes: 0

Léo Benoist
Léo Benoist

Reputation: 2541

You could store your locale in session and use it with an event listener. And on user login set user locale in session.

-LocaleListener : Store the locale in session and user locale in session

-UserLocaleListener : On user login set user locale in session

<?php

namespace YourApp\YourBundle\EventListener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;

use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class LocaleListener implements EventSubscriberInterface
{
    private $defaultLocale;


    public function __construct($defaultLocale = 'en')
    {
        $this->defaultLocale = $defaultLocale;
    }

    public function onKernelRequest17(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        if (!$request->hasPreviousSession()) {
            return;
        }

        // try to see if the locale has been set as a _locale routing parameter
        if ($locale = $request->attributes->get('_locale')) {
            $request->getSession()->set('_locale', $locale);
        } else {
            // if no explicit locale has been set on this request, use one from the session
            $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
        }
    }

    public static function getSubscribedEvents()
    {
        return array(
            // must be registered before the default Locale listener
        KernelEvents::REQUEST => array(array('onKernelRequest17', 17)),
        );
    }
}

Second service:

<?php

namespace YourApp\YourBundle\EventListener;

use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class UserLocaleListener
{
    private $session;

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

    /**
     * kernel.request event. If a guest user doesn't have an opened session, locale is equal to
     * "undefined" as configured by default in parameters.ini. If so, set as a locale the user's
     * preferred language.
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     */
    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());
            }
        }
    }

    /**
     * security.interactive_login event. If a user chose a language in preferences, it would be set,
     * if not, a locale that was set by setLocaleForUnauthenticatedUser remains.
     *
     * @param \Symfony\Component\Security\Http\Event\InteractiveLoginEvent $event
     */
    public function setLocaleForAuthenticatedUser(InteractiveLoginEvent $event)
    {
        $user = $event->getAuthenticationToken()->getUser();

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

}

services.yml

services:
    yourapp_your.locale_listener:
        class: YourApp\YourBundle\EventListener\LocaleListener
        arguments: ["%kernel.default_locale%"]
        tags:
            - { name: kernel.event_subscriber }

    yourapp_your.locale.interactive_login_listener:
        class: YourApp\YourBundle\EventListener\UserLocaleListener
        calls:
            - [ setSession, [@session] ]
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: setLocaleForAuthenticatedUser }

This is using

Upvotes: 1

Related Questions