src/EventSubscriber/LocaleSubscriber.php line 65

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