vendor/shopware/core/Content/Product/Cms/ProductDescriptionReviewsCmsElementResolver.php line 77

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Product\Cms;
  3. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
  4. use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
  5. use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
  6. use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
  7. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductDescriptionReviewsStruct;
  8. use Shopware\Core\Content\Product\Aggregate\ProductReview\ProductReviewEntity;
  9. use Shopware\Core\Content\Product\SalesChannel\Review\AbstractProductReviewRoute;
  10. use Shopware\Core\Content\Product\SalesChannel\Review\ProductReviewResult;
  11. use Shopware\Core\Content\Product\SalesChannel\Review\RatingMatrix;
  12. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\TermsAggregation;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Bucket\TermsResult;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  22. use Shopware\Core\Framework\Log\Package;
  23. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  24. use Symfony\Component\HttpFoundation\Request;
  25. #[Package('inventory')]
  26. class ProductDescriptionReviewsCmsElementResolver extends AbstractProductDetailCmsElementResolver
  27. {
  28.     private const LIMIT 10;
  29.     private const DEFAULT_PAGE 1;
  30.     private const FILTER_LANGUAGE 'filter-language';
  31.     private AbstractProductReviewRoute $productReviewRoute;
  32.     /**
  33.      * @internal
  34.      */
  35.     public function __construct(AbstractProductReviewRoute $productReviewRoute)
  36.     {
  37.         $this->productReviewRoute $productReviewRoute;
  38.     }
  39.     public function getType(): string
  40.     {
  41.         return 'product-description-reviews';
  42.     }
  43.     public function enrich(CmsSlotEntity $slotResolverContext $resolverContextElementDataCollection $result): void
  44.     {
  45.         $data = new ProductDescriptionReviewsStruct();
  46.         $slot->setData($data);
  47.         $productConfig $slot->getFieldConfig()->get('product');
  48.         if ($productConfig === null) {
  49.             return;
  50.         }
  51.         $request $resolverContext->getRequest();
  52.         $ratingSuccess = (bool) $request->get('success'false);
  53.         $data->setRatingSuccess($ratingSuccess);
  54.         $product null;
  55.         if ($productConfig->isMapped() && $resolverContext instanceof EntityResolverContext) {
  56.             $product $this->resolveEntityValue($resolverContext->getEntity(), $productConfig->getStringValue());
  57.         }
  58.         if ($productConfig->isStatic()) {
  59.             $product $this->getSlotProduct($slot$result$productConfig->getStringValue());
  60.         }
  61.         /** @var SalesChannelProductEntity|null $product */
  62.         if ($product !== null) {
  63.             $data->setProduct($product);
  64.             $data->setReviews($this->loadProductReviews($product$request$resolverContext->getSalesChannelContext()));
  65.         }
  66.     }
  67.     private function loadProductReviews(SalesChannelProductEntity $productRequest $requestSalesChannelContext $context): ProductReviewResult
  68.     {
  69.         $reviewCriteria $this->createReviewCriteria($request$context);
  70.         $reviews $this->productReviewRoute
  71.             ->load($product->getParentId() ?? $product->getId(), $request$context$reviewCriteria)
  72.             ->getResult();
  73.         $matrix $this->getReviewRatingMatrix($reviews);
  74.         $reviewResult ProductReviewResult::createFrom($reviews);
  75.         $reviewResult->setMatrix($matrix);
  76.         $reviewResult->setProductId($product->getId());
  77.         $reviewResult->setCustomerReview($this->getCustomerReview($product->getId(), $context));
  78.         $reviewResult->setTotalReviews($matrix->getTotalReviewCount());
  79.         $reviewResult->setProductId($product->getId());
  80.         $reviewResult->setParentId($product->getParentId() ?? $product->getId());
  81.         return $reviewResult;
  82.     }
  83.     private function createReviewCriteria(Request $requestSalesChannelContext $context): Criteria
  84.     {
  85.         $limit = (int) $request->get('limit'self::LIMIT);
  86.         $page = (int) $request->get('p'self::DEFAULT_PAGE);
  87.         $offset $limit * ($page 1);
  88.         $criteria = new Criteria();
  89.         $criteria->setLimit($limit);
  90.         $criteria->setOffset($offset);
  91.         $sorting = new FieldSorting('createdAt''DESC');
  92.         if ($request->get('sort''points') === 'points') {
  93.             $sorting = new FieldSorting('points''DESC');
  94.         }
  95.         $criteria->addSorting($sorting);
  96.         if ($request->get('language') === self::FILTER_LANGUAGE) {
  97.             $criteria->addPostFilter(
  98.                 new EqualsFilter('languageId'$context->getContext()->getLanguageId())
  99.             );
  100.         }
  101.         $this->handlePointsAggregation($request$criteria);
  102.         return $criteria;
  103.     }
  104.     private function handlePointsAggregation(Request $requestCriteria $criteria): void
  105.     {
  106.         $points $request->get('points', []);
  107.         if (\is_array($points) && \count($points) > 0) {
  108.             $pointFilter = [];
  109.             foreach ($points as $point) {
  110.                 $pointFilter[] = new RangeFilter('points', [
  111.                     'gte' => $point 0.5,
  112.                     'lt' => $point 0.5,
  113.                 ]);
  114.             }
  115.             $criteria->addPostFilter(new MultiFilter(MultiFilter::CONNECTION_OR$pointFilter));
  116.         }
  117.         $criteria->addAggregation(
  118.             new FilterAggregation(
  119.                 'status-filter',
  120.                 new TermsAggregation('ratingMatrix''points'),
  121.                 [new EqualsFilter('status'1)]
  122.             )
  123.         );
  124.     }
  125.     private function getCustomerReview(string $productIdSalesChannelContext $context): ?ProductReviewEntity
  126.     {
  127.         $customer $context->getCustomer();
  128.         if (!$customer) {
  129.             return null;
  130.         }
  131.         $criteria = new Criteria();
  132.         $criteria->setLimit(1);
  133.         $criteria->setOffset(0);
  134.         $criteria->addFilter(new EqualsFilter('customerId'$customer->getId()));
  135.         $customerReviews $this->productReviewRoute
  136.             ->load($productId, new Request(), $context$criteria)
  137.             ->getResult();
  138.         return $customerReviews->first();
  139.     }
  140.     private function getReviewRatingMatrix(EntitySearchResult $reviews): RatingMatrix
  141.     {
  142.         $aggregation $reviews->getAggregations()->get('ratingMatrix');
  143.         if ($aggregation instanceof TermsResult) {
  144.             return new RatingMatrix($aggregation->getBuckets());
  145.         }
  146.         return new RatingMatrix([]);
  147.     }
  148. }