Api-platform 2.6如何配置自定义路由获取实体关联的外部访客子资源
Api-Platform 2.6 自定义子资源路由实现方案
你的需求属于典型的非本地存储子资源场景,以下两种实现方式都符合框架设计规范,可根据你的后续扩展需求选择:
方案1:自定义控制器(快速实现,适合单一场景)
步骤1:配置实体操作
给你的EsiriusSite实体添加自定义item操作:
/** * @ApiResource( * itemOperations={ * "get", // 保留你原有需要的原生操作,不需要可以删掉 * "get_visitors"={ * "method"="GET", * "path"="/esirius_sites/{idsys}/visitors", * "controller"=GetEsiriusSiteVisitorsController::class, * "output"=Visitor::class, // 可指定为你自建的访客DTO类,不需要也可以去掉 * "read"=false, // 关闭框架默认的实体查询,不需要去数据库拉取EsiriusSite数据 * "write"=false, * } * } * ) * @ORM\Entity */ class EsiriusSite { // 原有实体属性,比如$idsys等 }
步骤2:实现自定义控制器
控制器仅需要实现__invoke方法即可:
<?php namespace App\Controller; use App\Service\ThirdPartyVisitorService; // 你自己封装的第三方API调用服务 use Symfony\Component\HttpFoundation\Request; class GetEsiriusSiteVisitorsController { public function __construct(private ThirdPartyVisitorService $visitorService) {} public function __invoke(Request $request, string $idsys) { // 直接用路径参数idsys调用第三方接口拉取访客数据,返回数组或Visitor对象集合 return $this->visitorService->getVisitorsBySiteId($idsys); } }
这个方案的优势是实现快,逻辑独立,不需要额外配置其他组件。
方案2:自定义数据提供者(符合框架规范,适合多扩展场景)
如果后续还有多个非本地存储的资源接口,推荐用这种方式,可复用Api-platform原生的序列化、分页、过滤等能力,不需要写自定义控制器。
步骤1:创建访客DTO类并配置资源
/** * @ApiResource( * collectionOperations={ * "get"={ * "path"="/esirius_sites/{idsys}/visitors", * } * }, * itemOperations={} // 不需要单访客接口可以留空 * ) */ class Visitor { // 定义访客对应的属性,比如id、姓名、访问时间等,加序列化组配置即可 }
步骤2:实现访客集合数据提供者
<?php namespace App\DataProvider; use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use App\Service\ThirdPartyVisitorService; use App\Entity\Visitor; use Symfony\Component\HttpFoundation\RequestStack; class VisitorCollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( private RequestStack $requestStack, private ThirdPartyVisitorService $visitorService ) {} public function supports(string $resourceClass, string $operationName = null, array $context = []): bool { return $resourceClass === Visitor::class && $operationName === 'get'; } public function getCollection(string $resourceClass, string $operationName = null, array $context = []) { $idsys = $this->requestStack->getCurrentRequest()->attributes->get('idsys'); // 调用第三方接口拉取数据,转换为Visitor对象集合返回 return $this->visitorService->getVisitorsBySiteId($idsys); } }
如果使用Symfony的自动配置,这个数据提供者会自动生效,不需要额外配置服务。
注意事项
- 如果需要先校验idsys对应的站点是否存在于本地数据库,只需要在控制器或数据提供者中添加对应的查询逻辑,不存在时直接抛出
NotFoundHttpException即可。 - 第三方接口的异常可以封装在你自己的服务类中,抛出对应的HTTP异常后框架会自动转换为标准的API响应格式。
- 两种方案都不会返回EsiriusSite的任何数据,输出内容完全由你返回的访客集合决定。
内容的提问来源于stack exchange,提问作者Floxblah
相关产品推荐
相关产品推荐

