vendor/boldr/cms-bundle/src/EventSubscriber/LocaleSubscriber.php line 144

Open in your IDE?
  1. <?php
  2. namespace Boldr\Cms\CmsBundle\EventSubscriber;
  3. use Boldr\Cms\CmsBundle\Locale\LocaleDeterminerInterface;
  4. use Boldr\Cms\CmsBundle\Controller\PermalinkController;
  5. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  6. use Symfony\Component\HttpKernel\KernelEvents;
  7. use Symfony\Component\HttpKernel\Event\{ RequestEvent, ResponseEvent };
  8. use Symfony\Component\HttpFoundation\{ Request, RedirectResponse, HeaderUtils };
  9. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  10. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  11. class LocaleSubscriber implements EventSubscriberInterface
  12. {
  13. /**
  14. * @var string[]
  15. */
  16. private array $enabledLocales;
  17. /**
  18. * @var iterable<LocaleDeterminerInterface>
  19. */
  20. private iterable $localeDeterminers;
  21. /**
  22. * @var array<string,string|array>
  23. */
  24. private array $localeBaseUrls;
  25. private UrlGeneratorInterface $urlGenerator;
  26. private PermalinkController $permalinkController;
  27. private bool $prefixPermalinksWithLocale;
  28. private bool $useHeaderLocale;
  29. /**
  30. * @param string[] $enabledLocales
  31. * @param iterable<LocaleDeterminerInterface> $localeDeterminers
  32. */
  33. public function __construct(
  34. array $enabledLocales,
  35. iterable $localeDeterminers,
  36. array $localeBaseUrls,
  37. UrlGeneratorInterface $urlGenerator,
  38. PermalinkController $permalinkController,
  39. bool $prefixPermalinksWithLocale,
  40. bool $useHeaderLocale
  41. )
  42. {
  43. $this->enabledLocales = $enabledLocales;
  44. $this->localeDeterminers = $localeDeterminers;
  45. $this->localeBaseUrls = $localeBaseUrls;
  46. $this->urlGenerator = $urlGenerator;
  47. $this->permalinkController = $permalinkController;
  48. $this->prefixPermalinksWithLocale = $prefixPermalinksWithLocale;
  49. $this->useHeaderLocale = $useHeaderLocale;
  50. }
  51. public static function getSubscribedEvents()
  52. {
  53. return [
  54. KernelEvents::REQUEST => [['onKernelRequest', 25]],
  55. KernelEvents::RESPONSE => [['onKernelResponse']]
  56. ];
  57. }
  58. public function onKernelResponse(ResponseEvent $event)
  59. {
  60. $request = $event->getRequest();
  61. $urls = [];
  62. /** @var array<string,string> */
  63. if ($request->attributes->has('_permalinkable'))
  64. {
  65. foreach ($this->enabledLocales as $locale)
  66. {
  67. $urls[$locale] = $this->permalinkController->generate($request->attributes->get('_permalinkable'), $locale);
  68. }
  69. }
  70. elseif ($request->attributes->has('_route'))
  71. {
  72. foreach ($this->enabledLocales as $locale)
  73. {
  74. $urls[$locale] = $this->urlGenerator->generate(
  75. $request->attributes->get('_route'),
  76. array_merge(
  77. $request->attributes->get('_route_params') ?: [],
  78. $request->query->all(),
  79. ['_locale' => $locale]
  80. )
  81. );
  82. }
  83. }
  84. $response = $event->getResponse();
  85. $linkHeader = $response->headers->get('Link');
  86. $baseUrl = $request->getSchemeAndHttpHost() . $request->getBaseUrl();
  87. foreach ($urls as $locale => $url)
  88. {
  89. if (!$url)
  90. {
  91. continue;
  92. }
  93. if ($linkHeader)
  94. {
  95. $linkHeader .= ', ';
  96. }
  97. $localeBaseUrl = $this->localeBaseUrls[$locale] ?? $baseUrl;
  98. if (is_array($localeBaseUrl))
  99. {
  100. $localeBaseUrl = $localeBaseUrl[0];
  101. }
  102. $linkHeader .= '<'. $localeBaseUrl . $url .'>; rel="alternate"; hreflang="'. $locale .'"';
  103. }
  104. $response->headers->set('Link', $linkHeader);
  105. }
  106. private function getAcceptHeaderLocale(Request $request): ?string
  107. {
  108. $acceptLanguageHeader = $request->headers->get("accept-language");
  109. if (empty($acceptLanguageHeader))
  110. {
  111. return null;
  112. }
  113. $arr = HeaderUtils::split($acceptLanguageHeader, ',;');
  114. if (empty($arr[0][0]))
  115. {
  116. return null;
  117. }
  118. // Symfony expects underscore instead of dash in locale
  119. $locale = str_replace('-', '_', $arr[0][0]);
  120. return $locale;
  121. }
  122. public function onKernelRequest(RequestEvent $event)
  123. {
  124. $request = $event->getRequest();
  125. $pathInfo = $request->getPathInfo();
  126. $requestLocale = $request->attributes->get('_locale');
  127. if ($requestLocale === null)
  128. {
  129. if ($request->attributes->get('_route') === 'cms_permalink' && $this->prefixPermalinksWithLocale)
  130. {
  131. $parts = explode('/', $request->attributes->get('permalink'), 2);
  132. if (in_array($parts[0], $this->enabledLocales))
  133. {
  134. $requestLocale = $parts[0];
  135. }
  136. }
  137. }
  138. // check baseurl
  139. $localeSetByBaseUrl = false;
  140. $baseUrl = $request->getSchemeAndHttpHost().$request->getBaseUrl();
  141. foreach ($this->localeBaseUrls as $locale => $localeBaseUrl)
  142. {
  143. if (is_array($localeBaseUrl) ? in_array($baseUrl, $localeBaseUrl) : $localeBaseUrl === $baseUrl)
  144. {
  145. $request->setLocale($locale);
  146. $localeSetByBaseUrl = true;
  147. }
  148. }
  149. if (str_starts_with($pathInfo, '/boldr-admin/') || str_starts_with($pathInfo, '/boldr-admin-api/') || str_starts_with($pathInfo, '/boldr-api/'))
  150. {
  151. return;
  152. }
  153. if (!$localeSetByBaseUrl && $this->useHeaderLocale)
  154. {
  155. // Use LocaleDeterminers to determine locale for this request
  156. // Can be based on headers, sessions, request parameters, cookies, etc.
  157. $locale = $this->getAcceptHeaderLocale($request);
  158. // Check if the locale is enabled, or if the primary part of the locale is enabled
  159. if (!in_array($locale, $this->enabledLocales))
  160. {
  161. $split = explode('_', $locale);
  162. $locale = $split[0];
  163. if (!in_array($locale, $this->enabledLocales))
  164. {
  165. $locale = $this->enabledLocales[0];
  166. }
  167. }
  168. if ($locale !== null)
  169. {
  170. $request->setLocale($locale);
  171. }
  172. }
  173. // Redirect to correct base URL if locale changed
  174. if ($request->getMethod() === 'GET' && $localeSetByBaseUrl && $requestLocale !== null && $request->getLocale() !== $requestLocale)
  175. {
  176. // check baseurl
  177. if (isset($this->localeBaseUrls[$requestLocale]))
  178. {
  179. $localeBaseUrl = $this->localeBaseUrls[$requestLocale];
  180. $baseUrl = $request->getSchemeAndHttpHost().$request->getBaseUrl();
  181. if (is_array($localeBaseUrl) ? in_array($baseUrl, $localeBaseUrl) : ($baseUrl !== $localeBaseUrl))
  182. {
  183. if (null !== $queryString = $request->getQueryString())
  184. {
  185. $queryString = '?'.$queryString;
  186. }
  187. $newUrl = (is_array($localeBaseUrl) ? $localeBaseUrl[0] : $localeBaseUrl) . $request->getPathInfo() . $queryString;
  188. $event->setResponse(new RedirectResponse($newUrl));
  189. return;
  190. }
  191. }
  192. }
  193. // Otherwise just use kernel default locale
  194. }
  195. }