Symfony 4 扩展验证请求
Symfony 4 extend request for validation
我目前正在做一个 API 项目。我习惯了 Laravel,现在我需要使用 Symfony。我想像 Laravel 那样使用请求进行验证。
所以我扩展了 Symfony\Component\HttpFoundation\Request class。在那里我做了一些逻辑来检查和清理传入的请求。
之后,我将新创建的请求添加到控制器中的存储函数中。但这给了我一个错误:
Argument 1 passed to App\Controller\Ticket\TicketController::store() must be an instance of App\Validation\Ticket\TicketStoreRequest, instance of Symfony\Component\HttpFoundation\Request given,/vendor/symfony/http-kernel/HttpKernel.php on line 149 {"exception":"[object] (Symfony\Component\Debug\Exception\FatalThrowableError(code: 0): Argument 1 passed to App\Controller\Ticket\TicketController::store() must be an instance of App\Validation\Ticket\TicketStoreRequest, instance of Symfony\Component\HttpFoundation\Request given
谷歌搜索后,我找到了几个选项。
- 将每个控制器操作添加到 service.yaml
- 创建侦听器并在正确的路由上添加验证
但是所有选项都需要在不同地方提供额外信息。我希望有人有更好的主意。
我发现了一些可能为您指明正确方向的提示:
Symfony ships with five value resolvers in the HttpKernel component:
...
RequestValueResolver
Injects the current Request if type-hinted with Request or a class extending Request.
见https://symfony.com/doc/current/controller/argument_value_resolver.html
然后页面继续描述自定义 RequestAttributeValueResolver 的实现。此自定义解析器可以在您的
services.yml
。
尽管在此示例中为一个单一属性类型(用户)创建了一个 Class,但有一些方法可以创建更动态的实现。
在此示例中,ArgumentMetadata
参数具有一个方法 $argument->getType()
,该方法应包含要检查的类型的字符串表示形式:
if (User::class !== $argument->getType()) {
return false;
}
没有什么能阻止您检查一组受支持的请求类型。该数组可以作为自定义 RequestValueResolver
中的 class 成员进行管理。自定义 RequestValueResolver
class 的唯一要求是 supports()
方法 returns true
用于支持的请求类型,以及 resolve()
函数returns 此支持的请求类型的一个实例。这应该很简单,因为这两种方法都通过 ArgumentMetaData
参数提供了 'desired' class。
作为替代方案,您可以为每个要支持的自定义请求类型实现自定义 RequestValueResolver
,但这感觉不是很优雅。
我不能保证这会起作用,我也不确定在示例中实现 RequestAttributeValueResolver
和实现自定义 RequestValueResolver
之间的区别,但我觉得它可能只是工作,用一点肘部润滑脂。
这是一个详细说明我的另一个示例的解决方案。它不像我的另一个示例那样安全,但它满足您的要求。
public function supports(Request $request, ArgumentMetadata $argument)
{
$desiredRequestClass = $argument->getType();
return class_exists($desiredRequestClass);
}
public function resolve(Request $request, ArgumentMetadata $argument)
{
$desiredRequestClass = $argument->getType();
$customRequest = new $desiredRequestClass();
$customRequest->createFromGlobals();
// TODO: more initialization you might need.
yield $customRequest;
}
可能建议检查 $desiredRequestClass
是否是 Request
的后代。
我目前正在做一个 API 项目。我习惯了 Laravel,现在我需要使用 Symfony。我想像 Laravel 那样使用请求进行验证。 所以我扩展了 Symfony\Component\HttpFoundation\Request class。在那里我做了一些逻辑来检查和清理传入的请求。
之后,我将新创建的请求添加到控制器中的存储函数中。但这给了我一个错误:
Argument 1 passed to App\Controller\Ticket\TicketController::store() must be an instance of App\Validation\Ticket\TicketStoreRequest, instance of Symfony\Component\HttpFoundation\Request given,/vendor/symfony/http-kernel/HttpKernel.php on line 149 {"exception":"[object] (Symfony\Component\Debug\Exception\FatalThrowableError(code: 0): Argument 1 passed to App\Controller\Ticket\TicketController::store() must be an instance of App\Validation\Ticket\TicketStoreRequest, instance of Symfony\Component\HttpFoundation\Request given
谷歌搜索后,我找到了几个选项。
- 将每个控制器操作添加到 service.yaml
- 创建侦听器并在正确的路由上添加验证
但是所有选项都需要在不同地方提供额外信息。我希望有人有更好的主意。
我发现了一些可能为您指明正确方向的提示:
Symfony ships with five value resolvers in the HttpKernel component:
...
RequestValueResolver
Injects the current Request if type-hinted with Request or a class extending Request.
见https://symfony.com/doc/current/controller/argument_value_resolver.html
然后页面继续描述自定义 RequestAttributeValueResolver 的实现。此自定义解析器可以在您的
services.yml
。
尽管在此示例中为一个单一属性类型(用户)创建了一个 Class,但有一些方法可以创建更动态的实现。
在此示例中,ArgumentMetadata
参数具有一个方法 $argument->getType()
,该方法应包含要检查的类型的字符串表示形式:
if (User::class !== $argument->getType()) {
return false;
}
没有什么能阻止您检查一组受支持的请求类型。该数组可以作为自定义 RequestValueResolver
中的 class 成员进行管理。自定义 RequestValueResolver
class 的唯一要求是 supports()
方法 returns true
用于支持的请求类型,以及 resolve()
函数returns 此支持的请求类型的一个实例。这应该很简单,因为这两种方法都通过 ArgumentMetaData
参数提供了 'desired' class。
作为替代方案,您可以为每个要支持的自定义请求类型实现自定义 RequestValueResolver
,但这感觉不是很优雅。
我不能保证这会起作用,我也不确定在示例中实现 RequestAttributeValueResolver
和实现自定义 RequestValueResolver
之间的区别,但我觉得它可能只是工作,用一点肘部润滑脂。
这是一个详细说明我的另一个示例的解决方案。它不像我的另一个示例那样安全,但它满足您的要求。
public function supports(Request $request, ArgumentMetadata $argument)
{
$desiredRequestClass = $argument->getType();
return class_exists($desiredRequestClass);
}
public function resolve(Request $request, ArgumentMetadata $argument)
{
$desiredRequestClass = $argument->getType();
$customRequest = new $desiredRequestClass();
$customRequest->createFromGlobals();
// TODO: more initialization you might need.
yield $customRequest;
}
可能建议检查 $desiredRequestClass
是否是 Request
的后代。