vendor/dvdw/directory/src/Content/Product/Subscriber/ProductCriteriaSubscriber.php line 59

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace DvdwDirectory\Content\Product\Subscriber;
  3. use Dvdw\Events\Content\DvdwEvent\Struct\DvdwEventContextExtension;
  4. use DvdwDirectory\Content\Product\Service\ProductCountService;
  5. use DvdwDirectory\Content\Product\Struct\FilterByParticipationReader;
  6. use DvdwDirectory\Content\Product\Struct\FilterByHasPromotionStruct;
  7. use DvdwDirectory\Content\Product\Struct\FilterByPaidStruct;
  8. use DvdwDirectory\Content\Product\Struct\ProductListingLimitStruct;
  9. use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
  10. use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
  11. use Shopware\Core\Content\Product\SearchKeyword\ProductSearchTermInterpreter;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\AndFilter;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\OrFilter;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Query\ScoreQuery;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Term\SearchPattern;
  22. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  23. use Shopware\Core\System\SystemConfig\SystemConfigService;
  24. use Shopware\Storefront\Page\Product\ProductPageCriteriaEvent;
  25. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  26. use Symfony\Component\HttpFoundation\Request;
  27. class ProductCriteriaSubscriber implements EventSubscriberInterface
  28. {
  29.     private ProductSearchTermInterpreter $interpreter;
  30.     private ProductCountService $productCountService;
  31.     private SystemConfigService $systemConfigService;
  32.     public function __construct(
  33.         ProductSearchTermInterpreter $interpreter,
  34.         ProductCountService $productCountService,
  35.         SystemConfigService $systemConfigService
  36.     )
  37.     {
  38.         $this->interpreter $interpreter;
  39.         $this->productCountService $productCountService;
  40.         $this->systemConfigService $systemConfigService;
  41.     }
  42.     public static function getSubscribedEvents(): array
  43.     {
  44.         return [
  45.             ProductListingCriteriaEvent::class => 'extendListing',
  46.             ProductSearchCriteriaEvent::class => 'extendListing',
  47.             ProductPageCriteriaEvent::class => 'extendDetail'
  48.         ];
  49.     }
  50.     public function extendListing(ProductListingCriteriaEvent $event): void
  51.     {
  52.         $request $event->getRequest();
  53.         $criteria $event->getCriteria();
  54.         $context $event->getSalesChannelContext();
  55.         $dvdwEventId $this->getDvdwEventId($context);
  56.         $this->addAssociations($criteria);
  57.         $this->handleSearch($request$criteria$context$dvdwEventId);
  58.         $limit $context->getExtension(ProductListingLimitStruct::KEY);
  59.         if ($limit && $limit->getProductListingLimit() > 0) {
  60.             $criteria->setLimit($limit->getProductListingLimit());
  61.         }
  62.         $this->applyRandomPage($request$criteria$context);
  63.         $filterByPaid $context->getExtension(FilterByPaidStruct::KEY);
  64.         if ($filterByPaid && $filterByPaid->isFilterByPaid()) {
  65.             $criteria->addFilter(new OrFilter([
  66.                 new EqualsFilter('product.dvdwParticipations.orderLineItem.dvdwTicket.type''gold'),
  67.                 new EqualsFilter('product.dvdwParticipations.orderLineItem.dvdwTicket.type''silver')
  68.             ]));
  69.             // Add the date filter for August, September, and October of the current year
  70.             $currentYear date('Y');
  71.             $criteria->addFilter(new OrFilter([
  72.                 new RangeFilter('createdAt', [
  73.                     RangeFilter::GTE => $currentYear '-08-01 00:00:00',
  74.                     RangeFilter::LTE => $currentYear '-10-31 23:59:59'
  75.                 ]),
  76.                 new RangeFilter('updatedAt', [
  77.                     RangeFilter::GTE => $currentYear '-08-01 00:00:00',
  78.                     RangeFilter::LTE => $currentYear '-10-31 23:59:59'
  79.                 ])
  80.             ]));
  81.         }
  82.         if ($dvdwEventId === null) {
  83.             return;
  84.         }
  85.         $filterByHasPromotion $context->getExtension(FilterByHasPromotionStruct::KEY);
  86.         if ($filterByHasPromotion && $filterByHasPromotion->isFilterByHasPromotion()) {
  87.             $criteria $this->addPromotionFilter($criteria$dvdwEventId);
  88.         }
  89.         $this->filterParticipations($criteria$dvdwEventId);
  90.         if (!FilterByParticipationReader::isOnlyParticipants($context)) {
  91.             return;
  92.         }
  93.         $criteria->addFilter(
  94.             new EqualsFilter(
  95.                 'dvdwParticipations.dvdwEventId',
  96.                 $dvdwEventId
  97.             )
  98.         );
  99.     }
  100.     public function extendDetail(ProductPageCriteriaEvent $event): void
  101.     {
  102.         $criteria $event->getCriteria();
  103.         $this->addAssociations($criteria);
  104.         $criteria->addAssociations([
  105.             'dvdwPromotions.dvdwPromotionLimitations',
  106.             'dvdwPromotions.media',
  107.             'dvdwProducts.media'
  108.         ]);
  109.         $context $event->getSalesChannelContext();
  110.         $dvdwEventId $this->getDvdwEventId($context);
  111.         if ($dvdwEventId === null) {
  112.             return;
  113.         }
  114.         $this->filterParticipations($criteria$dvdwEventId);
  115.     }
  116.     private function handleSearch(Request $requestCriteria $criteriaSalesChannelContext $context, ?string $dvdwEventId): void
  117.     {
  118.         $search $request->query->get('webshopSearch');
  119.         if ($search !== null) {
  120.             if (is_array($search)) {
  121.                 $term implode(' '$search);
  122.             } else {
  123.                 $term = (string) $search;
  124.             }
  125.             $term trim($term);
  126.             $pattern $this->interpreter->interpret($term$context->getContext());
  127.             foreach ($pattern->getTerms() as $searchTerm) {
  128.                 $criteria->addQuery(
  129.                     new ScoreQuery(
  130.                         new EqualsFilter('product.searchKeywords.keyword'$searchTerm->getTerm()),
  131.                         $searchTerm->getScore(),
  132.                         'product.searchKeywords.ranking'
  133.                     )
  134.                 );
  135.             }
  136.             $criteria->addQuery(
  137.                 new ScoreQuery(
  138.                     new ContainsFilter('product.searchKeywords.keyword'$pattern->getOriginal()->getTerm()),
  139.                     $pattern->getOriginal()->getScore(),
  140.                     'product.searchKeywords.ranking'
  141.                 )
  142.             );
  143.             if ($pattern->getBooleanClause() !== SearchPattern::BOOLEAN_CLAUSE_AND) {
  144.                 $criteria->addFilter(new AndFilter([
  145.                     new EqualsAnyFilter('product.searchKeywords.keyword'array_values($pattern->getAllTerms())),
  146.                     new EqualsFilter('product.searchKeywords.languageId'$context->getContext()->getLanguageId()),
  147.                 ]));
  148.             }
  149.         }
  150.         if (($categoryFilter $request->query->get('categoryFilter')) !== null) {
  151.             $categoryIds explode('|'$categoryFilter);
  152.             $queries = [];
  153.             foreach ($categoryIds as $categoryId) {
  154.                 $queries[] = new ContainsFilter('categoryTree'$categoryId);
  155.             }
  156.             $criteria->addFilter(new OrFilter($queries));
  157.         }
  158.         if ($dvdwEventId && $request->query->get('promotionFilter') !== null) {
  159.             $criteria $this->addPromotionFilter($criteria$dvdwEventId);
  160.         }
  161.     }
  162.     private function applyRandomPage(Request $requestCriteria $criteriaSalesChannelContext $context): void
  163.     {
  164.         $limit $criteria->getLimit() ? $criteria->getLimit() : $this->systemConfigService->getInt('core.listing.productsPerPage');
  165.         if ($limit <= 0) {
  166.             $limit 24;
  167.         }
  168.         $page = (int) $request->query->get('p');
  169.         if ($page <= 0) {
  170.             $page $this->getRandomFromTotalPages($limit$request$context);
  171.         }
  172.         $criteria->setLimit($limit);
  173.         $criteria->setOffset($page $limit * ($page 1) : 0);
  174.     }
  175.     private function getRandomFromTotalPages(int $limitRequest $requestSalesChannelContext $context): int
  176.     {
  177.         $total $this->productCountService->getTotal($request$context);
  178.         if ($total <= 0) {
  179.             $total 1;
  180.         }
  181.         return rand(1, (int) ceil($total $limit));
  182.     }
  183.     private function addAssociations(Criteria $criteria): void
  184.     {
  185.         $criteria->addAssociations([
  186.             'dvdwParticipations.orderLineItem.dvdwTicket',
  187.             'categories.media',
  188.             'categories.children'
  189.         ]);
  190.     }
  191.     private function getDvdwEventId(SalesChannelContext $context): ?string
  192.     {
  193.         /** @var DvdwEventContextExtension|null $contextExtension */
  194.         $contextExtension $context->getExtension(DvdwEventContextExtension::KEY);
  195.         if ($contextExtension === null) {
  196.             return null;
  197.         }
  198.         return $contextExtension->getEvent()->getId();
  199.     }
  200.     private function filterParticipations(Criteria $criteriastring $dvdwEventId): void
  201.     {
  202.         $criteria->getAssociation('dvdwParticipations')->addFilter(new EqualsFilter('dvdwEventId'$dvdwEventId));
  203.     }
  204.     private function addPromotionFilter(Criteria $criteriastring $dvdwEventId): Criteria
  205.     {
  206.         $criteria->addFilter(new NotFilter(NotFilter::CONNECTION_OR, [
  207.             new EqualsFilter('product.dvdwParticipations.dvdwPromotion.type''placeholder'),
  208.             new EqualsFilter('product.dvdwParticipations.dvdwPromotion.id'null)
  209.         ]));
  210.         $criteria->addFilter(
  211.             new EqualsFilter('product.dvdwParticipations.dvdwEvent.id'$dvdwEventId)
  212.         );
  213.         return $criteria;
  214.     }
  215. }