<?php declare(strict_types=1);namespace Shopware\Core\Framework\Routing;use Shopware\Core\Checkout\Cart\CartException;use Shopware\Core\Framework\Feature;use Shopware\Core\Framework\Log\Package;use Shopware\Core\Framework\Routing\Annotation\ContextTokenRequired;use Shopware\Core\Framework\Routing\Annotation\LoginRequired;use Shopware\Core\Framework\Routing\Event\SalesChannelContextResolvedEvent;use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;use Shopware\Core\Framework\Util\Random;use Shopware\Core\PlatformRequest;use Shopware\Core\SalesChannelRequest;use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceParameters;use Shopware\Core\System\SalesChannel\SalesChannelContext;use Symfony\Component\EventDispatcher\EventDispatcherInterface;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Request as SymfonyRequest;#[Package('core')]class SalesChannelRequestContextResolver implements RequestContextResolverInterface{ use RouteScopeCheckTrait; /** * @var RequestContextResolverInterface */ private $decorated; /** * @var SalesChannelContextServiceInterface */ private $contextService; /** * @var EventDispatcherInterface */ private $eventDispatcher; /** * @var SalesChannelContext[] */ private $cache = []; /** * @var RouteScopeRegistry */ private $routeScopeRegistry; /** * @internal */ public function __construct( RequestContextResolverInterface $decorated, SalesChannelContextServiceInterface $contextService, EventDispatcherInterface $eventDispatcher, RouteScopeRegistry $routeScopeRegistry ) { $this->decorated = $decorated; $this->contextService = $contextService; $this->eventDispatcher = $eventDispatcher; $this->routeScopeRegistry = $routeScopeRegistry; } public function resolve(SymfonyRequest $request): void { if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID)) { $this->decorated->resolve($request); return; } if (!$this->isRequestScoped($request, SalesChannelContextRouteScopeDependant::class)) { return; } if ( $this->contextTokenRequired($request) === true && !$request->headers->has(PlatformRequest::HEADER_CONTEXT_TOKEN) ) { throw new MissingRequestParameterException(PlatformRequest::HEADER_CONTEXT_TOKEN); } if ( $this->contextTokenRequired($request) === false && !$request->headers->has(PlatformRequest::HEADER_CONTEXT_TOKEN) ) { $request->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, Random::getAlphanumericString(32)); } $contextToken = $request->headers->get(PlatformRequest::HEADER_CONTEXT_TOKEN); $salesChannelId = $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID); $language = $request->headers->get(PlatformRequest::HEADER_LANGUAGE_ID); $currencyId = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_CURRENCY_ID); $domainId = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_ID); $cacheKey = $salesChannelId . $contextToken . $language . $currencyId . $domainId; if (!empty($this->cache[$cacheKey])) { $context = $this->cache[$cacheKey]; } else { $context = $this->contextService->get( new SalesChannelContextServiceParameters((string) $salesChannelId, (string) $contextToken, $language, $currencyId, $domainId) ); $request->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $context->getToken()); } $this->validateLogin($request, $context); $request->attributes->set(PlatformRequest::ATTRIBUTE_CONTEXT_OBJECT, $context->getContext()); $request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT, $context); $request->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $context->getToken()); $this->eventDispatcher->dispatch( new SalesChannelContextResolvedEvent($context, (string) $contextToken) ); } public function handleSalesChannelContext(Request $request, string $salesChannelId, string $contextToken): void { $language = $request->headers->get(PlatformRequest::HEADER_LANGUAGE_ID); $currencyId = $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_CURRENCY_ID); $context = $this->contextService ->get(new SalesChannelContextServiceParameters($salesChannelId, $contextToken, $language, $currencyId)); $request->attributes->set(PlatformRequest::ATTRIBUTE_CONTEXT_OBJECT, $context->getContext()); $request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT, $context); } protected function getScopeRegistry(): RouteScopeRegistry { return $this->routeScopeRegistry; } private function contextTokenRequired(Request $request): bool { if (Feature::isActive('v6.5.0.0')) { return $request->attributes->get(PlatformRequest::ATTRIBUTE_CONTEXT_TOKEN_REQUIRED, false); } if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_CONTEXT_TOKEN_REQUIRED)) { return false; } /** @var ContextTokenRequired|bool $contextTokenRequiredAnnotation */ $contextTokenRequiredAnnotation = $request->attributes->get(PlatformRequest::ATTRIBUTE_CONTEXT_TOKEN_REQUIRED); if (\is_bool($contextTokenRequiredAnnotation)) { return $contextTokenRequiredAnnotation; } return $contextTokenRequiredAnnotation->isRequired(); } private function validateLogin(Request $request, SalesChannelContext $context): void { if (Feature::isActive('v6.5.0.0')) { if (!$request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED)) { return; } if ($context->getCustomer() === null) { throw CartException::customerNotLoggedIn(); } if ($request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED_ALLOW_GUEST, false) === false && $context->getCustomer()->getGuest()) { throw CartException::customerNotLoggedIn(); } return; } /** @var LoginRequired|bool|null $loginRequired */ $loginRequired = $request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED); if ($loginRequired === null) { return; } if (\is_bool($loginRequired)) { if (!$loginRequired) { return; } if ($context->getCustomer() === null) { throw CartException::customerNotLoggedIn(); } if ($request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED_ALLOW_GUEST, false) === false && $context->getCustomer()->getGuest()) { throw CartException::customerNotLoggedIn(); } return; } if ($loginRequired->isLoggedIn($context)) { return; } throw CartException::customerNotLoggedIn(); }}