咨询Nested Line Items的PHP代码层面进阶技术信息
Shopware 购物车捆绑包(Nested Line Items)PHP进阶实现指引
核心实现步骤
1. 定义自定义捆绑包订单项类型
直接基于官方的ContainerLineItem扩展,创建专属的捆绑包类型,便于后续识别和处理:
use Shopware\Core\Checkout\Cart\LineItem\ContainerLineItem; class BundleLineItem extends ContainerLineItem { public const TYPE = 'bundle'; public function __construct(string $id, array $childLineItems = []) { parent::__construct(self::TYPE, $id); // 批量添加子产品项到捆绑包 foreach ($childLineItems as $item) { $this->addChild($item); } } }
2. 向购物车添加捆绑包
在业务服务或控制器中,创建捆绑包实例并关联子产品,再加入购物车:
use Shopware\Core\Checkout\Cart\Cart; use Shopware\Core\Checkout\Cart\LineItem\ProductLineItem; public function addBundleToCart(Cart $cart): void { // 初始化子产品订单项 $product1 = new ProductLineItem('prod-1', 'product', 'your-product-uuid-1', 1); $product2 = new ProductLineItem('prod-2', 'product', 'your-product-uuid-2', 1); // 创建捆绑包并设置显示名称 $bundle = new BundleLineItem('custom-bundle-001', [$product1, $product2]); $bundle->setLabel('夏季护肤套装'); // 将捆绑包加入购物车 $cart->add($bundle); }
3. 实现捆绑包整体移除逻辑
通过监听购物车变更事件,确保移除捆绑包时自动清理所有子项:
use Shopware\Core\Checkout\Cart\Event\CartChangedEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class BundleCartSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ CartChangedEvent::class => 'handleBundleRemoval', ]; } public function handleBundleRemoval(CartChangedEvent $event): void { $cart = $event->getCart(); $removedLineItemIds = $cart->getLineItems()->getRemovedIds(); foreach ($removedLineItemIds as $itemId) { $lineItem = $cart->getLineItems()->get($itemId); // 判断是否为自定义捆绑包类型 if ($lineItem instanceof BundleLineItem) { // 遍历移除所有子项 foreach ($lineItem->getChildren() as $childItem) { $cart->getLineItems()->remove($childItem->getId()); } } } } }
4. 订单后台展示捆绑包结构
通过覆盖后台订单详情模板,实现捆绑包的分组展示:
在插件目录下创建src/Resources/views/admin/order/detail/index.html.twig,添加以下内容:
{% block sw_order_detail_items %} {% for lineItem in order.lineItems %} {% if lineItem.type == 'bundle' %} <div class="sw-order-detail-items__bundle-group"> <h3 class="sw-order-detail-items__bundle-title">{{ lineItem.label }}</h3> {% for childItem in lineItem.children %} <div class="sw-order-detail-items__bundle-child"> {{ childItem.label }} × {{ childItem.quantity }} </div> {% endfor %} </div> {% else %} {{ parent() }} {% endif %} {% endfor %} {% endblock %}
注:Shopware默认会持久化ContainerLineItem的子项关联,无需额外处理订单数据存储,只需调整前端展示逻辑即可。
5. 进阶优化点
- 价格自定义:若需要捆绑包专属定价,可通过
CartProcessor修改BundleLineItem的价格,将子项价格设为0避免重复计算 - 库存逻辑:默认子产品库存单独扣减,若需捆绑包整体管控库存,需自定义
StockUpdater实现 - 前端交互:在Storefront购物车页面添加"移除整个捆绑包"按钮,触发对应ID的移除请求,配合后端逻辑完成操作
内容的提问来源于stack exchange,提问作者Jacky Raimond
相关产品推荐
相关产品推荐

