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

如何扩展Api-Platform GetCollection的JsonLd响应以添加额外数据?

在Api-Platform 3的GetCollection响应中添加额外数据

针对你的需求,有两种简洁可靠的方案可以扩展JsonLD集合响应,添加时间段内的交易总金额:

方案一:使用View事件监听器(直接修改响应)

通过监听KernelEvents::VIEW事件,在响应序列化完成后,追加自定义数据到返回结果中。

实现代码

// src/EventListener/TransactionCollectionTotalListener.php
namespace App\EventListener;

use ApiPlatform\Symfony\EventListener\EventPriorities;
use App\Entity\Transaction;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;

#[AsEventListener(event: KernelEvents::VIEW, priority: EventPriorities::POST_SERIALIZE)]
class TransactionCollectionTotalListener implements EventSubscriberInterface
{
    public function __construct(private EntityManagerInterface $em) {}

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::VIEW => ['addTotalAmount', EventPriorities::POST_SERIALIZE],
        ];
    }

    public function addTotalAmount(ViewEvent $event): void
    {
        $request = $event->getRequest();
        $resourceClass = $request->attributes->get('_api_resource_class');
        $operationName = $request->attributes->get('_api_operation_name');

        // 仅对Transaction实体的GetCollection操作生效
        if ($resourceClass !== Transaction::class || $operationName !== 'get_collection') {
            return;
        }

        $response = $event->getResponse();
        if (!$response) {
            return;
        }

        // 构建总金额查询,复用请求中的过滤参数
        $qb = $this->em->createQueryBuilder();
        $qb->select('SUM(t.amount) as totalAmount')
           ->from(Transaction::class, 't');

        // 应用日期范围过滤(匹配Api-Platform的DateFilter参数格式)
        $dateFilters = $request->query->get('date', []);
        if (isset($dateFilters['after'])) {
            $qb->andWhere('t.date >= :after')
               ->setParameter('after', new \DateTime($dateFilters['after']));
        }
        if (isset($dateFilters['before'])) {
            $qb->andWhere('t.date <= :before')
               ->setParameter('before', new \DateTime($dateFilters['before']));
        }

        // 执行查询获取总金额,处理空结果
        $totalAmount = $qb->getQuery()->getSingleScalarResult() ?: 0.0;

        // 修改响应内容,追加总金额字段
        $responseData = json_decode($response->getContent(), true);
        $responseData['totalAmount'] = (float)$totalAmount;
        $response->setContent(json_encode($responseData));
    }
}

方案二:自定义JsonLD规范化器(贴合Api-Platform序列化流程)

通过自定义规范化器,在实体集合序列化为JsonLD的过程中注入额外数据,这种方式更符合Api-Platform的设计规范。

实现代码

// src/Serializer/TransactionCollectionNormalizer.php
namespace App\Serializer;

use ApiPlatform\Serializer\SerializerContextBuilderInterface;
use App\Entity\Transaction;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;

class TransactionCollectionNormalizer implements ContextAwareNormalizerInterface, NormalizerAwareInterface
{
    use NormalizerAwareTrait;

    public function __construct(
        private EntityManagerInterface $em,
        private SerializerContextBuilderInterface $contextBuilder
    ) {}

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        // 校验是否为Transaction集合的GetCollection操作,且输出格式为JsonLD
        return is_iterable($data) 
            && $context['resource_class'] === Transaction::class
            && $context['operation_name'] === 'get_collection'
            && $format === 'jsonld';
    }

    public function normalize($object, string $format = null, array $context = []): array
    {
        // 先通过默认规范化器生成标准JsonLD集合数据
        $normalizedData = $this->normalizer->normalize($object, $format, $context);

        $request = $context['request'] ?? null;
        if (!$request) {
            return $normalizedData;
        }

        // 构建总金额查询
        $qb = $this->em->createQueryBuilder();
        $qb->select('SUM(t.amount) as totalAmount')
           ->from(Transaction::class, 't');

        // 应用日期过滤参数
        $dateFilters = $request->query->get('date', []);
        if (isset($dateFilters['after'])) {
            $qb->andWhere('t.date >= :after')
               ->setParameter('after', new \DateTime($dateFilters['after']));
        }
        if (isset($dateFilters['before'])) {
            $qb->andWhere('t.date <= :before')
               ->setParameter('before', new \DateTime($dateFilters['before']));
        }

        $totalAmount = $qb->getQuery()->getSingleScalarResult() ?: 0.0;
        // 追加总金额到规范化后的数据中
        $normalizedData['totalAmount'] = (float)$totalAmount;

        return $normalizedData;
    }
}

注册规范化器

在config/services.yaml中添加服务标签,确保优先级高于默认的JsonLD规范化器:

services:
    App\Serializer\TransactionCollectionNormalizer:
        arguments:
            $em: '@doctrine.orm.entity_manager'
            $contextBuilder: '@api_platform.serializer.context_builder'
        tags:
            - { name: serializer.normalizer, priority: 10 }

进阶优化:自动复用Api-Platform过滤器逻辑

如果你的实体配置了多种过滤器(如搜索、排序),手动处理过滤参数容易出错,可以通过Api-Platform的FilterLocator自动应用所有配置的过滤器:

// 在构造函数中注入相关依赖
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Symfony\Bridge\Doctrine\Orm\Filter\FilterLocatorInterface;

public function __construct(
    private EntityManagerInterface $em,
    private FilterLocatorInterface $filterLocator,
    private ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory
) {}

// 在构建查询时替换手动过滤逻辑
$resourceMetadata = $this->resourceMetadataFactory->create(Transaction::class);
$operation = $resourceMetadata->getOperation('get_collection');
$filters = $operation->getFilters() ?? [];

foreach ($filters as $filterId) {
    $filter = $this->filterLocator->get($filterId);
    if ($filter) {
        $filter->apply($qb, $operation, ['request' => $request]);
    }
}

这样可以确保总金额的查询和Api-Platform的集合查询使用完全一致的过滤条件,避免逻辑不一致的问题。

内容的提问来源于stack exchange,提问作者Armandelis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 09:54:52