<?php
namespace App\EventListener;
use App\Application\Service\Session\SessionService;
use App\Entity\System\Customer;
use App\Service\EnvironmentService;
use Doctrine\ORM\NonUniqueResultException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class LocaleListener
{
private TranslatorInterface $translator;
private TokenStorageInterface $tokenStorage;
private EnvironmentService $environmentService;
private SessionService $sessionService;
private string $defaultLocale;
private array $locales;
public function __construct(
TranslatorInterface $translator,
TokenStorageInterface $tokenStorage,
ParameterBagInterface $parameterBag,
EnvironmentService $environmentService,
SessionService $sessionService
) {
$this->translator = $translator;
$this->tokenStorage = $tokenStorage;
$this->environmentService = $environmentService;
$this->sessionService = $sessionService;
$this->defaultLocale = $parameterBag->get('locale');
$this->locales = $parameterBag->get('locales');
}
public function onKernelRequest(RequestEvent $event): void
{
if ($this->environmentService->isApi()) {
return;
}
$request = $event->getRequest();
$urlLocale = $this->getLocaleFromUrl($request);
if ($urlLocale) {
$this->setLocale($urlLocale, $request);
return;
}
$browserLocale = $this->getLocaleFromBrowser($request);
if ($browserLocale && str_contains($request->attributes->get('_route'), 'front_api')) {
$this->setLocale($browserLocale, $request);
return;
}
$sessionLocale = $request->getSession()->get('lang');
if (!$sessionLocale) {
if ($this->tokenStorage->getToken()) {
/** @var Customer $user */
$user = $this->tokenStorage->getToken()->getUser();
$userLocale = $user->getLanguage()->getIsoCode();
$this->setLocale($userLocale, $request);
return;
}
$locale = $browserLocale ?: $this->defaultLocale;
$this->setLocale($locale, $request);
return;
}
$this->setLocale($sessionLocale, $request);
}
/**
* @throws NonUniqueResultException
*/
private function setLocale(string $locale, Request $request): void
{
$request->setLocale($locale);
$this->translator->setLocale($locale);
$this->sessionService->setLocaleParameters($locale);
}
private function getLocaleFromBrowser(Request $request): ?string
{
if ($request->getLanguages()) {
return $request->getPreferredLanguage($this->locales);
}
return null;
}
private function isLocaleSupported(string $locale): bool
{
return \in_array($locale, $this->locales, true);
}
private function getLocaleFromUrl(Request $request): ?string
{
$urlArray = \explode('/', $request->getPathInfo());
if (is_array($urlArray) && isset($urlArray[1]) && $this->isLocaleSupported($urlArray[1])) {
return $urlArray[1];
}
$lang = $request->get('lang');
if ($lang && $this->isLocaleSupported($lang)) {
return $lang;
}
return null;
}
}