Shopware 6如何在Criteria中筛选属性选项及后台配置建议
解决Shopware 6属性选项筛选及后台配置规则问题
一、正确筛选/排除属性选项的方法
你当前的错误在于关联和过滤路径不对,Shopware 6中产品的属性选项关联路径是properties.options,而非直接properties.name或options.name。要针对属性选项做过滤,需要调整关联和过滤逻辑:
1. 修正关联与过滤代码
修改onListingCriteria方法中的关联和过滤部分:
public function onListingCriteria(ProductListingCriteriaEvent $event): void { // 关联属性组、属性以及属性选项 $criteria = $event->getCriteria(); $criteria->addAssociation('properties.group'); $criteria->addAssociation('properties.options'); // 新增属性选项关联 $filters = $criteria->getExtension('filters'); if (!$filters instanceof FilterCollection) { return; } $propertyFilter = $filters->get('properties'); if (!$propertyFilter instanceof Filter || !\is_array($propertyFilter->getValues())) { return; } $currentPropertyOptions = $propertyFilter->getValues(); // 当选中指定属性选项ID时,排除目标属性选项 if (in_array('c0d02d1738fd4293a489695787e06b5c', $currentPropertyOptions)) { // 用EqualsFilter针对属性选项ID过滤,比PrefixFilter更精准 $criteria->addFilter( new NotFilter( NotFilter::CONNECTION_OR, [ // 替换成你的目标选项ID new EqualsFilter('properties.options.id', '目标选项ID1'), new EqualsFilter('properties.options.id', '目标选项ID2') ] ) ); } }
关键说明
- 属性选项的正确关联路径是
properties.options,必须显式关联才能过滤 - 用
EqualsFilter针对选项ID过滤比名称更稳定,避免名称变更导致失效 - 如果需要按选项名称过滤,路径应为
properties.options.name,而非product.properties.name
二、实现后台可配置的关联规则
要实现后台可配置的“选中A属性的X选项时,才显示B属性的Y/Z选项”规则,需要做以下几步:
1. 创建后台配置实体
创建一个自定义实体(比如PropertyDependencyRule),存储以下字段:
triggerPropertyOptionId: 触发规则的属性选项ID(用户选中的选项)targetPropertyGroupId: 目标属性组ID(要控制的属性所属组)allowedOptionIds: 允许显示的属性选项ID列表(多选)
2. 生成后台配置界面
通过Shopware的Admin SDK创建自定义模块,在后台添加规则配置页面,让管理员可以选择触发选项、目标属性组以及允许的选项。
3. 修改Subscriber逻辑加载配置
在onListingCriteria方法中,注入自定义实体的Repository,加载所有生效的规则,动态生成过滤条件:
// 注入PropertyDependencyRuleRepository和PropertyGroupRepository private $ruleRepository; private $propertyGroupRepository; public function __construct( PropertyDependencyRuleRepository $ruleRepository, PropertyGroupRepository $propertyGroupRepository ) { $this->ruleRepository = $ruleRepository; $this->propertyGroupRepository = $propertyGroupRepository; } public function onListingCriteria(ProductListingCriteriaEvent $event): void { $criteria = $event->getCriteria(); $criteria->addAssociation('properties.group'); $criteria->addAssociation('properties.options'); $filters = $criteria->getExtension('filters'); if (!$filters instanceof FilterCollection) { return; } $propertyFilter = $filters->get('properties'); if (!$propertyFilter instanceof Filter || !\is_array($propertyFilter->getValues())) { return; } $currentSelectedOptionIds = $propertyFilter->getValues(); // 加载所有匹配当前选中选项的规则 $ruleCriteria = new Criteria(); $ruleCriteria->addFilter(new EqualsAnyFilter('triggerPropertyOptionId', $currentSelectedOptionIds)); $rules = $this->ruleRepository->search($ruleCriteria, $event->getContext())->getEntities(); foreach ($rules as $rule) { // 获取目标属性组下所有选项ID,排除规则中允许的选项之外的部分 $targetGroupCriteria = new Criteria([$rule->getTargetPropertyGroupId()]); $targetGroupCriteria->addAssociation('options'); $targetGroup = $this->propertyGroupRepository->search($targetGroupCriteria, $event->getContext())->first(); if (!$targetGroup) continue; $allOptionIds = $targetGroup->getOptions()->map(fn($opt) => $opt->getId())->getArrayCopy(); $disallowedOptionIds = array_diff($allOptionIds, $rule->getAllowedOptionIds()); if (!empty($disallowedOptionIds)) { $criteria->addFilter( new NotFilter( NotFilter::CONNECTION_OR, array_map(fn($id) => new EqualsFilter('properties.options.id', $id), $disallowedOptionIds) ) ); } } }
4. 适配前端过滤选项
如果需要在前端属性筛选器中隐藏禁用的选项,还要监听ProductListingResultEvent,修改返回的过滤选项集合,移除不符合规则的选项。
内容的提问来源于stack exchange,提问作者Stacker1427
相关产品推荐
相关产品推荐

