illuminatech/validation-composite

允许将多个验证规则合并为一个,便于重用

1.2.5 2024-03-25 10:46 UTC

This package is auto-updated.

Last update: 2024-08-25 11:36:29 UTC


README

Laravel 复合验证


此扩展允许将多个 Laravel 验证规则合并为一个,便于重用。

有关许可信息,请查看LICENSE文件。

Latest Stable Version Total Downloads Build Status

安装

安装此扩展的首选方式是通过composer

运行以下命令:

php composer.phar require --prefer-dist illuminatech/validation-composite

或者将以下内容添加到你的 composer.json 文件中 require 部分:

"illuminatech/validation-composite": "*"

to the require section of your composer.json.

使用方法

验证规则的相同顺序可能在整个应用程序中多次重复。例如:您可能有一组与用户密码相关的限制,例如它应该至少有8个符号长,但不超过200个符号以适应为其存储预留的数据库字段。您的程序也可能允许用户上传一张图片作为其头像,但为了使其安全,您应该验证上传文件的 mime 类型和大尺寸。因此,用户个人资料表单的验证可能如下所示:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProfileController extends Controller
{
    public function update(Request $request)
    {
        $validatedData = $request->validate([
            'password' => ['required', 'string', 'min:8', 'max:200'],
            'avatar' => ['required', 'file', 'mimes:png,jpg,jpeg', 'max:1024'],
            // ...
        ]);
        
        // ...
    }
}

问题是:用户密码或头像的验证可能出现在几个不同的地方。例如:密码可以在注册过程中设置,在密码重置期间等。您可能还有一个独立的管理面板,允许系统管理员调整现有用户记录或创建新的记录。因此,您将不得不在项目源代码的多个地方重复这些验证规则。如果要求更改,例如:我们决定密码长度至少应为10个符号而不是8个,或禁止 '*.png' 文件作为头像 - 您将不得不手动更改所有这些地方的验证规则。

此扩展允许将多个验证规则合并为一个,便于重用。对于上面的例子,您应该创建2个独立的验证规则类,它们扩展了Illuminatech\Validation\Composite\CompositeRule

<?php

namespace App\Rules;

use Illuminatech\Validation\Composite\CompositeRule;

class PasswordRule extends CompositeRule
{
    protected function rules(): array
    {
        return ['string', 'min:8', 'max:200'];
    }
}

class AvatarRule extends CompositeRule
{
    protected function rules(): array
    {
        return ['file', 'mimes:png,jpg,jpeg', 'max:1024'];
    }
}

在此方法rules()中定义了要由定义的规则内部应用的一系列验证规则。现在我们可以用以下方式重写表单验证:

<?php

namespace App\Http\Controllers;

use App\Rules\AvatarRule;
use App\Rules\PasswordRule;
use Illuminate\Http\Request;

class ProfileController extends Controller
{
    public function update(Request $request)
    {
        $validatedData = $request->validate([
            'password' => ['required', new PasswordRule],
            'avatar' => ['required', new AvatarRule],
            // ...
        ]);
        
        // ...
    }
}

使用这种方法,您可以在单个地方更改 'password' 和 'avatar' 的验证。

如果复合验证规则失败,验证器实例将从特定的子规则中选取错误信息。例如:

<?php

use App\Rules\PasswordRule;
use Illuminate\Support\Facades\Validator;

$validator = Validator::make(
    ['password' => 'short'],
    [
        'password' => ['required', new PasswordRule],
    ]
);

if ($validator->fails()) {
    echo $validator->errors()->first('password'); // outputs 'The password must be at least 8 characters.'
}

注意:不要在复合规则中使用像 'sometimes'、'required'、'required_with'、'required_without' 等规则。这些规则在不同的验证级别上处理,因此可能没有效果或可能表现出意外的行为。

您可以使用验证工厂扩展功能定义复合验证规则。对于这种情况,您可以使用Illuminatech\Validation\Composite\DynamicCompositeRule。例如:

<?php

namespace App\Providers;

use Illuminate\Contracts\Validation\Factory;
use Illuminate\Support\ServiceProvider;
use Illuminatech\Validation\Composite\DynamicCompositeRule;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->app->extend('validator', function (Factory $validatorFactory) {
            $validatorFactory->extend('password', function ($attribute, $value) {
                return (new DynamicCompositeRule(['string', 'min:8', 'max:200']))->passes($attribute, $value);
            });
            
            $validatorFactory->extend('avatar', function ($attribute, $value) {
                return (new DynamicCompositeRule(['file', 'mimes:png,jpg,jpeg', 'max:1024']))->passes($attribute, $value);
            });

            return $validatorFactory;
        });
        
        // ...
    }
}

注意,使用这种方法,自动提取验证错误信息变得不可能,您将不得不在语言文件中显式设置它。

您可以为复合验证规则中使用的每个验证规则指定自定义错误信息,覆盖messages()方法。例如:

<?php

namespace App\Rules;

use Illuminatech\Validation\Composite\CompositeRule;

class PasswordRule extends CompositeRule
{
    protected function rules(): array
    {
        return ['string', 'min:8', 'max:200'];
    }

    protected function messages(): array
    {
        return [
            'string' => 'Only string is allowed.',
            'min' => ':attribute is too short.',
            'max' => ':attribute is too long.',
        ];
    }
}