mojtaba-gheytasi / request-validator-bundle
用于在清晰结构中验证请求参数的 Symfony 扩展包
v0.1.0
2021-08-14 14:04 UTC
Requires
- php: >=7.4
- symfony/framework-bundle: ^4.4 || ^5.0
- symfony/validator: ^4.4 || ^5.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpunit/phpunit: 9.5.x-dev
- sensio/framework-extra-bundle: ^5.5
- symfony/browser-kit: ^5.0
- symfony/maker-bundle: ^1.30
- symfony/test-pack: ^1.0
- symfony/yaml: ^4.4 || ^5.0
README
Symfony 请求验证扩展包
它做什么? :)
此扩展包允许您根据请求类中的验证逻辑,通过您的约束和限制来验证请求参数。
安装
composer require mojtaba-gheytasi/request-validator-bundle
兼容性
- PHP v7.4 或更高版本
- Symfony v4.4 或更高版本
使用方法
假设您想如下验证传入的请求参数
//Get api/product/search?brand=gucci&price[min]=100&price[max]=1000 [ 'brand' => 'gucci', 'price' => [ 'min' => 100, 'max' => 1000, ], ];
首先,通过以下命令创建一个请求类
$ bin/console make:request SearchProduct
注意:将在 src/Request 中创建 SearchProductRequest.php。
现在将您的验证约束添加到 constraints 方法中
<?php namespace App\Request; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Type; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\Positive; use MojtabaGheytasi\RequestValidatorBundle\Request\RequestWithValidation; class SearchProductRequest extends RequestWithValidation { /** * Get the validation constraints that apply to the request. */ protected function constraints(): array { return [ 'brand' => [ new Length(['min' => 2]), new Type('string'), ], 'price' => new Collection([ 'fields' => [ 'min' => [ new Type('integer'), new Positive(), ], 'max' => [ new Type('integer'), new Positive(), ], ], ]), ]; } }
那么,如何评估验证约束?您只需在控制器方法中对请求进行类型提示。在调用控制器方法之前,将验证传入的请求数据,这意味着您不需要在控制器中添加验证逻辑。
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; class ProductController { public function search(SearchProductRequest $request): Response { if ($request->hasError()) { return new JsonResponse($request->getErrors(), Response::HTTP_BAD_REQUEST); } // The incoming request is valid... // Retrieve one of the validated input data... $brand = $request->validated('brand'); //gucci // Retrieve all of the validated input data... $validated = $request->validated(); // [ // 'brand' => 'gucci', // 'price' => [ // 'min' => 100, // 'max' => 1000, // ] // ] } }
如果按如下方式验证传入的请求参数,将看到错误信息
//Get api/product/search?brand=a&price[min]=dummy&price[max]=-10.5 [ 'brand' => 'a', 'price' => [ 'min' => 'dummy', 'max' => -10.5, ], ];
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\Response; class ProductController { public function search(SearchProductRequest $request): Response { $request->hasError(); // true $request->getErrors(); // returns following array // [ // "brand": [ // "This value is too short. It should have 2 characters or more." // ], // "price": [ // "min": [ // "This value should be of type integer.", // "This value should be positive." // ], // "max": [ // "This value should be of type integer.", // "This value should be positive." // ] // ] // ] } }
建议
最好在控制器方法中避免重复以下代码,if ($request->hasError()) { return new JsonResponse($request->getErrors(), Response::HTTP_BAD_REQUEST); }
RequestValidatorBundle 提供了一个很好的解决方案来做到这一点,首先创建一个实现 MojtabaGheytasi\RequestValidatorBundle\Contract\FailedValidationInterface 的类,并在 onFailedValidation 方法中编写您的逻辑
<?php namespace App\Request\CustomValidation; use MojtabaGheytasi\RequestValidatorBundle\Contract\FailedValidationInterface; class FailedValidation implements FailedValidationInterface { public function onFailedValidation(array $errors) { // Recommend throw an custom exception and handle it with symfony listeners (listen on ExceptionEvent) // You can find more details on https://symfony.com.cn/doc/4.4/event_dispatcher.html#creating-an-event-listener } }
现在只需在 config/packages/ 目录中创建一个 yaml 文件,并将上述类定义为 RequestValidatorBundle,如下所示
request_validator: failed_validation: 'App\Request\CustomValidation'
完成这些后,当请求出现错误时,RequestValidatorBundle 会立即执行 onFailedValidation 方法,如果您在 onFailedValidation 方法中抛出异常或以其他方式响应,则控制器方法代码将不会执行。因此,您可以像以下这样编写控制器方法
<?php namespace App\Controller; use Symfony\Component\HttpFoundation\Response; class ProductController { public function search(SearchProductRequest $request): Response { // The incoming request is valid... // Retrieve one of the validated input data... $brand = $request->validated('brand'); //gucci } }
贡献 
如果您发现一个问题,或有更好的做法,请随时提交问题或拉取请求。