vendor/shopware/storefront/Framework/Routing/StorefrontSubscriber.php line 205
<?php declare(strict_types=1);namespace Shopware\Storefront\Framework\Routing;use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;use Shopware\Core\Checkout\Customer\Event\CustomerLoginEvent;use Shopware\Core\Checkout\Customer\Event\CustomerLogoutEvent;use Shopware\Core\Content\Seo\HreflangLoaderInterface;use Shopware\Core\Content\Seo\HreflangLoaderParameter;use Shopware\Core\Framework\App\ActiveAppsLoader;use Shopware\Core\Framework\App\Exception\AppUrlChangeDetectedException;use Shopware\Core\Framework\App\ShopId\ShopIdProvider;use Shopware\Core\Framework\Event\BeforeSendResponseEvent;use Shopware\Core\Framework\Log\Package;use Shopware\Core\Framework\Routing\Event\SalesChannelContextResolvedEvent;use Shopware\Core\Framework\Routing\KernelListenerPriorities;use Shopware\Core\Framework\Util\Random;use Shopware\Core\PlatformRequest;use Shopware\Core\SalesChannelRequest;use Shopware\Core\System\SalesChannel\SalesChannelContext;use Shopware\Core\System\SystemConfig\SystemConfigService;use Shopware\Storefront\Event\StorefrontRenderEvent;use Shopware\Storefront\Theme\StorefrontPluginRegistryInterface;use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpFoundation\RedirectResponse;use Symfony\Component\HttpFoundation\RequestStack;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\HttpFoundation\Session\SessionInterface;use Symfony\Component\HttpKernel\Event\ControllerEvent;use Symfony\Component\HttpKernel\Event\ExceptionEvent;use Symfony\Component\HttpKernel\Event\RequestEvent;use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;use Symfony\Component\HttpKernel\KernelEvents;use Symfony\Component\Routing\RouterInterface;/*** @internal*/#[Package('storefront')]class StorefrontSubscriber implements EventSubscriberInterface{/*** @internal*/public function __construct(private readonly RequestStack $requestStack,private readonly RouterInterface $router,private readonly HreflangLoaderInterface $hreflangLoader,private readonly MaintenanceModeResolver $maintenanceModeResolver,private readonly ShopIdProvider $shopIdProvider,private readonly ActiveAppsLoader $activeAppsLoader,private readonly SystemConfigService $systemConfigService,private readonly StorefrontPluginRegistryInterface $themeRegistry) {}public static function getSubscribedEvents(): array{return [KernelEvents::REQUEST => [['startSession', 40],['maintenanceResolver'],],KernelEvents::EXCEPTION => [['customerNotLoggedInHandler'],['maintenanceResolver'],],KernelEvents::CONTROLLER => [['preventPageLoadingFromXmlHttpRequest', KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_SCOPE_VALIDATE],],CustomerLoginEvent::class => ['updateSessionAfterLogin',],CustomerLogoutEvent::class => ['updateSessionAfterLogout',],BeforeSendResponseEvent::class => [['setCanonicalUrl'],],StorefrontRenderEvent::class => [['addHreflang'],['addShopIdParameter'],['addIconSetConfig'],],SalesChannelContextResolvedEvent::class => [['replaceContextToken'],],];}public function startSession(): void{$master = $this->requestStack->getMainRequest();if (!$master) {return;}if (!$master->attributes->get(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {return;}if (!$master->hasSession()) {return;}$session = $master->getSession();if (!$session->isStarted()) {$session->setName('session-');$session->start();$session->set('sessionId', $session->getId());}$salesChannelId = $master->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID);if ($salesChannelId === null) {/** @var SalesChannelContext|null $salesChannelContext */$salesChannelContext = $master->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);if ($salesChannelContext !== null) {$salesChannelId = $salesChannelContext->getSalesChannel()->getId();}}if ($this->shouldRenewToken($session, $salesChannelId)) {$token = Random::getAlphanumericString(32);$session->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $token);$session->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID, $salesChannelId);}$master->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN,$session->get(PlatformRequest::HEADER_CONTEXT_TOKEN));}public function updateSessionAfterLogin(CustomerLoginEvent $event): void{$token = $event->getContextToken();$this->updateSession($token);}public function updateSessionAfterLogout(): void{$newToken = Random::getAlphanumericString(32);$this->updateSession($newToken, true);}public function updateSession(string $token, bool $destroyOldSession = false): void{$master = $this->requestStack->getMainRequest();if (!$master) {return;}if (!$master->attributes->get(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {return;}if (!$master->hasSession()) {return;}$session = $master->getSession();$session->migrate($destroyOldSession);$session->set('sessionId', $session->getId());$session->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $token);$master->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $token);}public function customerNotLoggedInHandler(ExceptionEvent $event): void{if (!$event->getRequest()->attributes->has(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {return;}if (!$event->getThrowable() instanceof CustomerNotLoggedInException) {return;}$request = $event->getRequest();$parameters = ['redirectTo' => $request->attributes->get('_route'),'redirectParameters' => json_encode($request->attributes->get('_route_params'), \JSON_THROW_ON_ERROR),];$redirectResponse = new RedirectResponse($this->router->generate('frontend.account.login.page', $parameters));$event->setResponse($redirectResponse);}public function maintenanceResolver(RequestEvent $event): void{if ($this->maintenanceModeResolver->shouldRedirect($event->getRequest())) {$event->setResponse(new RedirectResponse($this->router->generate('frontend.maintenance.page'),RedirectResponse::HTTP_TEMPORARY_REDIRECT));}}public function preventPageLoadingFromXmlHttpRequest(ControllerEvent $event): void{if (!$event->getRequest()->isXmlHttpRequest()) {return;}/** @var list<string> $scope */$scope = $event->getRequest()->attributes->get(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE, []);if (!\in_array(StorefrontRouteScope::ID, $scope, true)) {return;}/** @var callable(): Response $controller */$controller = $event->getController();// happens if Controller is a closureif (!\is_array($controller)) {return;}$isAllowed = $event->getRequest()->attributes->getBoolean('XmlHttpRequest');if ($isAllowed) {return;}throw new AccessDeniedHttpException('PageController can\'t be requested via XmlHttpRequest.');}// used to switch session token - when the context token expiredpublic function replaceContextToken(SalesChannelContextResolvedEvent $event): void{$context = $event->getSalesChannelContext();// only update session if token expired and switchedif ($event->getUsedToken() === $context->getToken()) {return;}$this->updateSession($context->getToken());}public function setCanonicalUrl(BeforeSendResponseEvent $event): void{if (!$event->getResponse()->isSuccessful()) {return;}if ($canonical = $event->getRequest()->attributes->get(SalesChannelRequest::ATTRIBUTE_CANONICAL_LINK)) {\assert(\is_string($canonical));$canonical = sprintf('<%s>; rel="canonical"', $canonical);$event->getResponse()->headers->set('Link', $canonical);}}public function addHreflang(StorefrontRenderEvent $event): void{$request = $event->getRequest();$route = $request->attributes->get('_route');if ($route === null) {return;}$routeParams = $request->attributes->get('_route_params', []);$salesChannelContext = $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);$parameter = new HreflangLoaderParameter($route, $routeParams, $salesChannelContext);$event->setParameter('hrefLang', $this->hreflangLoader->load($parameter));}public function addShopIdParameter(StorefrontRenderEvent $event): void{if (!$this->activeAppsLoader->getActiveApps()) {return;}try {$shopId = $this->shopIdProvider->getShopId();} catch (AppUrlChangeDetectedException) {return;}$event->setParameter('appShopId', $shopId);}public function addIconSetConfig(StorefrontRenderEvent $event): void{$request = $event->getRequest();// get name if theme is not inherited$theme = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_THEME_NAME);if (!$theme) {// get theme name from base theme because for inherited themes the name is always null$theme = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_THEME_BASE_NAME);}if (!$theme) {return;}$themeConfig = $this->themeRegistry->getConfigurations()->getByTechnicalName($theme);if (!$themeConfig) {return;}$iconConfig = [];foreach ($themeConfig->getIconSets() as $pack => $path) {$iconConfig[$pack] = ['path' => $path,'namespace' => $theme,];}$event->setParameter('themeIconConfig', $iconConfig);}private function shouldRenewToken(SessionInterface $session, ?string $salesChannelId = null): bool{if (!$session->has(PlatformRequest::HEADER_CONTEXT_TOKEN) || $salesChannelId === null) {return true;}if ($this->systemConfigService->get('core.systemWideLoginRegistration.isCustomerBoundToSalesChannel')) {return $session->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID) !== $salesChannelId;}return false;}}