custom/plugins/System4ShopTheme/src/Subscriber/CartCrossSellingSubscriber.php line 33

Open in your IDE?
  1. <?php
  2. namespace System4ShopTheme\Subscriber;
  3. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  4. use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CachedProductCrossSellingRoute;
  5. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  6. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  7. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  10. use System4ShopTheme\Struct\ColorVariantCollection;
  11. use System4ShopTheme\Struct\ColorVariantStruct;
  12. class CartCrossSellingSubscriber implements EventSubscriberInterface
  13. {
  14.     private CachedProductCrossSellingRoute $crossSellingLoader;
  15.     private EntityRepository $productRepository;
  16.     public function __construct(CachedProductCrossSellingRoute $crossSellingLoaderEntityRepository $productRepository)
  17.     {
  18.         $this->crossSellingLoader $crossSellingLoader;
  19.         $this->productRepository $productRepository;
  20.     }
  21.     public static function getSubscribedEvents(): array
  22.     {
  23.         return [
  24.             CheckoutCartPageLoadedEvent::class => 'onCartPageLoaded',
  25.         ];
  26.     }
  27.     public function onCartPageLoaded(CheckoutCartPageLoadedEvent $event): void
  28.     {
  29.         $cart $event->getPage()->getCart();
  30.         $salesChannelContext $event->getSalesChannelContext();
  31.         $hasProducts $cart->getLineItems()->filterType(LineItem::PRODUCT_LINE_ITEM_TYPE)->count() > 0;
  32.         if ($hasProducts) {
  33.             $products $cart->getLineItems()->filterType(LineItem::PRODUCT_LINE_ITEM_TYPE)->getElements();
  34.             $reversedItems array_reverse($products);
  35.             foreach ($reversedItems as $item) {
  36.                 $productId $item->getReferencedId();
  37.                 $crossSellings $this->crossSellingLoader
  38.                     ->load($productId, new Request(), $salesChannelContext, new Criteria())
  39.                     ->getResult();
  40.                 if ($crossSellings->count() > 0) {
  41.                     break;
  42.                 }
  43.             }
  44.             if ($crossSellings->count()) {
  45.                 $crossSellingProducts $crossSellings->first()?->getProducts();
  46.                 if ($crossSellingProducts) {
  47.                     $limitedProducts $crossSellingProducts->slice(04);
  48.                     foreach ($limitedProducts as $product) {
  49.                         $criteria = new Criteria([$product->getParentId()]);
  50.                         $criteria->addAssociation('options.group')
  51.                                   ->addAssociation('children')
  52.                                   ->addAssociation('children.options.group')
  53.                                   ->addAssociation('children.seoUrls');
  54.                         $parentProduct $this->productRepository->search(
  55.                             $criteria,
  56.                             $event->getSalesChannelContext()->getContext()
  57.                         )->first();
  58.                         if (!$parentProduct) {
  59.                             continue;
  60.                         }
  61.                         $colorVariants $this->getColorVariants($parentProduct);
  62.                         $product->addExtension('colorVariants'$colorVariants);
  63.                     }
  64.                     $event->getPage()->addExtension('cartCrossSellings'$limitedProducts);
  65.                 }
  66.             }
  67.         }
  68.     }
  69.     private function getColorVariants($parentProduct): ColorVariantCollection
  70.     {
  71.         $colorVariants = new ColorVariantCollection();
  72.         $children $parentProduct->getChildren();
  73.         $processedColors = []; // Track processed colors
  74.         if (!$children) {
  75.             return $colorVariants;
  76.         }
  77.         foreach ($children as $variant) {
  78.             $options $variant->getOptions();
  79.             if (!$options) {
  80.                 continue;
  81.             }
  82.             foreach ($options as $option) {
  83.                 $group $option->getGroup();
  84.                 if (!$group) {
  85.                     continue;
  86.                 }
  87.                 if (
  88.                     ($group->getDisplayType() === 'color' ||
  89.                     strtolower($group->getTranslation('name')) === 'color')
  90.                     && $variant->getAvailable() && $variant->getActive() // Only add available variants
  91.                 ) {
  92.                     // Create unique key based on color name and hex code
  93.                     $colorKey $option->getName() . '-' $option->getColorHexCode();
  94.                     // Skip if we've already processed this color
  95.                     if (isset($processedColors[$colorKey])) {
  96.                         continue;
  97.                     }
  98.                     $colorVariants->add(new ColorVariantStruct(
  99.                         $variant->getId(),
  100.                         $option->getTranslation('name'),
  101.                         $option->getColorHexCode(),
  102.                         $variant->getAvailable(),
  103.                         $variant->getStock()
  104.                     ));
  105.                     // Mark this color as processed
  106.                     $processedColors[$colorKey] = true;
  107.                 }
  108.             }
  109.         }
  110.         return $colorVariants;
  111.     }
  112. }