vendor/shopware/core/Framework/Routing/RouteScopeListener.php line 50

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Routing;
  3. use Shopware\Core\Framework\Log\Package;
  4. use Shopware\Core\Framework\Routing\Exception\InvalidRouteScopeException;
  5. use Shopware\Core\PlatformRequest;
  6. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\RequestStack;
  9. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  10. use Symfony\Component\HttpKernel\KernelEvents;
  11. /**
  12.  * @internal
  13.  */
  14. #[Package('core')]
  15. class RouteScopeListener implements EventSubscriberInterface
  16. {
  17.     /**
  18.      * @var RouteScopeWhitelistInterface[]
  19.      */
  20.     private readonly array $whitelists;
  21.     /**
  22.      * @internal
  23.      *
  24.      * @param iterable<RouteScopeWhitelistInterface> $whitelists
  25.      */
  26.     public function __construct(
  27.         private readonly RouteScopeRegistry $routeScopeRegistry,
  28.         private readonly RequestStack $requestStack,
  29.         iterable $whitelists
  30.     ) {
  31.         $this->whitelists \is_array($whitelists) ? $whitelists iterator_to_array($whitelists);
  32.     }
  33.     public static function getSubscribedEvents(): array
  34.     {
  35.         return [
  36.             KernelEvents::CONTROLLER => [
  37.                 ['checkScope'KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_SCOPE_VALIDATE],
  38.             ],
  39.         ];
  40.     }
  41.     /**
  42.      * Validate that any given controller invocation creates a valid scope with the original master request
  43.      */
  44.     public function checkScope(ControllerEvent $event): void
  45.     {
  46.         if ($this->isWhitelistedController($event)) {
  47.             return;
  48.         }
  49.         $scopes $this->extractCurrentScopeAnnotation($event);
  50.         $masterRequest $this->getMainRequest();
  51.         foreach ($scopes as $routeScopeName) {
  52.             $routeScope $this->routeScopeRegistry->getRouteScope($routeScopeName);
  53.             $pathAllowed $routeScope->isAllowedPath($masterRequest->getPathInfo());
  54.             $requestAllowed $routeScope->isAllowed($masterRequest);
  55.             if ($pathAllowed && $requestAllowed) {
  56.                 return;
  57.             }
  58.         }
  59.         throw new InvalidRouteScopeException($masterRequest->attributes->get('_route'));
  60.     }
  61.     private function extractControllerClass(ControllerEvent $event): ?string
  62.     {
  63.         $controllerCallable \Closure::fromCallable($event->getController());
  64.         $controllerCallable = new \ReflectionFunction($controllerCallable);
  65.         $controller $controllerCallable->getClosureThis();
  66.         if (!$controller) {
  67.             return null;
  68.         }
  69.         return $controller::class;
  70.     }
  71.     private function isWhitelistedController(ControllerEvent $event): bool
  72.     {
  73.         $controllerClass $this->extractControllerClass($event);
  74.         if (!$controllerClass) {
  75.             return false;
  76.         }
  77.         foreach ($this->whitelists as $whitelist) {
  78.             if ($whitelist->applies($controllerClass)) {
  79.                 return true;
  80.             }
  81.         }
  82.         return false;
  83.     }
  84.     /**
  85.      * @return list<string>
  86.      */
  87.     private function extractCurrentScopeAnnotation(ControllerEvent $event): array
  88.     {
  89.         $currentRequest $event->getRequest();
  90.         /** @var list<string> $scopes */
  91.         $scopes $currentRequest->get(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE, []);
  92.         if ($scopes !== []) {
  93.             return $scopes;
  94.         }
  95.         throw new InvalidRouteScopeException($currentRequest->attributes->get('_route'));
  96.     }
  97.     private function getMainRequest(): Request
  98.     {
  99.         $masterRequest $this->requestStack->getMainRequest();
  100.         if (!$masterRequest) {
  101.             throw new \InvalidArgumentException('Unable to check the request scope without master request');
  102.         }
  103.         return $masterRequest;
  104.     }
  105. }