laravel 中自动批量注册验证规则到验证器

laravel 中自动批量注册验证规则到验证器

创建抽象验证规则 App\Rules\RuleApp\Rules\RegexRule

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Str;

abstract class Rule implements ValidationRule
{
    abstract public function passes(string $attribute, mixed $value): bool;

    public function validate(string $attribute, mixed $value, \Closure $fail): void
    {
        if (! $this->passes($attribute, $value)) {
            $fail(static::message())->translate();
        }
    }

    /**
     * 规则名称
     */
    public static function name(): string
    {
        return Str::of(class_basename(static::class))->replaceLast('Rule', '')->snake();
    }

    /**
     * 错误消息
     */
    public static function message(): string
    {
        $transMessage = __($transKey = sprintf('validation.%s', static::name()));

        return $transMessage === $transKey ? static::fallbackMessage() : $transMessage;
    }

    /**
     * 扩展方法
     */
    public static function extendMethod(): string
    {
        $ruleReflectionClass = new \ReflectionClass(static::class);

        $isImplicit = $ruleReflectionClass->getDefaultProperties()['implicit'] ?? false;
        if ($isImplicit) {
            return 'extendImplicit';
        }

        // extendDependent todo

        return 'extend';
    }

    /**
     * 回退错误消息
     */
    protected static function fallbackMessage(): string
    {
        return __(
            app()->isLocale('zh_CN')
                ? ':Attribute [:input] 必须是有效的 :Name。'
                : 'The :attribute [:input] must be a valid :Name.',
            [
                'name' => value(static function () {
                    $name = __($key = sprintf('validation.attributes.%s', static::name()));

                    return $name === $key ? str(static::name())->replace('_', ' ') : $name;
                }),
            ]
        );
    }
}
<?php

namespace App\Rules;

abstract class RegexRule extends Rule
{
    abstract protected function pattern(): string;

    public function passes(string $attribute, mixed $value): bool
    {
        return (bool) preg_match($this->pattern(), $value);
    }
}

创建验证规则特性 App\Rules\Concerns\DataAwareApp\Rules\Concerns\ValidatorAware

<?php

namespace App\Rules\Concerns;

trait DataAware
{
    protected array $data;

    public function setData(array $data): self
    {
        $this->data = $data;

        return $this;
    }
}
<?php

namespace App\Rules\Concerns;

use Illuminate\Validation\Validator;

trait ValidatorAware
{
    protected Validator $validator;

    public function setValidator(Validator $validator): self
    {
        $this->validator = $validator;

        return $this;
    }
}

创建验证规则

普通验证规则

<?php

namespace App\Rules;

final class Base64Rule extends Rule
{
    public function passes(string $attribute, mixed $value): bool
    {
        return base64_encode(base64_decode($value, true)) === $value;
    }
}

正则验证规则

<?php

namespace App\Rules;

final class PhoneRule extends RegexRule
{
    protected function pattern(): string
    {
        /** @lang PhpRegExp */
        return '/^(?:(?:\+|00)86)?1[3-9]\d{9}$/';
    }
}

隐式验证规则

<?php

namespace App\Rules;

use App\Rules\Concerns\DataAware;
use App\Rules\Concerns\ValidatorAware;
use Illuminate\Contracts\Validation\ValidatorAwareRule;

final class DefaultRule extends Rule implements ValidatorAwareRule
{
    // use DataAware;
    use ValidatorAware;

    public bool $implicit = true;

    public function __construct(protected mixed $default) {}

    public function passes(string $attribute, mixed $value): bool
    {
        if ($value === null) {
            $data = $this->validator->getData();
            $data[$attribute] = $this->default;
            $this->validator->setData($data);
        }

        return true;
    }
}

注册验证规则到验证器

创建类发现器 App\Support\Discover

注册验证规则

<?php

namespace App\Providers;

use App\Rules\Rule;
use App\Support\Discover;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void {}

    public function boot(): void
    {
        Discover::in('Rules')
            ->instanceOf(Rule::class)
            ->all()
            ->each(static function (\ReflectionClass $ruleReflectionClass, $ruleClass): void {
                /** @var Rule&class-string $ruleClass */
                Validator::{$ruleClass::extendMethod()}(
                    $ruleClass::name(),
                    static fn (
                        string $attribute,
                        mixed $value,
                        array $parameters,
                        \Illuminate\Validation\Validator $validator
                    ): bool => tap(new $ruleClass(...$parameters), static function (Rule $rule) use ($validator): void {
                        $rule instanceof ValidatorAwareRule and $rule->setValidator($validator);
                        $rule instanceof DataAwareRule and $rule->setData($validator->getData());
                    })->passes($attribute, $value),
                    $ruleClass::message()
                );
            });
    }
}

验证

<?php

use App\Rules\Base64Rule;
use App\Rules\PhoneRule;
use Illuminate\Support\Facades\Validator;

$validator = Validator::make(
    [
        'base64' => 'foo',
        'phone' => 'bar',
    ],
    [
        // 'base64' => new Base64Rule(),
        'base64' => 'base64', // 验证规则名称
        'phone' => new PhoneRule(), // 验证规则实例
        // 'phone' => 'phone',
    ]
);
dump($validator->errors()->all());

$validator = Validator::make(
    [
        // 'default' => 'baz',
    ],
    [
        'default' => 'default:baz',
    ]
);
dump($validator->validate());
array:2 [
  0 => "Base64 [foo] 必须是有效的 Base64。"
  1 => "电话 [bar] 必须是有效的 电话。"
]

array:1 [
  "default" => "baz"
]

相关连接

原文连接

本作品采用《CC 协议》,转载必须注明作者和本文链接
No practice, no gain in one's wit. 我的 Gitub
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
56
粉丝
126
喜欢
972
收藏
1333
排名:46
访问:15.3 万
私信
所有博文
社区赞助商