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

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