如何在Shopware中实现商品列表按参考价格排序?
Shopware商品列表页按实时计算的参考价格排序方案
核心思路
因为参考价格是实时计算的(含税价格 / 销售单位),无法直接使用数据库字段排序,需要通过自定义DQL表达式或者扩展商品查询构建器注入计算逻辑来实现。
具体实现步骤
1. 创建自定义排序选项
先按照官方流程注册自定义排序,setFields留空,后续通过事件替换排序逻辑:
// 在插件的Migration或排序注册类中 $sorting = new ProductSortingEntity(); $sorting->setKey('reference_price_asc'); $sorting->setLabel('按参考价格升序'); $sorting->setActive(true); $sorting->setFields(''); // 留空,后续通过事件处理 $this->productSortingRepository->create([$sorting], Context::createDefaultContext()); // 同时注册降序排序 $sortingDesc = new ProductSortingEntity(); $sortingDesc->setKey('reference_price_desc'); $sortingDesc->setLabel('按参考价格降序'); $sortingDesc->setActive(true); $sortingDesc->setFields(''); $this->productSortingRepository->create([$sortingDesc], Context::createDefaultContext());
2. 监听商品列表查询事件
通过ProductListingCriteriaEvent事件修改查询的排序逻辑,注入实时计算表达式:
// 事件订阅类 use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Shopware\Core\Framework\DataAbstractionLayer\Sorting\FieldSorting; class ReferencePriceSortingSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ ProductListingCriteriaEvent::class => 'onProductListingCriteria' ]; } public function onProductListingCriteria(ProductListingCriteriaEvent $event): void { $criteria = $event->getCriteria(); $sorting = $criteria->getSorting()[0] ?? null; // 判断当前是否使用自定义的参考价格排序 if (!$sorting || !in_array($sorting->getField(), ['reference_price_asc', 'reference_price_desc'])) { return; } // 移除默认排序规则,添加自定义计算排序 $criteria->resetSorting(); // 构建参考价格计算表达式,用IFNULL处理除数为0的异常 $direction = $sorting->getField() === 'reference_price_asc' ? 'ASC' : 'DESC'; $criteria->addSorting(new FieldSorting( 'IFNULL(product.price / product.packUnit, 0)', $direction, true // 标记为DQL表达式,避免被解析为数据库字段 )); } }
3. 注册事件订阅者
在插件的services.xml中注册订阅类,让Shopware识别这个事件处理器:
<service id="YourPluginNamespace\Subscriber\ReferencePriceSortingSubscriber"> <tag name="kernel.event_subscriber"/> </service>
注意事项
- 若含税价格存储在关联表(如
product_price),需调整表达式为关联字段,例如product_price.gross / product.packUnit - 必须处理销售单位为0的情况,否则会触发SQL除法错误,示例中用
IFNULL将异常值设为0
内容的提问来源于stack exchange,提问作者lubart
相关产品推荐
相关产品推荐

