vendor/shopware/storefront/Framework/Routing/StorefrontSubscriber.php line 255

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Framework\Routing;
  3. use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
  4. use Shopware\Core\Checkout\Customer\Event\CustomerLoginEvent;
  5. use Shopware\Core\Content\Seo\HreflangLoaderInterface;
  6. use Shopware\Core\Content\Seo\HreflangLoaderParameter;
  7. use Shopware\Core\Framework\Event\BeforeSendResponseEvent;
  8. use Shopware\Core\Framework\Routing\KernelListenerPriorities;
  9. use Shopware\Core\Framework\Util\Random;
  10. use Shopware\Core\PlatformRequest;
  11. use Shopware\Core\SalesChannelRequest;
  12. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
  13. use Shopware\Storefront\Controller\ErrorController;
  14. use Shopware\Storefront\Event\StorefrontRenderEvent;
  15. use Shopware\Storefront\Framework\Csrf\CsrfPlaceholderHandler;
  16. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  17. use Symfony\Component\HttpFoundation\RedirectResponse;
  18. use Symfony\Component\HttpFoundation\RequestStack;
  19. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  20. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  21. use Symfony\Component\HttpKernel\Event\RequestEvent;
  22. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  23. use Symfony\Component\HttpKernel\KernelEvents;
  24. use Symfony\Component\Routing\RouterInterface;
  25. class StorefrontSubscriber implements EventSubscriberInterface
  26. {
  27.     /**
  28.      * @var RequestStack
  29.      */
  30.     private $requestStack;
  31.     /**
  32.      * @var RouterInterface
  33.      */
  34.     private $router;
  35.     /**
  36.      * @var ErrorController
  37.      */
  38.     private $errorController;
  39.     /**
  40.      * @var SalesChannelContextServiceInterface
  41.      */
  42.     private $contextService;
  43.     /**
  44.      * @var bool
  45.      */
  46.     private $kernelDebug;
  47.     /**
  48.      * @var CsrfPlaceholderHandler
  49.      */
  50.     private $csrfPlaceholderHandler;
  51.     /**
  52.      * @var MaintenanceModeResolver
  53.      */
  54.     private $maintenanceModeResolver;
  55.     /**
  56.      * @var HreflangLoaderInterface
  57.      */
  58.     private $hreflangLoader;
  59.     public function __construct(
  60.         RequestStack $requestStack,
  61.         RouterInterface $router,
  62.         ErrorController $errorController,
  63.         SalesChannelContextServiceInterface $contextService,
  64.         CsrfPlaceholderHandler $csrfPlaceholderHandler,
  65.         HreflangLoaderInterface $hreflangLoader,
  66.         bool $kernelDebug,
  67.         MaintenanceModeResolver $maintenanceModeResolver
  68.     ) {
  69.         $this->requestStack $requestStack;
  70.         $this->router $router;
  71.         $this->errorController $errorController;
  72.         $this->contextService $contextService;
  73.         $this->kernelDebug $kernelDebug;
  74.         $this->csrfPlaceholderHandler $csrfPlaceholderHandler;
  75.         $this->maintenanceModeResolver $maintenanceModeResolver;
  76.         $this->hreflangLoader $hreflangLoader;
  77.     }
  78.     public static function getSubscribedEvents(): array
  79.     {
  80.         return [
  81.             KernelEvents::REQUEST => [
  82.                 ['startSession'40],
  83.                 ['maintenanceResolver'],
  84.             ],
  85.             KernelEvents::EXCEPTION => [
  86.                 ['showHtmlExceptionResponse', -100],
  87.                 ['customerNotLoggedInHandler'],
  88.                 ['maintenanceResolver'],
  89.             ],
  90.             KernelEvents::CONTROLLER => [
  91.                 ['preventPageLoadingFromXmlHttpRequest'KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_SCOPE_VALIDATE],
  92.             ],
  93.             CustomerLoginEvent::class => [
  94.                 'updateSession',
  95.             ],
  96.             BeforeSendResponseEvent::class => [
  97.                 ['replaceCsrfToken'],
  98.                 ['setCanonicalUrl'],
  99.             ],
  100.             StorefrontRenderEvent::class => [
  101.                 ['addHreflang'],
  102.             ],
  103.         ];
  104.     }
  105.     public function startSession(): void
  106.     {
  107.         $master $this->requestStack->getMasterRequest();
  108.         if (!$master) {
  109.             return;
  110.         }
  111.         if (!$master->attributes->get(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
  112.             return;
  113.         }
  114.         if (!$master->hasSession()) {
  115.             return;
  116.         }
  117.         $session $master->getSession();
  118.         $applicationId $master->attributes->get(PlatformRequest::ATTRIBUTE_OAUTH_CLIENT_ID);
  119.         if (!$session->isStarted()) {
  120.             $session->setName('session-' $applicationId);
  121.             $session->start();
  122.             $session->set('sessionId'$session->getId());
  123.         }
  124.         if (!$session->has(PlatformRequest::HEADER_CONTEXT_TOKEN)) {
  125.             $token Random::getAlphanumericString(32);
  126.             $session->set(PlatformRequest::HEADER_CONTEXT_TOKEN$token);
  127.         }
  128.         $master->headers->set(
  129.             PlatformRequest::HEADER_CONTEXT_TOKEN,
  130.             $session->get(PlatformRequest::HEADER_CONTEXT_TOKEN)
  131.         );
  132.     }
  133.     public function updateSession(CustomerLoginEvent $event): void
  134.     {
  135.         $master $this->requestStack->getMasterRequest();
  136.         if (!$master) {
  137.             return;
  138.         }
  139.         if (!$master->attributes->get(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
  140.             return;
  141.         }
  142.         if (!$master->hasSession()) {
  143.             return;
  144.         }
  145.         $session $master->getSession();
  146.         $session->migrate();
  147.         $session->set('sessionId'$session->getId());
  148.         $token $event->getContextToken();
  149.         $session->set(PlatformRequest::HEADER_CONTEXT_TOKEN$token);
  150.         $master->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN$token);
  151.     }
  152.     public function showHtmlExceptionResponse(ExceptionEvent $event): void
  153.     {
  154.         if ($this->kernelDebug) {
  155.             return;
  156.         }
  157.         if (!$event->getRequest()->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT)) {
  158.             //When no saleschannel context is resolved, we need to resolve it now.
  159.             $this->setSalesChannelContext($event);
  160.         }
  161.         if ($event->getRequest()->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT)) {
  162.             $event->stopPropagation();
  163.             $response $this->errorController->error(
  164.                 $event->getThrowable(),
  165.                 $this->requestStack->getMasterRequest(),
  166.                 $event->getRequest()->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT)
  167.             );
  168.             $event->setResponse($response);
  169.         }
  170.     }
  171.     public function customerNotLoggedInHandler(ExceptionEvent $event): void
  172.     {
  173.         if (!$event->getRequest()->attributes->has(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
  174.             return;
  175.         }
  176.         if (!$event->getThrowable() instanceof CustomerNotLoggedInException) {
  177.             return;
  178.         }
  179.         $request $event->getRequest();
  180.         $parameters = [
  181.             'redirectTo' => $request->attributes->get('_route'),
  182.             'redirectParameters' => json_encode($request->attributes->get('_route_params')),
  183.         ];
  184.         $redirectResponse = new RedirectResponse($this->router->generate('frontend.account.login.page'$parameters));
  185.         $event->setResponse($redirectResponse);
  186.     }
  187.     public function maintenanceResolver(RequestEvent $event): void
  188.     {
  189.         if ($this->maintenanceModeResolver->shouldRedirect($event->getRequest())) {
  190.             $event->setResponse(
  191.                 new RedirectResponse($this->router->generate('frontend.maintenance.page'))
  192.             );
  193.         }
  194.     }
  195.     public function preventPageLoadingFromXmlHttpRequest(ControllerEvent $event): void
  196.     {
  197.         if (!$event->getRequest()->isXmlHttpRequest()) {
  198.             return;
  199.         }
  200.         if (!$event->getRequest()->attributes->has(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
  201.             return;
  202.         }
  203.         $controller $event->getController();
  204.         // happens if Controller is a closure
  205.         if (!is_array($controller)) {
  206.             return;
  207.         }
  208.         $isAllowed $event->getRequest()->attributes->getBoolean('XmlHttpRequest'false);
  209.         if ($isAllowed) {
  210.             return;
  211.         }
  212.         throw new AccessDeniedHttpException('PageController can\'t be requested via XmlHttpRequest.');
  213.     }
  214.     public function setCanonicalUrl(BeforeSendResponseEvent $event): void
  215.     {
  216.         if (!$event->getResponse()->isSuccessful()) {
  217.             return;
  218.         }
  219.         if ($canonical $event->getRequest()->attributes->get(SalesChannelRequest::ATTRIBUTE_CANONICAL_LINK)) {
  220.             $canonical sprintf('<%s>; rel="canonical"'$canonical);
  221.             $event->getResponse()->headers->set('Link'$canonical);
  222.         }
  223.     }
  224.     public function replaceCsrfToken(BeforeSendResponseEvent $event): void
  225.     {
  226.         $event->setResponse(
  227.             $this->csrfPlaceholderHandler->replaceCsrfToken($event->getResponse())
  228.         );
  229.     }
  230.     public function addHreflang(StorefrontRenderEvent $event): void
  231.     {
  232.         $request $event->getRequest();
  233.         $route $request->attributes->get('_route');
  234.         if ($route === null) {
  235.             return;
  236.         }
  237.         $routeParams $request->attributes->get('_route_params', []);
  238.         $salesChannelContext $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);
  239.         $parameter = new HreflangLoaderParameter($route$routeParams$salesChannelContext);
  240.         $event->setParameter('hrefLang'$this->hreflangLoader->load($parameter));
  241.     }
  242.     private function setSalesChannelContext(ExceptionEvent $event): void
  243.     {
  244.         $contextToken $event->getRequest()->headers->get(PlatformRequest::HEADER_CONTEXT_TOKEN);
  245.         $salesChannelId $event->getRequest()->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID);
  246.         $context $this->contextService->get(
  247.             $salesChannelId,
  248.             $contextToken,
  249.             $event->getRequest()->headers->get(PlatformRequest::HEADER_LANGUAGE_ID)
  250.         );
  251.         $event->getRequest()->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT$context);
  252.     }
  253. }