src/EventSubscriber/LocaleSubscriber.php line 73

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use Gedmo\Translatable\TranslatableListener;
  4. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  5. use Symfony\Component\HttpFoundation\RedirectResponse;
  6. use Symfony\Component\HttpKernel\Event\RequestEvent;
  7. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  8. use Symfony\Component\HttpKernel\KernelEvents;
  9. use Symfony\Component\Routing\RouteCollection;
  10. use Symfony\Component\Routing\RouterInterface;
  11. class LocaleSubscriber implements EventSubscriberInterface
  12. {
  13.     /**
  14.      * @var RouterInterface
  15.      */
  16.     private $router;
  17.     /**
  18.      * @var RouteCollection
  19.      */
  20.     private $routeCollection;
  21.     /**
  22.      * @var string
  23.      */
  24.     private $defaultLocale;
  25.     /**
  26.      * @var array
  27.      */
  28.     private $supportedLocales;
  29.     /**
  30.      * @var string
  31.      */
  32.     private $localeRouteParam;
  33.     /** @var TranslatableListener */
  34.     private $translatable;
  35.     /**
  36.      * @param RouterInterface $router
  37.      * @param TranslatableListener $listener
  38.      * @param string $defaultLocale
  39.      * @param array $supportedLocales
  40.      * @param string $localeRouteParam
  41.      */
  42.     public function __construct(RouterInterface $routerTranslatableListener $listener$defaultLocale 'fr',
  43.                                 array $supportedLocales = array('fr''en''it'), $localeRouteParam '_locale')
  44.     {
  45.         $this->router $router;
  46.         $this->routeCollection $router->getRouteCollection();
  47.         $this->defaultLocale $defaultLocale;
  48.         $this->supportedLocales $supportedLocales;
  49.         $this->localeRouteParam $localeRouteParam;
  50.         $this->translatable $listener;
  51.     }
  52.     public function isLocaleSupported($locale)
  53.     {
  54.         return in_array($locale$this->supportedLocales);
  55.     }
  56.     /**
  57.      * Redirect to correct locale route if omitted or not concordant with route requirements.
  58.      *
  59.      * @param ResponseEvent $event
  60.      * @return void
  61.      */
  62.     public function onKernelResponse(ResponseEvent $event): void
  63.     {
  64.         //--------------------------------------------------------------------------------------------------------------
  65.         // GOAL:
  66.         //--------------------------------------------------------------------------------------------------------------
  67.         // Redirect all incoming requests to their /locale/route equivalent as long as the route will exists when we do so.
  68.         // If the route required a specific locale so we force it.
  69.         // Do nothing if it already has /locale/ in the route to prevent redirect loops
  70.         //--------------------------------------------------------------------------------------------------------------
  71.         $request $event->getRequest();
  72.         $path $request->getPathInfo();
  73.         $route_exists false// By default, assume route does not exist.
  74.         $force_locale false// By default, assume not forcing locale.
  75.         foreach($this->routeCollection as $routeObject){
  76.             $routePath $routeObject->getPath();
  77.             if($routePath == '/'.$this->localeRouteParam.$path){
  78.                 $route_requirements $routeObject->getRequirements();
  79.                 $route_exists true;
  80.                 // Checks if route has a required locale.
  81.                 if (is_array($route_requirements) && array_key_exists($this->localeRouteParam$route_requirements)
  82.                     && !empty($route_requirements[$this->localeRouteParam])) {
  83.                     $force_locale $route_requirements[$this->localeRouteParam];
  84.                 }
  85.                 break;
  86.             }
  87.         }
  88.         // If the route does indeed exist then lets redirect there.
  89.         if($route_exists == true){
  90.             // Get the locale from the users browser.
  91.             $locale $request->getPreferredLanguage();
  92.             // If no locale from browser or locale not in list of known locales supported then set to defaultLocale.
  93.             if(!(!empty($locale) && $this->isLocaleSupported($locale) === true)){
  94.                 $locale $request->getDefaultLocale();
  95.             }
  96.             // If a locale was detected in route and current locale is different of required locale.
  97.             if(!is_bool($force_locale) && $locale !== $force_locale) {
  98.                 $locale $force_locale;
  99.             }
  100.             $event->setResponse(new RedirectResponse('/'.$locale.$path));
  101.         } elseif ($request->get($this->localeRouteParam) === null && $path === '/') {
  102.             $event->setResponse(new RedirectResponse('/'.$this->defaultLocale.'/'));
  103.         }
  104.         //Otherwise do nothing and continue on~
  105.     }
  106.     public function onKernelRequest(RequestEvent $event): void
  107.     {
  108.         $request $event->getRequest();
  109.         if (!$request->hasPreviousSession()) {
  110.             return;
  111.         }
  112.         // try to see if the locale has been set as a _locale routing parameter
  113.         if ($locale $request->attributes->get($this->localeRouteParam)) {
  114.             $request->getSession()->set($this->localeRouteParam$locale);
  115.         } else {
  116.             // if no explicit locale has been set on this request, use one from the session
  117.             $request->setLocale($request->getSession()->get($this->localeRouteParam$this->defaultLocale));
  118.         }
  119.         $this->translatable->setTranslatableLocale($request->getLocale());
  120.     }
  121.     public static function getSubscribedEvents()
  122.     {
  123.         return [
  124.             KernelEvents::RESPONSE => [['onKernelResponse'17]],
  125.             // must be registered before (i.e. with a higher priority than) the default Locale listener
  126.             KernelEvents::REQUEST => [['onKernelRequest', -256]],
  127.         ];
  128.     }
  129. }