Api Platform 3中GetCollection使用DTO时保留Doctrine分页信息
问题与解决方案
问题
需实现一个列出Doctrine托管实体的API端点,返回结果要包含实体本身没有的属性。已通过DTO完成单实体GET操作的数据展示,但在GetCollection操作中,为保留Doctrine的过滤和分页逻辑,复用了默认的ApiPlatform\Doctrine\Orm\State\CollectionProvider,获取到Paginator对象后遍历构建DTO数组返回,导致序列化输出丢失分页信息,需解决如何保留分页信息的问题。
解决方案
1. Symfony服务配置
通过依赖注入绑定默认的Doctrine集合Provider:
App\State\EntityProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
2. 自定义Provider实现
编写自定义Provider,复用默认Provider的分页逻辑,将实体转换为DTO后用TraversablePaginator包装,保留分页元信息:
namespace App\State; use ApiPlatform\Metadata\ResourceMetadataCollection; use ApiPlatform\State\ProviderInterface; use ApiPlatform\Doctrine\Orm\State\TraversablePaginator; use ApiPlatform\Metadata\ResourceMetadataCollectionFactoryInterface; class EntityProvider implements ProviderInterface { public function __construct( readonly private ProviderInterface $collectionProvider, readonly private ResourceMetadataCollectionFactoryInterface $collectionFactory ) {} public function provide( ResourceMetadataCollection $resourceMetadata, array $uriVariables = [], array $context = [] ): object|array|null { // 调用默认Provider获取带分页的结果 $paginator = $this->collectionProvider->provide($resourceMetadata, $uriVariables, $context); // 将每个实体转换为DTO $dtoCollection = []; foreach ($paginator as $entity) { // 替换为你的DTO实例化代码,比如: // $dtoCollection[] = new EntityDto($entity); } // 用TraversablePaginator包装DTO集合,传入原分页参数 return new TraversablePaginator( new \ArrayObject($dtoCollection), $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems() ); } }
原理说明
默认的Paginator包含分页元数据,但直接转换为数组会丢失这些信息。通过TraversablePaginator重新包装DTO集合,并传入原Paginator的当前页、每页条数、总条目数,API Platform就能识别并序列化出正确的分页信息。
内容的提问来源于stack exchange,提问作者Peter Hoehne
相关产品推荐
相关产品推荐

