custom/static-plugins/CogiFreeProductQuantity/src/Subscriber/FreeProductQuantitySubscriber.php line 85

Open in your IDE?
  1. <?php
  2. namespace Cogi\CogiFreeProductQuantity\Subscriber;
  3. use Shopware\Core\Checkout\Cart\Order\OrderConvertedEvent;
  4. use Shopware\Core\Checkout\Cart\Price\QuantityPriceCalculator;
  5. use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
  6. use Shopware\Core\Checkout\Cart\Price\Struct\QuantityPriceDefinition;
  7. use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTaxCollection;
  8. use Shopware\Core\Checkout\Cart\Tax\Struct\TaxRuleCollection;
  9. use Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice\CalculatedCheapestPrice;
  10. use Shopware\Core\Content\Product\ProductCollection;
  11. use Shopware\Core\Content\Product\ProductEntity;
  12. use Shopware\Core\Content\Product\SalesChannel\Detail\AbstractProductDetailRoute;
  13. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  14. use Shopware\Core\Content\ProductStream\Service\ProductStreamBuilderInterface;
  15. use Shopware\Core\Framework\Context;
  16. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  21. use Shopware\Core\Framework\Struct\ArrayEntity;
  22. use Shopware\Core\Framework\Struct\ArrayStruct;
  23. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  24. use Shopware\Core\System\SystemConfig\SystemConfigService;
  25. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
  26. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
  27. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  28. use Symfony\Component\HttpFoundation\Request;
  29. class FreeProductQuantitySubscriber implements EventSubscriberInterface
  30. {
  31.     private ProductStreamBuilderInterface $productStreamBuilder;
  32.     /**
  33.      * @var EntityRepositoryInterface
  34.      */
  35.     private $productRepository;
  36.     /**
  37.      * @var EntityRepositoryInterface
  38.      */
  39.     private $productStreamRepository;
  40.     /**
  41.      * @var AbstractProductDetailRoute
  42.      */
  43.     private $productDetailRoute;
  44.     /**
  45.      * @var QuantityPriceCalculator
  46.      */
  47.     private $calculator;
  48.     /**
  49.      * @var SystemConfigService
  50.      */
  51.     private $systemConfigService;
  52.     public function __construct(
  53.         ProductStreamBuilderInterface $productStreamBuilder,
  54.         EntityRepositoryInterface $productRepository,
  55.         EntityRepositoryInterface $productStreamRepository,
  56.         AbstractProductDetailRoute $productDetailRoute,
  57.         QuantityPriceCalculator $calculator,
  58.         SystemConfigService $systemConfigService
  59.     ) {
  60.         $this->productStreamBuilder $productStreamBuilder;
  61.         $this->productRepository $productRepository;
  62.         $this->productStreamRepository $productStreamRepository;
  63.         $this->productDetailRoute $productDetailRoute;
  64.         $this->calculator $calculator;
  65.         $this->systemConfigService $systemConfigService;
  66.     }
  67.     public static function getSubscribedEvents(): array
  68.     {
  69.         return [
  70.             CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoadedEvent',
  71.             CheckoutCartPageLoadedEvent::class => 'onCheckoutCartPageLoadedEvent'
  72.         ];
  73.     }
  74.     public function onCheckoutCartPageLoadedEvent(CheckoutCartPageLoadedEvent $event): void
  75.     {
  76.         $active =  $this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityActive'$event->getSalesChannelContext()->getSalesChannelId());
  77.         $checkCustomerGroup false;
  78.         if(empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()))) {
  79.             $checkCustomerGroup true;
  80.         }
  81.         if(!empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()))) {
  82.             if(!empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()) && !empty($event->getSalesChannelContext()->getCustomer()))) {
  83.                 foreach ($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()) as $customerGroupId) {
  84.                     if ($event->getSalesChannelContext()->getCustomer()->getGroupId() == $customerGroupId) {
  85.                         $checkCustomerGroup true;
  86.                     }
  87.                 }
  88.             }
  89.         }
  90.         if($active && $checkCustomerGroup) {
  91.             if($event->getRequest()->get('page')) {
  92.                 $page $event->getRequest()->get('page');
  93.             } else {
  94.                 $page 1;
  95.             }
  96.             $freeProductRule $this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantitySelect'$event->getSalesChannelContext()->getSalesChannelId());
  97.             if(!empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityStreamFree'$event->getSalesChannelContext()->getSalesChannelId()))) {
  98.                 $productStreamId $this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityStreamFree'$event->getSalesChannelContext()->getSalesChannelId());
  99.             } else {
  100.                 return;
  101.             }
  102.             $total $this->getFreeProductTotal($productStreamId$event->getSalesChannelContext(), $event->getRequest());
  103.             $limit 8;
  104.             $maxPages ceil($total $limit);
  105.             if($maxPages 1) {
  106.                 $maxPages 1;
  107.             }
  108.             $prevPage true;
  109.             $nextPage true;
  110.             if($page 2) {
  111.                 $prevPage false;
  112.             }
  113.             if($page >= $maxPages) {
  114.                 $nextPage false;
  115.             }
  116.             $products $this->getProductStreamCollection($productStreamId$event->getSalesChannelContext(), $page$limit$event->getRequest());
  117.             $freeProductCollection = [];
  118.             /** @var ProductEntity $product */
  119.             foreach($products as $product) {
  120.                 /** @var SalesChannelProductEntity $salesChannelProduct */
  121.                 $salesChannelProduct $this->createFreeProduct($product$event->getSalesChannelContext());
  122.                 array_push($freeProductCollection$salesChannelProduct);
  123.             }
  124.             $event->getPage()->addExtension('FreeProduct', new ArrayStruct([
  125.                 'total' => $total,
  126.                 'maxPages' => $maxPages,
  127.                 'activePage' => $page,
  128.                 'nextPage' => $nextPage,
  129.                 'prevPage' => $prevPage,
  130.             ]));
  131.             $event->getPage()->getCart()->setExtensions(["FreeProducts" => $freeProductCollection"freeProductRules" => new ArrayStruct($freeProductRule)]);
  132.         }
  133.     }
  134.     public function onCheckoutConfirmPageLoadedEvent(CheckoutConfirmPageLoadedEvent $event): void
  135.     {
  136.         $active $this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityActive'$event->getSalesChannelContext()->getSalesChannelId());
  137.         $checkCustomerGroup false;
  138.         if(!$event->getSalesChannelContext()->getCustomer()) {
  139.             return;
  140.         }
  141.         if(empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()))) {
  142.             $checkCustomerGroup true;
  143.         }
  144.         if(!empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()))) {
  145.             if(!empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()) && !empty($event->getSalesChannelContext()->getCustomer()))) {
  146.                 foreach ($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityCustomerGroupIds'$event->getSalesChannelContext()->getSalesChannelId()) as $customerGroupId) {
  147.                     if ($event->getSalesChannelContext()->getCustomer()->getGroupId() == $customerGroupId) {
  148.                         $checkCustomerGroup true;
  149.                     }
  150.                 }
  151.             }
  152.         }
  153.         if($active && $checkCustomerGroup) {
  154.             if($event->getRequest()->get('page')) {
  155.                 $page $event->getRequest()->get('page');
  156.             } else {
  157.                 $page 1;
  158.             }
  159.             $freeProductRule $this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantitySelect'$event->getSalesChannelContext()->getSalesChannelId());
  160.             if(!empty($this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityStreamFree'$event->getSalesChannelContext()->getSalesChannelId()))) {
  161.                 $productStreamId $this->systemConfigService->get('CogiFreeProductQuantity.config.cogiFreeProductQuantityStreamFree'$event->getSalesChannelContext()->getSalesChannelId());
  162.             } else {
  163.                 return;
  164.             }
  165.             $total $this->getFreeProductTotal($productStreamId$event->getSalesChannelContext(), $event->getRequest());
  166.             $limit 8;
  167.             $maxPages ceil($total $limit);
  168.             if($maxPages 1) {
  169.                 $maxPages 1;
  170.             }
  171.             $prevPage true;
  172.             $nextPage true;
  173.             if($page 2) {
  174.                 $prevPage false;
  175.             }
  176.             if($page >= $maxPages) {
  177.                 $nextPage false;
  178.             }
  179.             $products $this->getProductStreamCollection($productStreamId$event->getSalesChannelContext(), $page$limit$event->getRequest());
  180.             $freeProductCollection = [];
  181.             /** @var ProductEntity $product */
  182.             foreach($products as $product) {
  183.                 /** @var SalesChannelProductEntity $salesChannelProduct */
  184.                 $salesChannelProduct $this->createFreeProduct($product$event->getSalesChannelContext());
  185.                 array_push($freeProductCollection$salesChannelProduct);
  186.             }
  187.             $event->getPage()->addExtension('FreeProduct', new ArrayStruct([
  188.                 'total' => $total,
  189.                 'maxPages' => $maxPages,
  190.                 'activePage' => $page,
  191.                 'nextPage' => $nextPage,
  192.                 'prevPage' => $prevPage,
  193.             ]));
  194.             $event->getPage()->getCart()->setExtensions(["FreeProducts" => $freeProductCollection"freeProductRules" => new ArrayStruct($freeProductRule)]);
  195.         }
  196.     }
  197.     private function getProductStreamCollection(String $productStreamIdSalesChannelContext $contextint $pageint $limitRequest $request): ProductCollection
  198.     {
  199.         $filters $this->productStreamBuilder->buildFilters($productStreamId$context->getContext());
  200.         if($request->get("search")) {
  201.             $searchWord $request->get("search");
  202.             array_push($filters, new MultiFilter(MultiFilter::CONNECTION_OR, [
  203.                 new ContainsFilter("productNumber"$searchWord),
  204.                 new ContainsFilter("name"$searchWord)
  205.             ]));
  206.         }
  207.         $criteria = new Criteria();
  208.         $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND$filters));
  209.         $criteria->setLimit($limit);
  210.         $criteria->addAssociation('visibilities');
  211.         $criteria->addFilter(new EqualsFilter('visibilities.salesChannelId'$context->getSalesChannelId()));
  212.         $criteria->addFilter(new EqualsFilter('active'true));
  213.         $newOffset = ($page 1) * $limit;
  214.         $criteria->setOffset($newOffset);
  215.         /** @var ProductCollection $products */
  216.         $products $this->productRepository->search($criteria$context->getContext())->getEntities();
  217.         return $products;
  218.     }
  219.     private function getFreeProductTotal(String $productStreamIdSalesChannelContext $contextRequest $request): int
  220.     {
  221.         $filters $this->productStreamBuilder->buildFilters($productStreamId$context->getContext());
  222.         if($request->get("search")) {
  223.             $searchWord $request->get("search");
  224.             array_push($filters, new MultiFilter(MultiFilter::CONNECTION_OR, [
  225.                 new ContainsFilter("productNumber"$searchWord),
  226.                 new ContainsFilter("name"$searchWord)
  227.             ]));
  228.         }
  229.         $criteria = new Criteria();
  230.         $criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);
  231.         $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND$filters));
  232.         $criteria->addAssociation('visibilities');
  233.         $criteria->addFilter(new EqualsFilter('visibilities.salesChannelId'$context->getSalesChannelId()));
  234.         $criteria->addFilter(new EqualsFilter('active'true));
  235.         $totalFreeProducts $this->productRepository->searchIds($criteria$context->getContext())->getTotal();
  236.         return $totalFreeProducts;
  237.     }
  238.     public function createFreeProduct(ProductEntity $freeProductSalesChannelContext $context)
  239.     {
  240.         $criteria = new Criteria();
  241.         $criteria->addAssociation('options');
  242.         $criteria->addAssociation('options.group');
  243.         $criteria->addAssociation('media');
  244.         /** @var SalesChannelProductEntity $salesChannelProduktEntity */
  245.         $salesChannelProduktEntity $this->productDetailRoute->load($freeProduct->getId(), new Request(), $context$criteria)->getProduct();
  246.         $calcPrice = new CalculatedPrice(
  247.             0,
  248.             0,
  249.             new CalculatedTaxCollection(),
  250.             new TaxRuleCollection(),
  251.             1
  252.         );
  253.         $quantityPriceDefinition = new QuantityPriceDefinition(0.0, new TaxRuleCollection());
  254.         $cheapest CalculatedCheapestPrice::createFrom(
  255.             $this->calculator->calculate($quantityPriceDefinition$context)
  256.         );
  257.         $cheapest->setHasRange(false);
  258.         $salesChannelProduktEntity->setCalculatedCheapestPrice($cheapest);
  259.         $salesChannelProduktEntity->setCalculatedPrice($calcPrice);
  260.         $salesChannelProduktEntity->addExtension("FreeProductQuantity", new ArrayEntity(["isFreeProductQuantity" => true]));
  261.         return $salesChannelProduktEntity;
  262.     }
  263. }