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

Open in your IDE?
  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 RouterInterface, RequestMatcherInterface, WarmableInterface, ServiceSubscriberInterface
  16. {
  17. /**
  18. * @var int Used to indicate the router that we only need the path info without the sales channel prefix
  19. */
  20. public const PATH_INFO = 10;
  21. /**
  22. * @var SymfonyRouter
  23. */
  24. private $decorated;
  25. /**
  26. * @var RequestStack
  27. */
  28. private $requestStack;
  29. /**
  30. * @internal
  31. */
  32. public function __construct(SymfonyRouter $decorated, RequestStack $requestStack)
  33. {
  34. $this->decorated = $decorated;
  35. $this->requestStack = $requestStack;
  36. }
  37. /**
  38. * @return array
  39. */
  40. public static function getSubscribedServices()
  41. {
  42. return SymfonyRouter::getSubscribedServices();
  43. }
  44. /**
  45. * @return array<string>
  46. */
  47. public function warmUp(string $cacheDir)
  48. {
  49. return $this->decorated->warmUp($cacheDir);
  50. }
  51. /**
  52. * @return array
  53. */
  54. public function matchRequest(Request $request)
  55. {
  56. if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID)) {
  57. return $this->decorated->matchRequest($request);
  58. }
  59. $server = array_merge(
  60. $request->server->all(),
  61. ['REQUEST_URI' => $request->attributes->get(RequestTransformer::SALES_CHANNEL_RESOLVED_URI)]
  62. );
  63. $localClone = $request->duplicate(null, null, null, null, null, $server);
  64. return $this->decorated->matchRequest($localClone);
  65. }
  66. public function setContext(RequestContext $context)
  67. {
  68. return $this->decorated->setContext($context);
  69. }
  70. /**
  71. * @return RequestContext
  72. */
  73. public function getContext()
  74. {
  75. return $this->decorated->getContext();
  76. }
  77. /**
  78. * @return RouteCollection
  79. */
  80. public function getRouteCollection()
  81. {
  82. return $this->decorated->getRouteCollection();
  83. }
  84. /**
  85. * @return string
  86. */
  87. public function generate(string $name, array $parameters = [], int $referenceType = self::ABSOLUTE_PATH)
  88. {
  89. $basePath = $this->getBasePath();
  90. if ($referenceType === self::PATH_INFO) {
  91. $route = $this->decorated->generate($name, $parameters, self::ABSOLUTE_PATH);
  92. return $this->removePrefix($route, $basePath);
  93. }
  94. if (!$this->isStorefrontRoute($name)) {
  95. return $this->decorated->generate($name, $parameters, $referenceType);
  96. }
  97. $salesChannelBaseUrl = $this->getSalesChannelBaseUrl();
  98. // we need to insert the sales channel base url between the baseUrl and the infoPath
  99. switch ($referenceType) {
  100. case self::NETWORK_PATH:
  101. case self::ABSOLUTE_URL:
  102. $schema = '';
  103. if ($referenceType === self::ABSOLUTE_URL) {
  104. $schema = $this->getContext()->getScheme() . ':';
  105. }
  106. $schemaAuthority = $schema . '//' . $this->getContext()->getHost();
  107. if ($this->getContext()->getHttpPort() !== 80) {
  108. $schemaAuthority .= ':' . $this->getContext()->getHttpPort();
  109. } elseif ($this->getContext()->getHttpsPort() !== 443) {
  110. $schemaAuthority .= ':' . $this->getContext()->getHttpsPort();
  111. }
  112. $generated = $this->decorated->generate($name, $parameters);
  113. $pathInfo = $this->removePrefix($generated, $basePath);
  114. $rewrite = $schemaAuthority . rtrim($basePath, '/') . rtrim($salesChannelBaseUrl, '/') . $pathInfo;
  115. break;
  116. case self::RELATIVE_PATH:
  117. // remove base path from generated url (/shopware/public or /)
  118. $generated = $this->removePrefix(
  119. $this->decorated->generate($name, $parameters, self::RELATIVE_PATH),
  120. $basePath
  121. );
  122. // url contains the base path and the base url
  123. // base url /shopware/public/de
  124. $rewrite = ltrim($salesChannelBaseUrl, '/') . $generated;
  125. break;
  126. case self::ABSOLUTE_PATH:
  127. default:
  128. $generated = $this->removePrefix(
  129. $this->decorated->generate($name, $parameters),
  130. $basePath
  131. );
  132. $rewrite = $basePath . rtrim($salesChannelBaseUrl, '/') . $generated;
  133. break;
  134. }
  135. return $rewrite;
  136. }
  137. /**
  138. * @return array
  139. */
  140. public function match($pathinfo)
  141. {
  142. return $this->decorated->match($pathinfo);
  143. }
  144. private function removePrefix(string $subject, string $prefix): string
  145. {
  146. if (!$prefix || mb_strpos($subject, $prefix) !== 0) {
  147. return $subject;
  148. }
  149. return mb_substr($subject, mb_strlen($prefix));
  150. }
  151. private function getSalesChannelBaseUrl(): string
  152. {
  153. $request = $this->requestStack->getMainRequest();
  154. if (!$request) {
  155. return '';
  156. }
  157. $url = (string) $request->attributes->get(RequestTransformer::SALES_CHANNEL_BASE_URL);
  158. if (empty($url)) {
  159. return $url;
  160. }
  161. return '/' . trim($url, '/') . '/';
  162. }
  163. private function getBasePath(): string
  164. {
  165. $request = $this->requestStack->getMainRequest();
  166. if (!$request) {
  167. return '';
  168. }
  169. return $request->getBasePath();
  170. }
  171. private function isStorefrontRoute(string $name): bool
  172. {
  173. return strncmp($name, 'frontend.', 9) === 0
  174. || strncmp($name, 'widgets.', 8) === 0
  175. || strncmp($name, 'payment.', 8) === 0;
  176. }
  177. }