You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:35:08