API Platform Doctrine:如何筛选关联商品数量超指定值的订单
解决方案
1. 先修正实体关联的注解错误
原实体里的inversedBy属性写反了,这会导致Doctrine无法正确识别关联关系,修正后的代码如下:
Order实体
class Order { #[ORM\Id] #[ORM\GeneratedValue] private ?int $id = null; #[ORM\ManyToMany(targetEntity: Item::class, inversedBy: 'orders')] private Collection $items; // 初始化集合 public function __construct() { $this->items = new ArrayCollection(); } // 这里补充你的getter/setter方法... }
Item实体
class Item { #[ORM\Id] #[ORM\GeneratedValue] private ?int $id = null; #[ORM\ManyToMany(targetEntity: Order::class, inversedBy: 'items')] private Collection $orders; // 初始化集合 public function __construct() { $this->orders = new ArrayCollection(); } // 这里补充你的getter/setter方法... }
2. 完善自定义过滤器逻辑
API Platform的自定义过滤器不需要自己执行查询,只需要修改QueryBuilder让框架后续处理即可,以下是完整的过滤器代码:
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use Doctrine\ORM\QueryBuilder; use Symfony\Component\PropertyInfo\Type; #[AsFilter('order_total_items_filter')] // Symfony 5.4+用这个注解直接注册过滤器,旧版本看步骤3 class OrderTotalItemsFilter extends AbstractFilter { protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void { // 只处理totalItems属性,且值是有效数字 if ($property !== 'totalItems' || !is_numeric($value)) { return; } $rootAlias = $queryBuilder->getRootAliases()[0]; $itemsAlias = $queryNameGenerator->generateJoinAlias('items'); $parameterName = $queryNameGenerator->generateParameterName('totalItems'); // 关联商品表、分组、添加筛选条件(商品数量大于传入值) $queryBuilder ->leftJoin(sprintf('%s.items', $rootAlias), $itemsAlias) ->groupBy($rootAlias) ->having(sprintf('COUNT(%s.id) > :%s', $itemsAlias, $parameterName)) ->setParameter($parameterName, (int)$value, Type::BUILTIN_TYPE_INT); } public function getDescription(string $resourceClass): array { return [ 'totalItems' => [ 'property' => 'totalItems', 'type' => 'int', 'required' => false, 'description' => '筛选关联商品数量大于指定数值的订单,例:?totalItems=2 返回商品数量超过2的订单', 'openapi' => [ 'example' => 2, 'type' => 'integer', ], ], ]; } }
3. 注册过滤器(旧Symfony版本用)
如果你的Symfony版本低于5.4,没法用#[AsFilter]注解,就在config/services.yaml里手动注册:
services: App\Filter\OrderTotalItemsFilter: tags: - { name: api_platform.filter, id: 'order_total_items_filter' }
4. 在Order实体上启用过滤器
给Order实体加上API Platform的过滤器注解:
use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Metadata\ApiResource; #[ApiResource] #[ApiFilter(OrderTotalItemsFilter::class)] class Order { // ... 你的实体代码 }
5. 使用方式
调用API时带上totalItems参数就行,比如:GET /orders?totalItems=2
这个请求会返回所有关联商品数量大于2的订单(对应你给的示例数据,暂时没有符合条件的订单;如果有订单关联3个及以上商品,就会被返回)。
如果需要支持>=、<这类其他比较逻辑,可以扩展过滤器,让参数支持操作符(比如totalItems[gte]=2),但上面的代码已经满足你“筛选超过2个商品的订单”的需求。
内容的提问来源于stack exchange,提问作者apple salad
相关产品推荐
相关产品推荐

