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

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