vendor/shopware/core/Content/Product/SalesChannel/Review/CachedProductReviewRoute.php line 85

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Product\SalesChannel\Review;
  3. use Shopware\Core\Content\Product\Events\ProductDetailRouteCacheKeyEvent;
  4. use Shopware\Core\Content\Product\Events\ProductDetailRouteCacheTagsEvent;
  5. use Shopware\Core\Framework\Adapter\Cache\AbstractCacheTracer;
  6. use Shopware\Core\Framework\Adapter\Cache\CacheStateSubscriber;
  7. use Shopware\Core\Framework\Adapter\Cache\CacheValueCompressor;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Cache\EntityCacheKeyGenerator;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\RuleAreas;
  10. use Shopware\Core\Framework\DataAbstractionLayer\FieldSerializer\JsonFieldSerializer;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\Log\Package;
  13. use Shopware\Core\Framework\Routing\Annotation\Entity;
  14. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  15. use Shopware\Core\Framework\Routing\Annotation\Since;
  16. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. use Symfony\Contracts\Cache\CacheInterface;
  20. use Symfony\Contracts\Cache\ItemInterface;
  21. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  22. /**
  23.  * @Route(defaults={"_routeScope"={"store-api"}})
  24.  */
  25. #[Package('inventory')]
  26. class CachedProductReviewRoute extends AbstractProductReviewRoute
  27. {
  28.     public const ALL_TAG 'product-review-route';
  29.     private AbstractProductReviewRoute $decorated;
  30.     private CacheInterface $cache;
  31.     private EntityCacheKeyGenerator $generator;
  32.     /**
  33.      * @var AbstractCacheTracer<ProductReviewRouteResponse>
  34.      */
  35.     private AbstractCacheTracer $tracer;
  36.     /**
  37.      * @var string[]
  38.      */
  39.     private array $states;
  40.     private EventDispatcherInterface $dispatcher;
  41.     /**
  42.      * @internal
  43.      *
  44.      * @param AbstractCacheTracer<ProductReviewRouteResponse> $tracer
  45.      * @param string[] $states
  46.      */
  47.     public function __construct(
  48.         AbstractProductReviewRoute $decorated,
  49.         CacheInterface $cache,
  50.         EntityCacheKeyGenerator $generator,
  51.         AbstractCacheTracer $tracer,
  52.         EventDispatcherInterface $dispatcher,
  53.         array $states
  54.     ) {
  55.         $this->decorated $decorated;
  56.         $this->cache $cache;
  57.         $this->generator $generator;
  58.         $this->tracer $tracer;
  59.         $states[] = CacheStateSubscriber::STATE_LOGGED_IN;
  60.         $this->states array_unique($states);
  61.         $this->dispatcher $dispatcher;
  62.     }
  63.     public function getDecorated(): AbstractProductReviewRoute
  64.     {
  65.         return $this->decorated;
  66.     }
  67.     /**
  68.      * @Since("6.3.2.0")
  69.      * @Entity("product_review")
  70.      * @Route("/store-api/product/{productId}/reviews", name="store-api.product-review.list", methods={"POST"})
  71.      */
  72.     public function load(string $productIdRequest $requestSalesChannelContext $contextCriteria $criteria): ProductReviewRouteResponse
  73.     {
  74.         if ($context->hasState(...$this->states)) {
  75.             return $this->getDecorated()->load($productId$request$context$criteria);
  76.         }
  77.         $key $this->generateKey($productId$request$context$criteria);
  78.         $value $this->cache->get($key, function (ItemInterface $item) use ($productId$request$context$criteria) {
  79.             $name self::buildName($productId);
  80.             $response $this->tracer->trace($name, function () use ($productId$request$context$criteria) {
  81.                 return $this->getDecorated()->load($productId$request$context$criteria);
  82.             });
  83.             $item->tag($this->generateTags($productId$request$response$context$criteria));
  84.             return CacheValueCompressor::compress($response);
  85.         });
  86.         return CacheValueCompressor::uncompress($value);
  87.     }
  88.     public static function buildName(string $productId): string
  89.     {
  90.         return 'product-review-route-' $productId;
  91.     }
  92.     private function generateKey(string $productIdRequest $requestSalesChannelContext $contextCriteria $criteria): string
  93.     {
  94.         $parts = [
  95.             $this->generator->getCriteriaHash($criteria),
  96.             $this->generator->getSalesChannelContextHash($context, [RuleAreas::PRODUCT_AREA]),
  97.         ];
  98.         $event = new ProductDetailRouteCacheKeyEvent($parts$request$context$criteria);
  99.         $this->dispatcher->dispatch($event);
  100.         return self::buildName($productId) . '-' md5(JsonFieldSerializer::encodeJson($event->getParts()));
  101.     }
  102.     /**
  103.      * @return string[]
  104.      */
  105.     private function generateTags(string $productIdRequest $requestProductReviewRouteResponse $responseSalesChannelContext $contextCriteria $criteria): array
  106.     {
  107.         $tags array_merge(
  108.             $this->tracer->get(self::buildName($productId)),
  109.             [self::buildName($productId)]
  110.         );
  111.         $event = new ProductDetailRouteCacheTagsEvent($tags$request$response$context$criteria);
  112.         $this->dispatcher->dispatch($event);
  113.         return array_unique(array_filter($event->getTags()));
  114.     }
  115. }