phpshopwareshopware6

Shopware6: How to add a product to a cart?


TL;DR: how to create and add a LineItem from an existing product to the cart in a plugin?

I'm trying to write a plugin to add a Product to a cart when it's not in it already, e.g. to always have it in a cart (a fee for Paypal, costing nothing when the billingMethod is not Paypal and otherwise the Paypal fee).

I have a Subscriber listening on AfterLineItemAddedEvent successfully triggering on that event, so no problems there. This is my code:

public function onItemAdded(AfterLineItemAddedEvent $event) {
  //$cart = $event->getCart();
  $cart = $this->cartservice->getCart($event->getCart()->getToken(), $event->getSalesChannelContext());

  if ($cart->getLineItems()->filter(function (LineItem $item) {
      if ($item->getPayload()['productNumber'] === "PP")
        return $item;
      })->count() !== 0)
    return;

  $criteria = new Criteria();
  $criteria->addFilter(new EqualsFilter('productNumber', 'PP'));
  $product = $this->productRepository->search($criteria, $event->getContext())->first();

  $paypalFeeLineItem = (new LineItem('paypalfee', LineItem::PRODUCT_LINE_ITEM_TYPE, $product->getId(), 1))
                       ->setRemovable(false)
                       ->setStackable(false);

  //$cart->add($paypalFeeLineItem);
  //$this->persister->save($cart, $event->getSalesChannelContext());
  $this->cartservice->add($cart, $paypalFeeLineItem, $event->getSalesChannelContext());
}

This leads to an endless loop, since the cartservice->add triggers more AfterLineItemAddedEvents. If I use the commented-out methods (e.g. using a persister with the event-cart, not the cartservice) this does not trigger events, not leading to my product in the cart but my cart in the browser shows "Item added successfully" (the normal product I added) AND "product not found" (probably my PayPalFee attempt) in the top of the cart.

-> I think this means my problem is either that the LineItem is not correctly added, or that it is incorrectly built.

So, how would I do this the correct way?


Solution

  • Solved my own question:

    It was not correctly added, because the underlying product was not activated and made available to the storefront channel. My bad. So it adds the lineitem, but the persister->save() discards the item, but the controller still generates an AfterLineItemAdded event, as it is technically after adding a line item. This leads to the endless loop, as the cart still does not contain the product, trying to build it again, etc etc

    All the methods above worked to add a LineItem into a cart, the error message "Invalid Product" on the cart was the relevant help.