API Platform自定义过滤器:已交付商品数量范围筛选异常求助
问题分析
你当前的代码中,SIZE(' . $alias . '.items)统计的是主实体关联的全部商品总数,而非过滤出的已交付状态商品数量。后续的item.status = :status仅会过滤查询返回的关联商品记录,但并不会改变SIZE()函数的统计范围——它始终基于主实体关联的整个商品集合,而非筛选后的子集。
解决方案
下面提供两种可行的修正方案,你可以根据Doctrine版本和项目需求选择:
方案1:使用子查询统计已交付商品数量(兼容所有Doctrine版本)
通过子查询单独统计每个主实体下已交付状态的商品数量,再将这个统计值与数量范围比较:
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void { if ($property !== 'totalDeliveredItems' || empty($value)) { return; } $alias = $queryBuilder->getRootAliases()[0]; $em = $queryBuilder->getEntityManager(); $subQuery = $em->createQueryBuilder(); // 替换以下两处为你的实际实体关联关系: // 1. 替换为商品实体的类名(如 OrderItem::class) // 2. 替换为商品实体关联主实体的字段名(如 i.order = :mainEntity) $subQuery->select('COUNT(i.id)') ->from('App\Entity\OrderItem', 'i') ->where('i.order = ' . $alias) ->andWhere('i.status = :status'); $queryBuilder ->andWhere(sprintf('(%s) BETWEEN :from AND :to', $subQuery->getDQL())) ->setParameter('status', 'delivered') ->setParameter('from', 1) ->setParameter('to', 20); }
方案2:使用Doctrine COUNT_FILTER函数(Doctrine ORM 2.13+ 可用)
如果你的项目使用Doctrine ORM 2.13及以上版本,可以直接使用COUNT_FILTER()函数,它支持对关联集合进行条件统计:
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void { if ($property !== 'totalDeliveredItems' || empty($value)) { return; } $alias = $queryBuilder->getRootAliases()[0]; $queryBuilder ->andWhere("COUNT_FILTER($alias.items, 'status = :status') BETWEEN :from AND :to") ->setParameter('status', 'delivered') ->setParameter('from', 1) ->setParameter('to', 20); }
额外说明
- 移除原代码中的
innerJoin($alias . '.items', 'item'):因为我们不需要返回关联的商品记录,只需要统计数量,这个关联会增加不必要的查询开销。 - 原代码中的
$queryBuilder->getQuery()->getResult();也可以移除:过滤器的职责是修改查询构造器,无需在这里执行查询,查询的执行由API平台的核心流程处理。
内容的提问来源于stack exchange,提问作者blueshark67
相关产品推荐
相关产品推荐

