vendor/shopware/storefront/Framework/Routing/Router.php line 63

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Framework\Routing;
  3. use Shopware\Core\Framework\Log\Package;
  4. use Shopware\Core\PlatformRequest;
  5. use Symfony\Bundle\FrameworkBundle\Routing\Router as SymfonyRouter;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Symfony\Component\HttpFoundation\RequestStack;
  8. use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
  9. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  10. use Symfony\Component\Routing\RequestContext;
  11. use Symfony\Component\Routing\RouteCollection;
  12. use Symfony\Component\Routing\RouterInterface;
  13. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  14. #[Package('storefront')]
  15. class Router implements RouterInterfaceRequestMatcherInterfaceWarmableInterfaceServiceSubscriberInterface
  16. {
  17.     /**
  18.      * @var int Used to indicate the router that we only need the path info without the sales channel prefix
  19.      */
  20.     final public const PATH_INFO 10;
  21.     /**
  22.      * @internal
  23.      */
  24.     public function __construct(
  25.         private readonly SymfonyRouter $decorated,
  26.         private readonly RequestStack $requestStack
  27.     ) {
  28.     }
  29.     /**
  30.      * @return array<string, string>
  31.      */
  32.     public static function getSubscribedServices(): array
  33.     {
  34.         return SymfonyRouter::getSubscribedServices();
  35.     }
  36.     /**
  37.      * @return array<string>
  38.      */
  39.     public function warmUp(string $cacheDir): array
  40.     {
  41.         return $this->decorated->warmUp($cacheDir);
  42.     }
  43.     public function matchRequest(Request $request): array
  44.     {
  45.         if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID)) {
  46.             return $this->decorated->matchRequest($request);
  47.         }
  48.         $server array_merge(
  49.             $request->server->all(),
  50.             ['REQUEST_URI' => $request->attributes->get(RequestTransformer::SALES_CHANNEL_RESOLVED_URI)]
  51.         );
  52.         $localClone $request->duplicate(nullnullnullnullnull$server);
  53.         return $this->decorated->matchRequest($localClone);
  54.     }
  55.     public function setContext(RequestContext $context): void
  56.     {
  57.         $this->decorated->setContext($context);
  58.     }
  59.     public function getContext(): RequestContext
  60.     {
  61.         return $this->decorated->getContext();
  62.     }
  63.     public function getRouteCollection(): RouteCollection
  64.     {
  65.         return $this->decorated->getRouteCollection();
  66.     }
  67.     public function generate(string $name, array $parameters = [], int $referenceType self::ABSOLUTE_PATH): string
  68.     {
  69.         $basePath $this->getBasePath();
  70.         if ($referenceType === self::PATH_INFO) {
  71.             $route $this->decorated->generate($name$parameters);
  72.             return $this->removePrefix($route$basePath);
  73.         }
  74.         if (!$this->isStorefrontRoute($name)) {
  75.             return $this->decorated->generate($name$parameters$referenceType);
  76.         }
  77.         $salesChannelBaseUrl $this->getSalesChannelBaseUrl();
  78.         // we need to insert the sales channel base url between the baseUrl and the infoPath
  79.         switch ($referenceType) {
  80.             case self::NETWORK_PATH:
  81.             case self::ABSOLUTE_URL:
  82.                 $schema '';
  83.                 if ($referenceType === self::ABSOLUTE_URL) {
  84.                     $schema $this->getContext()->getScheme() . ':';
  85.                 }
  86.                 $schemaAuthority $schema '//' $this->getContext()->getHost();
  87.                 if ($this->getContext()->getHttpPort() !== 80) {
  88.                     $schemaAuthority .= ':' $this->getContext()->getHttpPort();
  89.                 } elseif ($this->getContext()->getHttpsPort() !== 443) {
  90.                     $schemaAuthority .= ':' $this->getContext()->getHttpsPort();
  91.                 }
  92.                 $generated $this->decorated->generate($name$parameters);
  93.                 $pathInfo $this->removePrefix($generated$basePath);
  94.                 $rewrite $schemaAuthority rtrim($basePath'/') . rtrim($salesChannelBaseUrl'/') . $pathInfo;
  95.                 break;
  96.             case self::RELATIVE_PATH:
  97.                 // remove base path from generated url (/shopware/public or /)
  98.                 $generated $this->removePrefix(
  99.                     $this->decorated->generate($name$parametersself::RELATIVE_PATH),
  100.                     $basePath
  101.                 );
  102.                 // url contains the base path and the base url
  103.                 // base url /shopware/public/de
  104.                 $rewrite ltrim($salesChannelBaseUrl'/') . $generated;
  105.                 break;
  106.             case self::ABSOLUTE_PATH:
  107.             default:
  108.                 $generated $this->removePrefix(
  109.                     $this->decorated->generate($name$parameters),
  110.                     $basePath
  111.                 );
  112.                 $rewrite $basePath rtrim($salesChannelBaseUrl'/') . $generated;
  113.                 break;
  114.         }
  115.         return $rewrite;
  116.     }
  117.     public function match(string $pathinfo): array
  118.     {
  119.         return $this->decorated->match($pathinfo);
  120.     }
  121.     private function removePrefix(string $subjectstring $prefix): string
  122.     {
  123.         if (!$prefix || mb_strpos($subject$prefix) !== 0) {
  124.             return $subject;
  125.         }
  126.         return mb_substr($subjectmb_strlen($prefix));
  127.     }
  128.     private function getSalesChannelBaseUrl(): string
  129.     {
  130.         $request $this->requestStack->getMainRequest();
  131.         if (!$request) {
  132.             return '';
  133.         }
  134.         $url = (string) $request->attributes->get(RequestTransformer::SALES_CHANNEL_BASE_URL);
  135.         if (empty($url)) {
  136.             return $url;
  137.         }
  138.         return '/' trim($url'/') . '/';
  139.     }
  140.     private function getBasePath(): string
  141.     {
  142.         $request $this->requestStack->getMainRequest();
  143.         if (!$request) {
  144.             return '';
  145.         }
  146.         return $request->getBasePath();
  147.     }
  148.     private function isStorefrontRoute(string $name): bool
  149.     {
  150.         return str_starts_with($name'frontend.')
  151.             || str_starts_with($name'widgets.')
  152.             || str_starts_with($name'payment.');
  153.     }
  154. }