vendor/shopware/core/Checkout/Promotion/Subscriber/Storefront/StorefrontCartSubscriber.php line 90

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Checkout\Promotion\Subscriber\Storefront;
  3. use Shopware\Core\Checkout\Cart\Cart;
  4. use Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent;
  5. use Shopware\Core\Checkout\Cart\Event\BeforeLineItemRemovedEvent;
  6. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  7. use Shopware\Core\Checkout\Cart\Exception\LineItemNotFoundException;
  8. use Shopware\Core\Checkout\Cart\Exception\LineItemNotRemovableException;
  9. use Shopware\Core\Checkout\Cart\Exception\PayloadKeyNotFoundException;
  10. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  11. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  12. use Shopware\Core\Checkout\Promotion\Aggregate\PromotionDiscount\PromotionDiscountEntity;
  13. use Shopware\Core\Checkout\Promotion\Cart\Extension\CartExtension;
  14. use Shopware\Core\Checkout\Promotion\Cart\PromotionProcessor;
  15. use Shopware\Core\Framework\Log\Package;
  16. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\HttpFoundation\RequestStack;
  19. /**
  20.  * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  21.  */
  22. #[Package('checkout')]
  23. class StorefrontCartSubscriber implements EventSubscriberInterface
  24. {
  25.     public const SESSION_KEY_PROMOTION_CODES 'cart-promotion-codes';
  26.     private CartService $cartService;
  27.     private RequestStack $requestStack;
  28.     /**
  29.      * @internal
  30.      */
  31.     public function __construct(CartService $cartServiceRequestStack $requestStack)
  32.     {
  33.         $this->cartService $cartService;
  34.         $this->requestStack $requestStack;
  35.     }
  36.     public static function getSubscribedEvents(): array
  37.     {
  38.         return [
  39.             BeforeLineItemAddedEvent::class => 'onLineItemAdded',
  40.             BeforeLineItemRemovedEvent::class => 'onLineItemRemoved',
  41.             CheckoutOrderPlacedEvent::class => 'resetCodes',
  42.         ];
  43.     }
  44.     public function resetCodes(): void
  45.     {
  46.         $mainRequest $this->requestStack->getMainRequest();
  47.         if ($mainRequest === null) {
  48.             return;
  49.         }
  50.         if (!$mainRequest->hasSession()) {
  51.             return;
  52.         }
  53.         $mainRequest->getSession()->set(self::SESSION_KEY_PROMOTION_CODES, []);
  54.     }
  55.     /**
  56.      * This function is called whenever a new line item has been
  57.      * added to the cart from within the controllers.
  58.      * We verify if we have a placeholder line item for a promotion
  59.      * and add that code to our extension list.
  60.      */
  61.     public function onLineItemAdded(BeforeLineItemAddedEvent $event): void
  62.     {
  63.         if ($event->getLineItem()->getType() === PromotionProcessor::LINE_ITEM_TYPE) {
  64.             $code $event->getLineItem()->getReferencedId();
  65.             if ($code !== null && $code !== '') {
  66.                 $this->addCode($code$event->getCart());
  67.             }
  68.         }
  69.     }
  70.     /**
  71.      * This function is called whenever a line item is being removed
  72.      * from the cart from within a controller.
  73.      * We verify if it is a promotion item, and also remove that
  74.      * code from our extension, if existing.
  75.      */
  76.     public function onLineItemRemoved(BeforeLineItemRemovedEvent $event): void
  77.     {
  78.         $cart $event->getCart();
  79.         if ($event->getLineItem()->getType() !== PromotionProcessor::LINE_ITEM_TYPE) {
  80.             return;
  81.         }
  82.         $lineItem $event->getLineItem();
  83.         $code $lineItem->getReferencedId();
  84.         if (!empty($code)) {
  85.             // promotion with code
  86.             $this->checkFixedDiscountItems($cart$lineItem);
  87.             //remove other discounts of the promotion that should be deleted
  88.             $this->removeOtherDiscountsOfPromotion($cart$lineItem$event->getSalesChannelContext());
  89.             $this->removeCode($code$cart);
  90.             return;
  91.         }
  92.         // the user wants to remove an automatic added
  93.         // promotions, so lets do this
  94.         if ($lineItem->hasPayloadValue('promotionId')) {
  95.             $promotionId = (string) $lineItem->getPayloadValue('promotionId');
  96.             $this->blockPromotion($promotionId$cart);
  97.         }
  98.     }
  99.     /**
  100.      * @throws LineItemNotFoundException
  101.      * @throws LineItemNotRemovableException
  102.      * @throws PayloadKeyNotFoundException
  103.      */
  104.     private function checkFixedDiscountItems(Cart $cartLineItem $lineItem): void
  105.     {
  106.         $lineItems $cart->getLineItems()->filterType(PromotionProcessor::LINE_ITEM_TYPE);
  107.         if ($lineItems->count() < 1) {
  108.             return;
  109.         }
  110.         if (!$lineItem->hasPayloadValue('discountType')) {
  111.             return;
  112.         }
  113.         if ($lineItem->getPayloadValue('discountType') !== PromotionDiscountEntity::TYPE_FIXED_UNIT) {
  114.             return;
  115.         }
  116.         if (!$lineItem->hasPayloadValue('discountId')) {
  117.             return;
  118.         }
  119.         $discountId $lineItem->getPayloadValue('discountId');
  120.         $removeThisDiscounts $lineItems->filter(static function (LineItem $lineItem) use ($discountId) {
  121.             return $lineItem->hasPayloadValue('discountId') && $lineItem->getPayloadValue('discountId') === $discountId;
  122.         });
  123.         foreach ($removeThisDiscounts as $discountItem) {
  124.             $cart->remove($discountItem->getId());
  125.         }
  126.     }
  127.     private function removeOtherDiscountsOfPromotion(Cart $cartLineItem $lineItemSalesChannelContext $context): void
  128.     {
  129.         // ge all promotions from cart
  130.         $lineItems $cart->getLineItems()->filterType(PromotionProcessor::LINE_ITEM_TYPE);
  131.         if ($lineItems->count() < 1) {
  132.             return;
  133.         }
  134.         //filter them by the promotion which discounts should be deleted
  135.         $lineItems $lineItems->filter(function (LineItem $promotionLineItem) use ($lineItem) {
  136.             return $promotionLineItem->getPayloadValue('promotionId') === $lineItem->getPayloadValue('promotionId');
  137.         });
  138.         if ($lineItems->count() < 1) {
  139.             return;
  140.         }
  141.         $promotionLineItem $lineItems->first();
  142.         if ($promotionLineItem instanceof LineItem) {
  143.             // this is recursive because we are listening on LineItemRemovedEvent, it will stop if there
  144.             // are no discounts in the cart, that belong to the promotion that should be deleted
  145.             $this->cartService->remove($cart$promotionLineItem->getId(), $context);
  146.         }
  147.     }
  148.     private function addCode(string $codeCart $cart): void
  149.     {
  150.         $extension $this->getExtension($cart);
  151.         $extension->addCode($code);
  152.         $cart->addExtension(CartExtension::KEY$extension);
  153.     }
  154.     private function removeCode(string $codeCart $cart): void
  155.     {
  156.         $extension $this->getExtension($cart);
  157.         $extension->removeCode($code);
  158.         $cart->addExtension(CartExtension::KEY$extension);
  159.     }
  160.     private function blockPromotion(string $idCart $cart): void
  161.     {
  162.         $extension $this->getExtension($cart);
  163.         $extension->blockPromotion($id);
  164.         $cart->addExtension(CartExtension::KEY$extension);
  165.     }
  166.     private function getExtension(Cart $cart): CartExtension
  167.     {
  168.         if (!$cart->hasExtension(CartExtension::KEY)) {
  169.             $cart->addExtension(CartExtension::KEY, new CartExtension());
  170.         }
  171.         /** @var CartExtension $extension */
  172.         $extension $cart->getExtension(CartExtension::KEY);
  173.         return $extension;
  174.     }
  175. }