ApiPlatform+Symfony自定义URL参数被识别为标识符致NotFoundHttpException
解决ApiPlatform自定义路径参数被误识别为标识符的问题
1. 修正ApiResource操作配置
ApiPlatform 默认会把 URI 模板中的变量当作资源的标识符(比如实体的ID),所以需要显式声明tenant是自定义参数而非标识符。修改GetCollection操作,添加uriVariables配置:
#[ApiResource( operations: [ new GetCollection( uriTemplate: '/{tenant}/agreement', uriVariables: [ 'tenant' => new UriVariable( // 声明该变量不是资源标识符,无需匹配实体 identifier: false, // 可选:指定参数类型 schema: new Type(type: Type::STRING) ) ], openapi: new Model\Operation( parameters: [ new Model\Parameter( name: 'tenant', in: 'path', required: true, schema: new Type(type: Type::STRING) ), ], ), ), ] )]
2. 将参数注入SQL查询
要把tenant参数加入查询条件,推荐使用ApiPlatform的Doctrine ORM扩展,无需编写自定义控制器:
步骤1:创建查询扩展类
// src/Doctrine/Extension/TenantFilterExtension.php namespace App\Doctrine\Extension; use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use App\Entity\Agreement; use Doctrine\ORM\QueryBuilder; class TenantFilterExtension implements QueryCollectionExtensionInterface { public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void { // 仅对Agreement资源和目标GetCollection操作生效 if ($resourceClass !== Agreement::class || $operation?->getName() !== 'get_collection') { return; } // 从请求上下文获取tenant参数 $tenant = $context['request']->get('tenant'); if (!$tenant) { return; } // 添加tenant过滤条件 $rootAlias = $queryBuilder->getRootAliases()[0]; $queryBuilder->andWhere(sprintf('%s.tenant = :tenant', $rootAlias)) ->setParameter('tenant', $tenant); } }
步骤2:注册扩展类
在config/services.yaml中注册该服务:
services: App\Doctrine\Extension\TenantFilterExtension: tags: - { name: api_platform.doctrine.orm.query_extension.collection }
3. 验证效果
现在请求/指定租户值/agreement时,ApiPlatform会正确识别tenant为路径参数,不会再抛出NotFoundHttpException,同时查询会自动带上tenant的过滤条件。
内容的提问来源于stack exchange,提问作者atmacola
相关产品推荐
相关产品推荐

