vendor/shopware/storefront/Page/Product/Review/ProductReviewLoader.php line 56

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Page\Product\Review;
  3. use Shopware\Core\Content\Product\Aggregate\ProductReview\ProductReviewEntity;
  4. use Shopware\Core\Content\Product\SalesChannel\Review\AbstractProductReviewRoute;
  5. use Shopware\Core\Content\Product\SalesChannel\Review\RatingMatrix;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\TermsAggregation;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Bucket\TermsResult;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  14. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  15. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  16. use Shopware\Storefront\Framework\Page\StorefrontSearchResult;
  17. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  18. use Symfony\Component\HttpFoundation\Request;
  19. class ProductReviewLoader
  20. {
  21.     private const LIMIT 10;
  22.     private const DEFAULT_PAGE 1;
  23.     private const FILTER_LANGUAGE 'filter-language';
  24.     /**
  25.      * @var EventDispatcherInterface
  26.      */
  27.     private $eventDispatcher;
  28.     /**
  29.      * @var AbstractProductReviewRoute
  30.      */
  31.     private $route;
  32.     /**
  33.      * @internal
  34.      */
  35.     public function __construct(
  36.         AbstractProductReviewRoute $route,
  37.         EventDispatcherInterface $eventDispatcher
  38.     ) {
  39.         $this->eventDispatcher $eventDispatcher;
  40.         $this->route $route;
  41.     }
  42.     /**
  43.      * load reviews for one product. The request must contain the productId
  44.      * otherwise MissingRequestParameterException is thrown
  45.      *
  46.      * @throws MissingRequestParameterException
  47.      * @throws \Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException
  48.      */
  49.     public function load(Request $requestSalesChannelContext $context): ReviewLoaderResult
  50.     {
  51.         $productId $request->get('parentId') ?? $request->get('productId');
  52.         if (!$productId) {
  53.             throw new MissingRequestParameterException('productId');
  54.         }
  55.         $criteria $this->createCriteria($request$context);
  56.         $reviews $this->route
  57.             ->load($productId$request$context$criteria)
  58.             ->getResult();
  59.         $reviews StorefrontSearchResult::createFrom($reviews);
  60.         $this->eventDispatcher->dispatch(new ProductReviewsLoadedEvent($reviews$context$request));
  61.         $reviewResult ReviewLoaderResult::createFrom($reviews);
  62.         $reviewResult->setProductId($request->get('productId'));
  63.         $reviewResult->setParentId($request->get('parentId'));
  64.         $aggregation $reviews->getAggregations()->get('ratingMatrix');
  65.         $matrix = new RatingMatrix([]);
  66.         if ($aggregation instanceof TermsResult) {
  67.             $matrix = new RatingMatrix($aggregation->getBuckets());
  68.         }
  69.         $reviewResult->setMatrix($matrix);
  70.         $reviewResult->setCustomerReview($this->getCustomerReview($productId$context));
  71.         $reviewResult->setTotalReviews($matrix->getTotalReviewCount());
  72.         return $reviewResult;
  73.     }
  74.     private function createCriteria(Request $requestSalesChannelContext $context): Criteria
  75.     {
  76.         $limit = (int) $request->get('limit'self::LIMIT);
  77.         $page = (int) $request->get('p'self::DEFAULT_PAGE);
  78.         $offset $limit * ($page 1);
  79.         $criteria = new Criteria();
  80.         $criteria->setLimit($limit);
  81.         $criteria->setOffset($offset);
  82.         $criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);
  83.         $sorting = new FieldSorting('createdAt''DESC');
  84.         if ($request->get('sort''createdAt') === 'points') {
  85.             $sorting = new FieldSorting('points''DESC');
  86.         }
  87.         $criteria->addSorting($sorting);
  88.         if ($request->get('language') === self::FILTER_LANGUAGE) {
  89.             $criteria->addPostFilter(
  90.                 new EqualsFilter('languageId'$context->getContext()->getLanguageId())
  91.             );
  92.         }
  93.         $this->handlePointsAggregation($request$criteria$context);
  94.         return $criteria;
  95.     }
  96.     /**
  97.      * get review by productId and customer
  98.      * a customer should only create one review per product, so if there are more than one
  99.      * review we only take one
  100.      *
  101.      * @throws \Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException
  102.      */
  103.     private function getCustomerReview(string $productIdSalesChannelContext $context): ?ProductReviewEntity
  104.     {
  105.         $customer $context->getCustomer();
  106.         if (!$customer) {
  107.             return null;
  108.         }
  109.         $criteria = new Criteria();
  110.         $criteria->setLimit(1);
  111.         $criteria->setOffset(0);
  112.         $criteria->addFilter(new EqualsFilter('customerId'$customer->getId()));
  113.         $customerReviews $this->route
  114.             ->load($productId, new Request(), $context$criteria)
  115.             ->getResult();
  116.         return $customerReviews->first();
  117.     }
  118.     private function handlePointsAggregation(Request $requestCriteria $criteriaSalesChannelContext $context): void
  119.     {
  120.         $points $request->get('points', []);
  121.         if (\is_array($points) && \count($points) > 0) {
  122.             $pointFilter = [];
  123.             foreach ($points as $point) {
  124.                 $pointFilter[] = new RangeFilter('points', [
  125.                     'gte' => $point 0.5,
  126.                     'lt' => $point 0.5,
  127.                 ]);
  128.             }
  129.             $criteria->addPostFilter(new MultiFilter(MultiFilter::CONNECTION_OR$pointFilter));
  130.         }
  131.         $reviewFilters[] = new EqualsFilter('status'true);
  132.         if ($context->getCustomer() !== null) {
  133.             $reviewFilters[] = new EqualsFilter('customerId'$context->getCustomer()->getId());
  134.         }
  135.         $criteria->addAggregation(
  136.             new FilterAggregation(
  137.                 'customer-login-filter',
  138.                 new TermsAggregation('ratingMatrix''points'),
  139.                 [
  140.                     new MultiFilter(MultiFilter::CONNECTION_OR$reviewFilters),
  141.                 ]
  142.             )
  143.         );
  144.     }
  145. }