使用大于/小于/等于筛选时触发count()错误求助
问题分析
错误count(): Argument #1 ($value) must be of type Countable|array, Doctrine\ORM\Query\Expr\Andx given的核心原因是分页器(NewPaginator)在处理带GROUP BY和HAVING的查询时,错误地将Doctrine的查询表达式对象(Andx)传入了count()函数,而非可计数的结果集。
从代码逻辑来看,当你添加GROUP BY s.id和HAVING条件后,默认的分页计数逻辑无法正确解析这种分组查询结构,最终触发类型错误。
解决方案
1. 手动构建分页计数查询
修改findPaginated方法,为NewPaginator提供手动构建的count查询,绕过默认计数逻辑的缺陷:
public function findPaginated(InterpretationTranslationSourceFilter $filter): NewPaginator { $qb = $this->createQueryBuilder('s') ->leftJoin('s.authorToSourceRelations', 'atsr') ->select('s as interpretationTranslationSource') ->addSelect('COUNT(DISTINCT atsr.id) AS authorToSourceRelationsCount') ->groupBy('s.id'); // 原有筛选条件逻辑保留 if ($filter->isHasLink() OR $filter->getDontHasLink()) { if ($filter->isHasLink()) { $qb->andWhere('s.url IS NOT NULL'); } if ($filter->getDontHasLink()) { $qb->andWhere('s.url IS NULL'); } } if ($filter->getSortByAuthorsCount()) { $comparisonOperator = substr($filter->getSortByAuthorsCount(), 0, 1); $authorsCount = (int) substr($filter->getSortByAuthorsCount(), 1); switch ($comparisonOperator) { case '=': $qb->having('authorToSourceRelationsCount = :authorsCount') ->setParameter('authorsCount', $authorsCount); break; case '>': $qb->having('authorToSourceRelationsCount > :authorsCount') ->setParameter('authorsCount', $authorsCount); break; case '<': $qb->having('authorToSourceRelationsCount < :authorsCount') ->setParameter('authorsCount', $authorsCount); break; default: $qb->orderBy('s.title', 'ASC'); break; } } if ($filter->getTitle()) { $qb->andWhere('s.title like :title') ->setParameter('title', '%' . $filter->getTitle() . '%'); } if ($filter->getUrl()) { $qb->andWhere('s.url LIKE :url') ->setParameter('url', '%' . $filter->getUrl() . '%'); } // 手动构建count查询 $countQb = $this->createQueryBuilder('s') ->select('COUNT(DISTINCT s.id)') ->leftJoin('s.authorToSourceRelations', 'atsr'); // 复制主查询的WHERE条件 foreach ($qb->getDQLPart('where') as $wherePart) { $countQb->andWhere($wherePart); } // 复制主查询的HAVING条件(分组筛选需保留) if ($qb->getDQLPart('having')) { foreach ($qb->getDQLPart('having') as $havingPart) { $countQb->having($havingPart); } } // 同步参数绑定 foreach ($qb->getParameters() as $param) { $countQb->setParameter($param->getName(), $param->getValue()); } // 将count查询传入分页器(需确保NewPaginator支持此方法) $paginator = new NewPaginator($qb, $filter); $paginator->setCountQuery($countQb); return $paginator; }
2. 适配NewPaginator实现
如果你的NewPaginator没有setCountQuery方法,需要修改其内部逻辑:
- 移除直接对主查询调用
count()的逻辑,改为单独执行手动构建的count查询获取总条数。 - 针对分组查询,确保count查询统计的是分组后的主键数量,而非原始行数。
3. 输入合法性校验(可选优化)
在处理$filter->getSortByAuthorsCount()时,添加格式校验,避免非法输入引发异常:
if ($filter->getSortByAuthorsCount()) { $sortValue = $filter->getSortByAuthorsCount(); // 校验格式:首字符为=/>/<,后续为数字 if (!preg_match('/^[=><]\d+$/', $sortValue)) { $qb->orderBy('s.title', 'ASC'); goto endSortLogic; // 或用return/continue跳过后续逻辑 } $comparisonOperator = substr($sortValue, 0, 1); $authorsCount = (int) substr($sortValue, 1); // 原有switch逻辑... } endSortLogic:
内容的提问来源于stack exchange,提问作者Ivan Havran
相关产品推荐
相关产品推荐

