vendor/shopware/core/Framework/Routing/SalesChannelRequestContextResolver.php line 67

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Routing;
  3. use Shopware\Core\Checkout\Cart\CartException;
  4. use Shopware\Core\Framework\Feature;
  5. use Shopware\Core\Framework\Log\Package;
  6. use Shopware\Core\Framework\Routing\Annotation\ContextTokenRequired;
  7. use Shopware\Core\Framework\Routing\Annotation\LoginRequired;
  8. use Shopware\Core\Framework\Routing\Event\SalesChannelContextResolvedEvent;
  9. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  10. use Shopware\Core\Framework\Util\Random;
  11. use Shopware\Core\PlatformRequest;
  12. use Shopware\Core\SalesChannelRequest;
  13. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
  14. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceParameters;
  15. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  16. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
  19. #[Package('core')]
  20. class SalesChannelRequestContextResolver implements RequestContextResolverInterface
  21. {
  22. use RouteScopeCheckTrait;
  23. /**
  24. * @var RequestContextResolverInterface
  25. */
  26. private $decorated;
  27. /**
  28. * @var SalesChannelContextServiceInterface
  29. */
  30. private $contextService;
  31. /**
  32. * @var EventDispatcherInterface
  33. */
  34. private $eventDispatcher;
  35. /**
  36. * @var SalesChannelContext[]
  37. */
  38. private $cache = [];
  39. /**
  40. * @var RouteScopeRegistry
  41. */
  42. private $routeScopeRegistry;
  43. /**
  44. * @internal
  45. */
  46. public function __construct(
  47. RequestContextResolverInterface $decorated,
  48. SalesChannelContextServiceInterface $contextService,
  49. EventDispatcherInterface $eventDispatcher,
  50. RouteScopeRegistry $routeScopeRegistry
  51. ) {
  52. $this->decorated = $decorated;
  53. $this->contextService = $contextService;
  54. $this->eventDispatcher = $eventDispatcher;
  55. $this->routeScopeRegistry = $routeScopeRegistry;
  56. }
  57. public function resolve(SymfonyRequest $request): void
  58. {
  59. if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID)) {
  60. $this->decorated->resolve($request);
  61. return;
  62. }
  63. if (!$this->isRequestScoped($request, SalesChannelContextRouteScopeDependant::class)) {
  64. return;
  65. }
  66. if (
  67. $this->contextTokenRequired($request) === true
  68. && !$request->headers->has(PlatformRequest::HEADER_CONTEXT_TOKEN)
  69. ) {
  70. throw new MissingRequestParameterException(PlatformRequest::HEADER_CONTEXT_TOKEN);
  71. }
  72. if (
  73. $this->contextTokenRequired($request) === false
  74. && !$request->headers->has(PlatformRequest::HEADER_CONTEXT_TOKEN)
  75. ) {
  76. $request->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, Random::getAlphanumericString(32));
  77. }
  78. $contextToken = $request->headers->get(PlatformRequest::HEADER_CONTEXT_TOKEN);
  79. $salesChannelId = $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID);
  80. $language = $request->headers->get(PlatformRequest::HEADER_LANGUAGE_ID);
  81. $currencyId = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_CURRENCY_ID);
  82. $domainId = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_ID);
  83. $cacheKey = $salesChannelId . $contextToken . $language . $currencyId . $domainId;
  84. if (!empty($this->cache[$cacheKey])) {
  85. $context = $this->cache[$cacheKey];
  86. } else {
  87. $context = $this->contextService->get(
  88. new SalesChannelContextServiceParameters((string) $salesChannelId, (string) $contextToken, $language, $currencyId, $domainId)
  89. );
  90. $request->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $context->getToken());
  91. }
  92. $this->validateLogin($request, $context);
  93. $request->attributes->set(PlatformRequest::ATTRIBUTE_CONTEXT_OBJECT, $context->getContext());
  94. $request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT, $context);
  95. $request->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $context->getToken());
  96. $this->eventDispatcher->dispatch(
  97. new SalesChannelContextResolvedEvent($context, (string) $contextToken)
  98. );
  99. }
  100. public function handleSalesChannelContext(Request $request, string $salesChannelId, string $contextToken): void
  101. {
  102. $language = $request->headers->get(PlatformRequest::HEADER_LANGUAGE_ID);
  103. $currencyId = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_CURRENCY_ID);
  104. $context = $this->contextService
  105. ->get(new SalesChannelContextServiceParameters($salesChannelId, $contextToken, $language, $currencyId));
  106. $request->attributes->set(PlatformRequest::ATTRIBUTE_CONTEXT_OBJECT, $context->getContext());
  107. $request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT, $context);
  108. }
  109. protected function getScopeRegistry(): RouteScopeRegistry
  110. {
  111. return $this->routeScopeRegistry;
  112. }
  113. private function contextTokenRequired(Request $request): bool
  114. {
  115. if (Feature::isActive('v6.5.0.0')) {
  116. return $request->attributes->get(PlatformRequest::ATTRIBUTE_CONTEXT_TOKEN_REQUIRED, false);
  117. }
  118. if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_CONTEXT_TOKEN_REQUIRED)) {
  119. return false;
  120. }
  121. /** @var ContextTokenRequired|bool $contextTokenRequiredAnnotation */
  122. $contextTokenRequiredAnnotation = $request->attributes->get(PlatformRequest::ATTRIBUTE_CONTEXT_TOKEN_REQUIRED);
  123. if (\is_bool($contextTokenRequiredAnnotation)) {
  124. return $contextTokenRequiredAnnotation;
  125. }
  126. return $contextTokenRequiredAnnotation->isRequired();
  127. }
  128. private function validateLogin(Request $request, SalesChannelContext $context): void
  129. {
  130. if (Feature::isActive('v6.5.0.0')) {
  131. if (!$request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED)) {
  132. return;
  133. }
  134. if ($context->getCustomer() === null) {
  135. throw CartException::customerNotLoggedIn();
  136. }
  137. if ($request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED_ALLOW_GUEST, false) === false && $context->getCustomer()->getGuest()) {
  138. throw CartException::customerNotLoggedIn();
  139. }
  140. return;
  141. }
  142. /** @var LoginRequired|bool|null $loginRequired */
  143. $loginRequired = $request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED);
  144. if ($loginRequired === null) {
  145. return;
  146. }
  147. if (\is_bool($loginRequired)) {
  148. if (!$loginRequired) {
  149. return;
  150. }
  151. if ($context->getCustomer() === null) {
  152. throw CartException::customerNotLoggedIn();
  153. }
  154. if ($request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED_ALLOW_GUEST, false) === false && $context->getCustomer()->getGuest()) {
  155. throw CartException::customerNotLoggedIn();
  156. }
  157. return;
  158. }
  159. if ($loginRequired->isLoggedIn($context)) {
  160. return;
  161. }
  162. throw CartException::customerNotLoggedIn();
  163. }
  164. }