custom/plugins/WbfkExpertRating/src/CmsElementResolver/ProductReviewsCmsElementResolver.php line 86

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