Symfony的 MapQueryString不支持可选参数
我有一个简单的端点,带有用于过滤的可选查询参数。在我的控制器中,我使用MapQueryString将它们映射到一个DTO,并在内部进行验证。问题在于当我完全不传任何参数调用端点时,Symfony会返回422 HTTP错误。
我的控制器端点:
#[SuccessfulPaginatedResponse(description: 'Returns paginated list of categories by given filters.')]
#[ValidationErrorResponse]
#[Route(name: 'categories_index', methods: ['GET'], format: 'json')]
public function index(
#[MapQueryString(
validationGroups: ['default'],
validationFailedStatusCode: Response::HTTP_UNPROCESSABLE_ENTITY
)] IndexRequestQueryDto $queryParams,
Request $request
): JSONResponse {
$filter = CategoryFilterFactory::createFromIndexRequest($queryParams);
$result = $this->categoryService->fetch($filter);
$paginatedResponse = PaginatedResponse::create(
$result['data'],
$queryParams,
$result['totalCount'],
$request
);
return $this->json($paginatedResponse->toArray());
}
我的DTO:
class IndexRequestQueryDto extends PaginatedRequest
{
public function __construct(
#[Assert\Positive]
#[Assert\Type('integer')]
public readonly ?int $businessUnit = null,
#[Assert\Positive]
#[Assert\Type('integer')]
public readonly ?int $parentId = null,
#[Assert\Type('string')]
public readonly ?string $name = null,
?int $page = null,
?int $pageSize = null,
) {
parent::__construct($page, $pageSize);
}
}
我的DTO的扩展类:
class PaginatedRequest implements DtoInterface
{
public const DEFAULT_PAGE = 1;
public const DEFAULT_PAGE_SIZE = 25;
public const MAX_PAGE_SIZE = 100;
public function __construct(
#[Assert\Type('integer')]
#[Assert\Positive]
public readonly ?int $page = null,
#[Assert\Type('integer')]
#[Assert\Positive]
#[Assert\LessThanOrEqual(self::MAX_PAGE_SIZE)]
public readonly ?int $pageSize = null,
) {
}
我尝试但没奏效的做法:
- 移除了所有断言
- 在IndexRequestQueryDto中尝试定义page与 pageSize,但没有将它们传给父构造函数
- 尝试使用#[Assert\When()]
唯一对我有用的是在控制器中使用ValidatorInterface,但该方案需要额外的代码,我不喜欢:
$queryParams = new IndexRequestQueryDto(
$request->query->has('businessUnit') ? (int) $request->query->get('businessUnit') : null,
$request->query->has('parentId') ? (int) $request->query->get('parentId') : null,
$request->query->has('name') ? (string) $request->query->get('name') : null,
$request->query->has('page') ? (int) $request->query->get('page') : null,
$request->query->has('pageSize') ? (int) $request->query->get('pageSize') : null,
);
$errors = $this->validator->validate($queryParams);
if (count($errors) > 0) {
return $this->json(['errors' => $errors], Response::HTTP_UNPROCESSABLE_ENTITY);
}
Symfony版本为6.4,PHP为 8.2
解决方案
解决方案是在默认情况下不带参数来实例化Dto,感谢给出这个答案的人,不过他把答案删掉了。对我确实有用。
public function index(
#[MapQueryString(
validationFailedStatusCode: Response::HTTP_UNPROCESSABLE_ENTITY
)] IndexRequestQueryDto $queryParams = new IndexRequestQueryDto(),
Request $request
)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。