vendor/shopware/core/Content/LandingPage/SalesChannel/CachedLandingPageRoute.php line 94

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\LandingPage\SalesChannel;
  3. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
  4. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductBoxStruct;
  5. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductSliderStruct;
  6. use Shopware\Core\Content\LandingPage\Event\LandingPageRouteCacheKeyEvent;
  7. use Shopware\Core\Content\LandingPage\Event\LandingPageRouteCacheTagsEvent;
  8. use Shopware\Core\Framework\Adapter\Cache\AbstractCacheTracer;
  9. use Shopware\Core\Framework\Adapter\Cache\CacheValueCompressor;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Cache\EntityCacheKeyGenerator;
  11. use Shopware\Core\Framework\DataAbstractionLayer\FieldSerializer\JsonFieldSerializer;
  12. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  13. use Shopware\Core\Framework\Routing\Annotation\Since;
  14. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. use Symfony\Contracts\Cache\CacheInterface;
  18. use Symfony\Contracts\Cache\ItemInterface;
  19. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  20. /**
  21.  * @Route(defaults={"_routeScope"={"store-api"}})
  22.  */
  23. class CachedLandingPageRoute extends AbstractLandingPageRoute
  24. {
  25.     private AbstractLandingPageRoute $decorated;
  26.     private CacheInterface $cache;
  27.     private EntityCacheKeyGenerator $generator;
  28.     /**
  29.      * @var AbstractCacheTracer<LandingPageRouteResponse>
  30.      */
  31.     private AbstractCacheTracer $tracer;
  32.     /**
  33.      * @var array<string>
  34.      */
  35.     private array $states;
  36.     private EventDispatcherInterface $dispatcher;
  37.     /**
  38.      * @internal
  39.      *
  40.      * @param AbstractCacheTracer<LandingPageRouteResponse> $tracer
  41.      * @param array<string> $states
  42.      */
  43.     public function __construct(
  44.         AbstractLandingPageRoute $decorated,
  45.         CacheInterface $cache,
  46.         EntityCacheKeyGenerator $generator,
  47.         AbstractCacheTracer $tracer,
  48.         EventDispatcherInterface $dispatcher,
  49.         array $states
  50.     ) {
  51.         $this->decorated $decorated;
  52.         $this->cache $cache;
  53.         $this->generator $generator;
  54.         $this->tracer $tracer;
  55.         $this->states $states;
  56.         $this->dispatcher $dispatcher;
  57.     }
  58.     public static function buildName(string $id): string
  59.     {
  60.         return 'landing-page-route-' $id;
  61.     }
  62.     public function getDecorated(): AbstractLandingPageRoute
  63.     {
  64.         return $this->decorated;
  65.     }
  66.     /**
  67.      * @Since("6.4.0.0")
  68.      * @Route("/store-api/landing-page/{landingPageId}", name="store-api.landing-page.detail", methods={"POST"})
  69.      */
  70.     public function load(string $landingPageIdRequest $requestSalesChannelContext $context): LandingPageRouteResponse
  71.     {
  72.         if ($context->hasState(...$this->states)) {
  73.             return $this->getDecorated()->load($landingPageId$request$context);
  74.         }
  75.         $key $this->generateKey($landingPageId$request$context);
  76.         if ($key === null) {
  77.             return $this->getDecorated()->load($landingPageId$request$context);
  78.         }
  79.         $value $this->cache->get($key, function (ItemInterface $item) use ($request$context$landingPageId) {
  80.             $name self::buildName($landingPageId);
  81.             $response $this->tracer->trace($name, function () use ($landingPageId$request$context) {
  82.                 return $this->getDecorated()->load($landingPageId$request$context);
  83.             });
  84.             $item->tag($this->generateTags($landingPageId$response$request$context));
  85.             return CacheValueCompressor::compress($response);
  86.         });
  87.         return CacheValueCompressor::uncompress($value);
  88.     }
  89.     private function generateKey(string $landingPageIdRequest $requestSalesChannelContext $context): ?string
  90.     {
  91.         $parts array_merge(
  92.             $request->query->all(),
  93.             $request->request->all(),
  94.             [$this->generator->getSalesChannelContextHash($context)]
  95.         );
  96.         $event = new LandingPageRouteCacheKeyEvent($landingPageId$parts$request$contextnull);
  97.         $this->dispatcher->dispatch($event);
  98.         if (!$event->shouldCache()) {
  99.             return null;
  100.         }
  101.         return self::buildName($landingPageId) . '-' md5(JsonFieldSerializer::encodeJson($event->getParts()));
  102.     }
  103.     /**
  104.      * @return array<string>
  105.      */
  106.     private function generateTags(string $landingPageIdLandingPageRouteResponse $responseRequest $requestSalesChannelContext $context): array
  107.     {
  108.         $tags array_merge(
  109.             $this->tracer->get(self::buildName($landingPageId)),
  110.             $this->extractIds($response),
  111.             [self::buildName($landingPageId)]
  112.         );
  113.         $event = new LandingPageRouteCacheTagsEvent($landingPageId$tags$request$response$contextnull);
  114.         $this->dispatcher->dispatch($event);
  115.         return array_unique(array_filter($event->getTags()));
  116.     }
  117.     /**
  118.      * @return array<string>
  119.      */
  120.     private function extractIds(LandingPageRouteResponse $response): array
  121.     {
  122.         $page $response->getLandingPage()->getCmsPage();
  123.         if ($page === null) {
  124.             return [];
  125.         }
  126.         $ids = [];
  127.         $slots $page->getElementsOfType('product-slider');
  128.         /** @var CmsSlotEntity $slot */
  129.         foreach ($slots as $slot) {
  130.             $slider $slot->getData();
  131.             if (!$slider instanceof ProductSliderStruct) {
  132.                 continue;
  133.             }
  134.             if ($slider->getProducts() === null) {
  135.                 continue;
  136.             }
  137.             foreach ($slider->getProducts() as $product) {
  138.                 $ids[] = $product->getId();
  139.                 $ids[] = $product->getParentId();
  140.             }
  141.         }
  142.         $slots $page->getElementsOfType('product-box');
  143.         /** @var CmsSlotEntity $slot */
  144.         foreach ($slots as $slot) {
  145.             $box $slot->getData();
  146.             if (!$box instanceof ProductBoxStruct) {
  147.                 continue;
  148.             }
  149.             if ($box->getProduct() === null) {
  150.                 continue;
  151.             }
  152.             $ids[] = $box->getProduct()->getId();
  153.             $ids[] = $box->getProduct()->getParentId();
  154.         }
  155.         $ids array_values(array_unique(array_filter($ids)));
  156.         return array_merge(
  157.             array_map([EntityCacheKeyGenerator::class, 'buildProductTag'], $ids),
  158.             [EntityCacheKeyGenerator::buildCmsTag($page->getId())]
  159.         );
  160.     }
  161. }