You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shopware6插件开发:如何从已有商品创建并添加LineItem至购物车?

Shopware6插件:从已有商品创建LineItem并添加至购物车的正确实现

核心问题分析

  • 无限循环:调用CartService->add会再次触发AfterLineItemAddedEvent,导致代码反复执行。
  • 商品未找到:直接通过LineItem构造函数创建商品类型条目,缺少销售渠道关联、商品价格等必要元数据,购物车持久化时无法识别。

解决方案一:事件中添加循环防护(快速修复)

在事件回调里先判断当前触发事件的条目是否为手续费商品,避免循环;同时用ProductLineItemFactory创建符合规范的商品条目:

use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\LineItem\Factory\ProductLineItemFactory;
use Shopware\Core\Checkout\Cart\Event\AfterLineItemAddedEvent;

class YourCartSubscriber
{
    private $cartService;
    private $productRepository;
    private $productLineItemFactory;

    public function __construct(
        \Shopware\Core\Checkout\Cart\CartService $cartService,
        \Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface $productRepository,
        ProductLineItemFactory $productLineItemFactory
    ) {
        $this->cartService = $cartService;
        $this->productRepository = $productRepository;
        $this->productLineItemFactory = $productLineItemFactory;
    }

    public function onItemAdded(AfterLineItemAddedEvent $event): void
    {
        $addedItem = $event->getLineItem();
        // 防护:如果当前添加的是手续费商品,直接返回避免循环
        if ($addedItem->getType() === LineItem::PRODUCT_LINE_ITEM_TYPE 
            && ($addedItem->getPayload()['productNumber'] ?? '') === 'PP') {
            return;
        }

        $cart = $event->getCart();
        // 检查购物车是否已存在手续费商品
        $hasFeeItem = $cart->getLineItems()->filter(function (LineItem $item) {
            return ($item->getPayload()['productNumber'] ?? '') === 'PP';
        })->count() > 0;

        if ($hasFeeItem) {
            return;
        }

        // 查询手续费商品(关联销售渠道确保可用)
        $criteria = new \Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria();
        $criteria->addFilter(new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter('productNumber', 'PP'));
        $criteria->addAssociation('salesChannels');
        $product = $this->productRepository->search($criteria, $event->getSalesChannelContext()->getContext())->first();

        if (!$product) {
            return;
        }

        // 用工厂创建标准商品LineItem
        $feeLineItem = $this->productLineItemFactory->create(
            $product,
            $event->getSalesChannelContext(),
            1,
            'paypalfee'
        );

        $feeLineItem->setRemovable(false)
                    ->setStackable(false);

        // 添加并更新购物车
        $cart->add($feeLineItem);
        $this->cartService->update($cart, $event->getSalesChannelContext());
    }
}

解决方案二:使用CartProcessor(官方推荐)

Shopware推荐通过CartProcessor接口修改购物车,这是更规范的方式,不会触发事件循环:

1. 创建CartProcessor类

use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartProcessorInterface;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\LineItem\Factory\ProductLineItemFactory;
use Shopware\Core\Checkout\Cart\SalesChannel\CartContext;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;

class PayPalFeeCartProcessor implements CartProcessorInterface
{
    private $productRepository;
    private $productLineItemFactory;

    public function __construct(
        EntityRepositoryInterface $productRepository,
        ProductLineItemFactory $productLineItemFactory
    ) {
        $this->productRepository = $productRepository;
        $this->productLineItemFactory = $productLineItemFactory;
    }

    public function process(Cart $cart, CartContext $context): void
    {
        // 检查是否已存在手续费商品
        $hasFeeItem = $cart->getLineItems()->filter(function (LineItem $item) {
            return ($item->getPayload()['productNumber'] ?? '') === 'PP';
        })->count() > 0;

        if ($hasFeeItem) {
            return;
        }

        // 查询手续费商品
        $criteria = new \Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria();
        $criteria->addFilter(new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter('productNumber', 'PP'));
        $product = $this->productRepository->search($criteria, $context->getContext())->first();

        if (!$product) {
            return;
        }

        // 创建商品LineItem
        $feeLineItem = $this->productLineItemFactory->create(
            $product,
            $context->getSalesChannelContext(),
            1,
            'paypalfee'
        );

        $feeLineItem->setRemovable(false)
                    ->setStackable(false);

        // 根据支付方式调整价格(非PayPal时金额设为0)
        $paymentMethodId = $context->getSalesChannelContext()->getPaymentMethod()->getId();
        if ($paymentMethodId !== '你的PayPal支付方式ID') {
            $feeLineItem->setPrice(new \Shopware\Core\Checkout\Cart\Price\Price(0, 0, []));
        }

        $cart->add($feeLineItem);
    }
}

2. 注册CartProcessor

在插件的services.xml中注册服务:

<service id="YourPlugin\Cart\PayPalFeeCartProcessor">
    <argument type="service" id="product.repository"/>
    <argument type="service" id="Shopware\Core\Checkout\Cart\LineItem\Factory\ProductLineItemFactory"/>
    <tag name="shopware.cart.processor" priority="100"/>
</service>

额外注意事项

  • 确保手续费商品PP已关联到当前销售渠道,否则会查询失败。
  • 动态调整价格时,在CartProcessor中处理是最优方案,因为每次购物车计算都会执行逻辑。
  • 不要直接调用CartPersister保存购物车,通过CartService->update处理会自动完成持久化和必要事件触发。

内容的提问来源于stack exchange,提问作者Sistason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 22:17:03