如何实现匹配registrationId与hash双字段的API自定义过滤器?
解决方案
情况1:通过两个独立查询参数(registrationId和hash)同时过滤
这种方式最直观,用户通过?registrationId=xxx&hash=yyy的形式传递参数,过滤器会自动生成AND条件匹配两个字段。
修改你的RegistrationSearchFilter代码如下:
final class RegistrationSearchFilter extends AbstractFilter { protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void { // 只处理我们需要的两个字段 if (!in_array($property, ['registrationId', 'hash'])) { return; } $alias = $queryBuilder->getRootAliases()[0]; // 生成唯一参数名,避免多参数冲突 $paramName = $queryNameGenerator->generateParameterName($property); // 添加AND条件并绑定参数值 $queryBuilder->andWhere(sprintf('%s.%s = :%s', $alias, $property, $paramName)) ->setParameter($paramName, $value); } public function getDescription(string $resourceClass): array { $description = []; $fields = [ 'registrationId' => '匹配注册ID', 'hash' => '匹配哈希值' ]; foreach ($fields as $property => $desc) { $description[$property] = [ 'property' => $property, 'type' => Type::BUILTIN_TYPE_STRING, 'required' => false, 'description' => $desc, 'openapi' => [ 'example' => $property === 'registrationId' ? 'REG-202405' : 'a1b2c3d4e5f6', 'allowReserved' => false, 'allowEmptyValue' => false, 'explode' => false, ], ]; } return $description; } }
关键修正点:
- 移除原代码中对
search属性的判断,改为处理实体注解指定的registrationId和hash字段 - 为每个字段生成唯一参数名,避免参数冲突
- 正确绑定参数值到查询中,解决原代码参数未赋值的问题
- 生成对应OpenAPI文档描述,方便前端使用
情况2:通过单个查询参数传递两个字段值
如果需要通过单个参数(比如?search=REG-202405:a1b2c3d4e5f6)传递两个值,可按以下方式修改:
final class RegistrationSearchFilter extends AbstractFilter { protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void { if ($property !== 'search') { return; } // 按分隔符拆分参数值(这里用冒号,可根据需求调整) [$registrationId, $hash] = explode(':', $value, 2); // 格式不合法则跳过 if (empty($registrationId) || empty($hash)) { return; } $alias = $queryBuilder->getRootAliases()[0]; // 生成唯一参数名 $regParam = $queryNameGenerator->generateParameterName('registrationId'); $hashParam = $queryNameGenerator->generateParameterName('hash'); // 添加AND条件并绑定两个参数 $queryBuilder->andWhere(sprintf('%s.registrationId = :%s AND %s.hash = :%s', $alias, $regParam, $alias, $hashParam)) ->setParameter($regParam, $registrationId) ->setParameter($hashParam, $hash); } public function getDescription(string $resourceClass): array { return [ 'search' => [ 'property' => 'search', 'type' => Type::BUILTIN_TYPE_STRING, 'required' => false, 'description' => '同时匹配registrationId和hash,格式为「registrationId:hash」', 'openapi' => [ 'example' => 'REG-202405:a1b2c3d4e5f6', 'allowReserved' => false, 'allowEmptyValue' => false, 'explode' => false, ], ], ]; } }
注意:这种方式需要修改实体注解为#[ApiFilter(RegistrationSearchFilter::class, properties: ['search'])],确保过滤器监听search参数。
原代码问题总结
- 过滤器逻辑错误:原代码只处理
search属性,但实体注解指定的是registrationId和hash,导致过滤逻辑从未执行 - 参数未绑定:原代码的
WHERE子句使用了:search和:hash参数,但未通过setParameter赋值,导致查询报错 - 文档描述不符:原代码生成的是正则过滤的描述,与实际需求的精确匹配不符
内容的提问来源于stack exchange,提问作者Richard Bridge
相关产品推荐
相关产品推荐

