Shopware如何通过Criteria添加自定义SQL将指定推广商品前置
解决方案
你可以通过两种合法的Shopware原生方式实现该需求,无需自定义字段也不用硬改SQL逻辑:
方法1:使用ScoreQuery打分排序(更安全,推荐)
利用Shopware DAL内置的打分机制,给需要前置的商品加上足够高的权重分,再优先按权重分排序即可,完全不用拼接原生SQL,无注入风险:
use Shopware\Core\Framework\DataAbstractionLayer\Search\Query\ScoreQuery; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter; use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting; $criteria = $event->getCriteria(); // 你已经拿到的需要前置的商品UUID数组 $promotedProductIds = ['xxx', 'yyy', 'zzz']; // 给指定ID的商品加1000的权重分,保证权重高于所有默认排序规则 $criteria->addQuery( new ScoreQuery( new EqualsAnyFilter('product.id', $promotedProductIds), 1000 ) ); // 调整排序顺序,把权重分排序放在最前面,再追加原有排序规则 $originalSortings = $criteria->getSorting(); $criteria->resetSorting(); // 优先按权重降序,分值高的排在前面 $criteria->addSorting(new FieldSorting('_score', FieldSorting::DESCENDING)); foreach ($originalSortings as $sorting) { $criteria->addSorting($sorting); }
方法2:使用ExpressionSorting插入自定义SQL片段
如果你需要严格按照你传入的ID顺序排列前置商品,可以用ExpressionSorting来插入FIELD函数的SQL片段,注意要做好参数转义避免SQL注入:
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\ExpressionSorting; use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting; $criteria = $event->getCriteria(); $promotedProductIds = ['xxx', 'yyy', 'zzz']; // 转义ID避免SQL注入 $escapedIds = array_map(fn(string $id) => '"' . str_replace('"', '\\"', $id) . '"', $promotedProductIds); $idList = implode(',', $escapedIds); $originalSortings = $criteria->getSorting(); $criteria->resetSorting(); // 插入自定义排序规则,匹配ID的商品按传入顺序排在最前 $criteria->addSorting( new ExpressionSorting( sprintf('FIELD(HEX(product.id), %s)', $idList), FieldSorting::DESCENDING ) ); foreach ($originalSortings as $sorting) { $criteria->addSorting($sorting); }
注意:表达式里要加
product.别名前缀,避免和查询中其他关联表的id字段冲突,使用HEX()函数是因为Shopware底层存储UUID为二进制格式,需要转成十六进制字符串和你拿到的字符串格式ID匹配。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

