custom/plugins/WbfkExtensions/src/Subscriber/MultiPartProductListingSubscriber.php line 29

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace WbfkExtensions\Subscriber;
  4. use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
  5. use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
  6. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
  7. use Shopware\Core\Content\Cms\CmsPageCollection;
  8. use Shopware\Core\Content\Cms\CmsPageEntity;
  9. use Shopware\Core\Content\Cms\Events\CmsPageLoadedEvent;
  10. use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductListingStruct;
  11. use Shopware\Core\Content\Product\ProductCollection;
  12. use Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingResult;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. use WbfkExtensions\Core\Content\Cms\SalesChannel\Struct\ProductPartialListingStruct;
  15. class MultiPartProductListingSubscriber implements EventSubscriberInterface
  16. {
  17.     public static function getSubscribedEvents(): array
  18.     {
  19.         return [
  20.             CmsPageLoadedEvent::class => 'onCmsPageLoadedEvent',
  21.         ];
  22.     }
  23.     public function onCmsPageLoadedEvent(CmsPageLoadedEvent $event): void
  24.     {
  25.         /** @var CmsPageCollection $pageCol */
  26.         $pageColl $event->getResult();
  27.         $pages $pageColl->getElements();
  28.         foreach ($pages as $page) {
  29.             if ($page->getType() === 'product_list') {
  30.                 $this->handleMultipartListingPage($page);
  31.             }
  32.         }
  33.     }
  34.     private function handleMultipartListingPage(CmsPageEntity &$page): void
  35.     {
  36.         /** @var CmsSlotEntity $primaryListingElement */
  37.         $primaryListingElement null;
  38.         /** @var CmsSlotEntity[] $subListingElements */
  39.         $subListingElements = [];
  40.         /** @var CmsSectionEntity $section */
  41.         foreach ($page->getSections()->getElements() as $section) {
  42.             /** @var CmsBlockEntity $block */
  43.             foreach ($section->getBlocks()->getElements() as $block) {
  44.                 /** @var CmsSlotEntity $slotEntity */
  45.                 foreach ($block->getSlots()->getElements() as $slotEntity) {
  46.                     switch ($slotEntity->getType()) {
  47.                         case 'product-listing':
  48.                             $primaryListingElement $slotEntity;
  49.                             break;
  50.                         case 'wbfk-multipart-product-listing':
  51.                             $subListingElements[] = $slotEntity;
  52.                             break;
  53.                     }
  54.                 }
  55.             }
  56.         }
  57.         if ($primaryListingElement && $subListingElements) {
  58.             /** @var ProductListingStruct $prodListData */
  59.             $prodListData $primaryListingElement->getData();
  60.             /** @var ProductListingResult $prodListing */
  61.             $prodListing $prodListData->getListing();
  62.             $addProdListElement = function (CmsSlotEntity $element$start$numProducts null) use (&$prodListing) {
  63.                 $numProductsOnPage $prodListing->getLimit();
  64.                 $numProducts $numProducts ?: $numProductsOnPage;
  65.                 $end $start $numProducts;
  66.                 $partialSearchResult $this->createPartialProdListingFromProdListing($prodListing$start$numProducts);
  67.                 $productListingStruct = new ProductPartialListingStruct();
  68.                 $productListingStruct->setListing($partialSearchResult);
  69.                 $productListingStruct->setHideTopNav($start 0);
  70.                 $productListingStruct->setHideBottomNav($end $numProductsOnPage);
  71.                 $productListingStruct->setStart($start);
  72.                 $productListingStruct->setEnd($end);
  73.                 $element->setData($productListingStruct);
  74.                 // We cannot remove the empty product partial lists because there may be a filter applied.
  75.                 // When the user removes the filter (AJAX), the product partial lists should appear and be populated.
  76.                 // else $this->removeMultiPartElement($element);
  77.             };
  78.             $start 0;
  79.             $previous $primaryListingElement;
  80.             foreach ($subListingElements as $listElement) {
  81.                 $conf $listElement->getConfig();
  82.                 $numProducts $conf && isset($conf['numberProducts']) && isset($conf['numberProducts']['value']) ? (int)$conf['numberProducts']['value'] : 8;
  83.                 $addProdListElement($previous$start$numProducts);
  84.                 $previous $listElement;
  85.                 $start += $numProducts;
  86.             }
  87.             $addProdListElement($previous$start);
  88.         }
  89.     }
  90.     private function createPartialProdListingFromProdListing(ProductListingResult &$prodListingint $startint $numProducts): ProductListingResult
  91.     {
  92.         $partialList array_slice($prodListing->getElements(), $start$numProductstrue);
  93.         $partialCollection = new ProductCollection($partialList);
  94.         $partialSearchResult = new ProductListingResult(
  95.             $prodListing->getEntity(),
  96.             $prodListing->getTotal(),
  97.             $partialCollection,
  98.             $prodListing->getAggregations(),
  99.             $prodListing->getCriteria(),
  100.             $prodListing->getContext()
  101.         );
  102.         $partialSearchResult->setSorting($prodListing->getSorting());
  103.         $partialSearchResult->setAvailableSortings($prodListing->getAvailableSortings());
  104.         $partialSearchResult->setStreamId($prodListing->getStreamId());
  105.         foreach ($prodListing->getCurrentFilters() as $key => $filter) {
  106.             $partialSearchResult->addCurrentFilter($key$filter);
  107.         }
  108.         return $partialSearchResult;
  109.     }
  110.     private function removeMultiPartElement(CmsSlotEntity $toRemove)
  111.     {
  112.         if ($toRemove->getType() !== 'wbfk-multipart-product-listing') {
  113.             return;
  114.         }
  115.         $block $toRemove->getBlock();
  116.         if ($block) {
  117.             $section $block->getSection();
  118.             if ($section && count($block->getSlots()->getElements()) === 1) {
  119.                 // This is the only element in the block, Remove the block from the section,
  120.                 $page $section->getPage();
  121.                 if ($page && count($section->getBlocks()->getElements()) === 1) {
  122.                     // This is the only block in the section, Remove the section from the page,
  123.                     $page->getSections()->remove($section->getUniqueIdentifier());
  124.                 } else {
  125.                     $section->getBlocks()->remove($block->getUniqueIdentifier());
  126.                 }
  127.             } else {
  128.                 $block->getSlots()->remove($toRemove->getUniqueIdentifier());
  129.             }
  130.         }
  131.     }
  132. }