mojtaba-gheytasi/request-validator-bundle

用于在清晰结构中验证请求参数的 Symfony 扩展包

v0.1.0 2021-08-14 14:04 UTC

This package is auto-updated.

Last update: 2024-09-09 16:06:59 UTC


README

Symfony 请求验证扩展包

Scrutinizer Code Quality Build Status

它做什么? :)

此扩展包允许您根据请求类中的验证逻辑,通过您的约束和限制来验证请求参数。

安装

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
    }
}

贡献 raising_hand

如果您发现一个问题,或有更好的做法,请随时提交问题或拉取请求。