oriatec/validation

对 somnambulist/validation 进行重写,提供类似 Laravel 的验证,符合 psr-7 标准,作为独立库

1.4.1 2022-06-17 15:12 UTC

This package is not auto-updated.

Last update: 2024-09-25 00:36:42 UTC


README

GitHub Actions Build Status Issues License PHP Version Current Version

这是一个 somnambulist/validation 的分支,类似于 Laravel 验证器的独立验证器。

最初,这个包是对 rakit/validation 的重写。与 rakit/validation 保持一致,这个库在使用时没有其他依赖。请注意,内部 API 与 rakit/validation 实质上不同。

这个分支增加了对 PSR-7 的兼容性,特别是对UploadedFileInterface的支持。

跳转到 规则

需求

  • PHP 8.0+
  • ext/mb-string
  • php-fig/http-message

安装

使用 composer 安装,或从 github.com 检出/拉取文件。

  • composer require oriatec/validation

用法

使用这个库验证数据有两种方式:使用 make 创建验证对象,然后使用 validate 进行验证;或者直接使用 validate

例如

使用 make

<?php

require('vendor/autoload.php');

use ORIATEC\Components\Validation\Factory;

$validation = (new Factory)->make($_POST + $_FILES, [
    'name'                  => 'required',
    'email'                 => 'required|email',
    'password'              => 'required|min:6',
    'confirm_password'      => 'required|same:password',
    'avatar'                => 'required|uploaded_file:0,500K,png,jpeg',
    'skills'                => 'array',
    'skills.*.id'           => 'required|numeric',
    'skills.*.percentage'   => 'required|numeric'
]);
$validation->validate();

if ($validation->fails()) {
    // handling errors
    $errors = $validation->errors();
    echo "<pre>";
    print_r($errors->firstOfAll());
    echo "</pre>";
    exit;
} else {
    // validation passes
    echo "Success!";
}

或者通过 validate

<?php

require('vendor/autoload.php');

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory)->validate($_POST + $_FILES, [
    'name'                  => 'required',
    'email'                 => 'required|email',
    'password'              => 'required|min:6',
    'confirm_password'      => 'required|same:password',
    'avatar'                => 'required|uploaded_file:0,500K,png,jpeg',
    'skills'                => 'array',
    'skills.*.id'           => 'required|numeric',
    'skills.*.percentage'   => 'required|numeric'
]);

if ($validation->fails()) {
	// handling errors
	$errors = $validation->errors();
	echo "<pre>";
	print_r($errors->firstOfAll());
	echo "</pre>";
	exit;
} else {
	// validation passes
	echo "Success!";
}

强烈建议使用依赖注入容器,并将 Factory 作为单例存储,而不是创建新实例。这将减少创建验证实例的代价,并允许更轻松地管理自定义规则。

属性别名

rakit/validation 不同,属性名称不会进行任何转换;相反,如果您想命名属性,则必须使用别名。

别名可以通过几种方式定义:在规则本身上,或者在验证中添加别名。请注意,别名应在调用 validate 之前设置。

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory)->make([
	'province_id' => $_POST['province_id'],
	'district_id' => $_POST['district_id']
], [
	'province_id:Province' => 'required|numeric',
	'district_id:District' => 'required|numeric'
]);

// or set the aliases:
$validation->setAlias('province_id', 'Province');
$validation->setAlias('district_id', 'District');

// then validate it
$validation->validate();

验证消息

验证消息定义在 Resources/i18n/en.php 中。任何消息都可以替换为自定义字符串,或翻译成其他语言。英语字符串始终在 Factory 实例化期间加载。

根据失败类型,将提供各种变量以供使用,但以下变量始终可用于所有消息

  • :attribute:正在验证的属性,如果设置了别名,则使用别名
  • :value:正在验证的属性的值,转换为字符串,数组对象作为 JSON 字符串

Validator 的自定义消息

所有消息都存储在 Factory 实例的 MessageBag 中。可以向此消息包添加更多语言,或在特定的验证实例中进行自定义。此外,可以在 Factory 的消息包上设置默认语言,或在验证实例上设置特定语言。

添加新的消息集

use Somnambulist\Components\Validation\Factory;

$factory = new Factory();
$factory->messages()->add('es', [
    'rule.required' => 'Se requiere :attribute',
]);

$validation = $factory->validate($inputs, $rules);
$validation->setLanguage('es')->validate();

或覆盖默认的英文字符串

use Somnambulist\Components\Validation\Factory;

$factory = new Factory();
$factory->messages()->replace('en', 'rule.required', 'Se requiere :attribute');

$validation = $factory->validate($inputs, $rules);
$validation->validate();

或设置默认语言

use Somnambulist\Components\Validation\Factory;

$factory = new Factory();
$factory->messages()->default('es');

$validation = $factory->validate($inputs, $rules);
$validation->validate();

特定属性规则的自定义消息

有时您可能想要为特定属性规则设置自定义消息,以便使其更明确或添加其他信息。这是通过为属性添加一个以 : 和规则名称结尾的消息键来完成的。

例如

use Somnambulist\Components\Validation\Factory;

$validator = new Factory();
$validation_a = $validator->make($input, [
	'age' => 'required|min:18'
]);

$validation->messages()->add('en', 'age:min', '18+ only');

$validation->validate();

规则的自定义消息

一些规则有多个可能的验证消息。这些消息都命名为 rule.<name>.<check>。要更改消息,覆盖或添加特定的消息。

例如,uploaded_file可能因文件、最小/最大尺寸和类型出现错误。这些与以下相关:

  • rule.uploaded_file
  • rule.uploaded_file.min_size
  • rule.uploaded_file.max_size
  • rule.uploaded_file.type

要更改任何子消息,请向消息包中添加/覆盖该消息键。

例如

use Somnambulist\Components\Validation\Factory;

$validator = new Factory();
$validation_a = $validator->make($input, [
	'age' => 'required|min:18'
]);

$validation->messages()->add('en', 'age:min', '18+ only');

$validation->validate();

rakit不同,无法直接在Rule实例中设置自定义消息。任何消息都必须在消息包中设置。

复杂翻译需求

该库中的翻译系统相当基本。如果您有复杂的需求,或者希望处理可数名词等,那么所有错误消息都存储为包含消息键和该消息变量的ErrorMessage实例。

您可以使用底层数组(或一个DataBag实例)来代替使用ErrorBag显示消息,然后将消息键和变量一起传递给您的翻译系统。

请注意,错误按属性和规则名称嵌套。

与错误消息一起工作

错误消息收集在您可以通过验证实例上的errors()访问的ErrorBag实例中。

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory())->validate($inputs, $rules);

$errors = $validation->errors();

现在,您可以使用以下方法检索消息:

all(string $format = ':message')

获取所有消息作为一个扁平数组

$messages = $errors->all();
// [
//     'email is not a valid email address',
//     'password minimum is 6 characters',
//     'password must contain capital letters'
// ]

$messages = $errors->all('<li>:message</li>');
// [
//     '<li>email is not a valid email address</li>',
//     '<li>password minimum is 6 character</li>',
//     '<li>password must contain capital letters</li>'
// ]

firstOfAll(string $format = ':message', bool $dotNotation = false)

从所有现有键中获取第一条消息

$messages = $errors->firstOfAll();
// [
//     'email' => Email is not valid email',
//     'password' => 'Password minimum 6 character',
// ]

$messages = $errors->firstOfAll('<li>:message</li>');
// [
//     'email' => '<li>Email is not valid email</li>',
//     'password' => '<li>Password minimum 6 character</li>',
// ]

参数$dotNotation用于数组验证。如果它是false,它将返回原始数组结构;如果它是true,它将返回一个具有点符号键的扁平数组。

例如

$messages = $errors->firstOfAll(':message', false);
// [
//     'contacts' => [
//          1 => [
//              'email' => 'Email is not valid email',
//              'phone' => 'Phone is not valid phone number'
//          ],
//     ],
// ]

$messages = $errors->firstOfAll(':message', true);
// [
//     'contacts.1.email' => 'Email is not valid email',
//     'contacts.1.phone' => 'Email is not valid phone number',
// ]

first(string $key)

获取给定键的第一条消息。如果有错误消息,它将返回string;如果没有错误,它将返回null

例如

if ($emailError = $errors->first('email')) {
    echo $emailError;
}

toArray()

获取ErrorMessage对象的原始底层关联数组。

例如

$messages = $errors->toArray();
// [
//     'email' => [
//         'email' => 'Email is not valid email'
//     ],
//     'password' => [
//         'min' => 'Password minimum 6 character',
//         'regex' => Password must contains capital letters'
//     ]
// ]

toDataBag()

获取ErrorMessage对象的原始底层关联数组作为DataBag实例。

例如

$message = $errors->toDataBag()->filter()->first();

count()

获取错误消息的数量。

has(string $key)

检查给定的键是否有错误。如果有键有错误,它返回true;否则返回false

已验证、有效和无效数据

验证后,数据结果保留在每个验证实例中。例如

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory())->validate([
    'title' => 'Lorem Ipsum',
    'body' => 'Lorem ipsum dolor sit amet ...',
    'published' => null,
    'something' => '-invalid-'
], [
    'title' => 'required',
    'body' => 'required',
    'published' => 'default:1|required|in:0,1',
    'something' => 'required|numeric'
]);

现在您可以获取验证数据、只有有效数据或只有无效数据

$validatedData = $validation->getValidatedData();
// [
//     'title' => 'Lorem Ipsum',
//     'body' => 'Lorem ipsum dolor sit amet ...',
//     'published' => '1' // notice this
//     'something' => '-invalid-'
// ]

$validData = $validation->getValidData();
// [
//     'title' => 'Lorem Ipsum',
//     'body' => 'Lorem ipsum dolor sit amet ...',
//     'published' => '1'
// ]

$invalidData = $validation->getInvalidData();
// [
//     'something' => '-invalid-'
// ]

可用规则

点击显示详细信息。

accepted

此规则下的字段必须是'on''yes''1''true'(字符串"true")或true之一。

after:明天

此规则下的字段必须是一个在给定最小值之后的日期。

参数应该是任何可以被strtotime解析的有效字符串。例如

  • after:下周
  • after:2016-12-31
  • after:2016
  • after:2016-12-31 09:56:02
alpha

此规则下的字段必须是完全由字母字符组成。

alpha_num

此规则下的字段必须是完全由字母数字字符组成。

alpha_dash

此规则下的字段可以包含字母数字字符、连字符和下划线。

alpha_spaces

此规则下的字段可以包含字母字符,以及空格。

any_of:value,value,value

in的变体:这里的值(默认情况下用逗号分隔)都必须在给定的值中。例如:将order => 'name,date'与规则any_of:name,id一起使用将失败验证,因为date不是允许的值之一。分隔符可以通过在规则实例上调用separator()来更改。

use Somnambulist\Components\Validation\Factory;
use Somnambulist\Components\Validation\Rules\AnyOf;

$validation = $factory->validate([
    'field' => 'foo;bar;example'
], [
    'field' => $factory->rule('any_of')->separator(';')->values(['foo', 'bar']),
]);

$validation->passes(); // true if field only contains the values in any_of

in类似,可以通过在规则上调用->strict(true)来执行严格匹配。

此规则对于允许用逗号分隔的数据作为单个参数的API非常有用,例如JsonAPI include、order等。如果源已经是数组,则可以使用array|in:...代替。

array

根据此规则,该字段必须是数组。

before:昨天

根据此规则,该字段必须是在给定最大值之前的一个日期。

这同样适用于after规则。传递任何可以被strtotime解析的内容。

between:min,max

根据此规则,该字段的大小必须在min和max参数之间。值的大小计算方式与minmax规则相同。

您还可以使用此规则验证上传文件的大小。

$validation = $validator->validate([
    'photo' => $_FILES['photo']
], [
    'photo' => 'required|between:1M,2M'
]);
布尔型

根据此规则,该字段必须是布尔型。可接受输入包括truefalse10"1""0"

回调函数

定义一个自定义的回调函数来验证值。此规则不能使用字符串语法进行注册。要使用此规则,您必须使用数组语法,并明确指定callback,或者传递闭包。

$validation = $validator->validate($_POST, [
    'even_number' => [
        'required',
        function ($value) {
            // false = invalid
            return (is_numeric($value) AND $value % 2 === 0);
        },
        'callback' => fn ($v) => is_numeric($v) && $v % 2 === 0,
    ]
]);

您可以设置自定义消息,通过返回一个字符串而不是false来实现。

$validation = $validator->validate($_POST, [
    'even_number' => [
        'required',
        function ($value) {
            if (!is_numeric($value)) {
                return ":attribute must be numeric.";
            }
            if ($value % 2 !== 0) {
                return ":attribute is not even number.";
            }
            
            return true; // always return true if validation passes
        }
    ]
]);

注意:回调闭包绑定到规则实例,允许通过$this访问规则属性。

日期:格式

根据此规则,该字段必须遵循给定格式的有效日期。参数format是可选的,默认格式为Y-m-d

默认/默认值

如果该属性没有值,此默认值将用于验证数据中。

例如,如果您有如下验证:

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory)->validate([
    'enabled' => null
], [
    'enabled' => 'default:1|required|in:0,1'
    'published' => 'default:0|required|in:0,1'
]);

$validation->passes(); // true

// Get the valid/default data
$valid_data = $validation->getValidData();

$enabled = $valid_data['enabled'];
$published = $valid_data['published'];

验证通过,因为enabledpublished的默认值分别设置为10,这是有效的。

不同another_field

same的反义;根据此规则,该字段的值必须与another_field的值不同。

数字:value

正在验证的字段必须是数字,并且必须具有与value精确的长度。

数字之间:min,max

正在验证的字段必须是数字,并且长度必须在给定的minmax之间。

电子邮件

根据此验证,该字段必须是一个有效的电子邮件地址,根据内置的PHP过滤器扩展。

有关详细信息,请参阅FILTER_VALIDATE_EMAIL

存在:table,column (数据库)

根据此验证,该字段必须在给定的表中存在。这并不检查唯一性,只是检查表中至少有一个记录的值和列与提供的值匹配。

要使用此规则,您必须提供一个DBAL连接。这应该通过依赖注入来完成。

例如

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory)->validate([
    'country' => 'GBR'
], [
    'country' => 'exists:countries,id',
]);

$validation->passes(); // true if table countries has a record with id GBR

为了进行更精细的验证,可以通过调用->where()设置闭包来修改底层查询。闭包将传递一个Doctrine\DBAL\Query\QueryBuilder实例。

use Doctrine\DBAL\Query\QueryBuilder;
use Somnambulist\Components\Validation\Factory;
use Somnambulist\Components\Validation\Rules\Exists;

$factory    = new Factory;
$factory->addRule('exists', new Exists($dbalConn));

$validation = $factory->validate([
    'country' => 'GBR'
], [
    'country' => $factory->rule('exists')->table('countries')->column('id')->where(fn (QueryBuilder $qb) => $qb->andWhere('active = 1')),
]);

$validation->passes(); // true if table countries has a record with id GBR and it is active
扩展名:extension_a,extension_b,...

根据此规则,该字段必须以列表中之一对应的扩展名结束。

这在验证给定路径或url的文件类型时很有用。应该使用mimes规则来验证上传。

如果您需要严格的MIME检查,应该实现一个自定义的MimeTypeGuesser,该闭包可以使用服务器端文件检查器,该检查器使用MIME库。

浮点数

根据此规则,该字段必须是一个浮点数,例如:0.0 12.3456等。值可以是一个包含浮点数的字符串。请注意,整数和0(零)将使用此规则失败验证。

in:value_1,value_2,...

根据此规则,该字段必须包含在给定的值列表中。

为了帮助构建字符串规则,In(和NotIn)规则有一个辅助方法。

use Somnambulist\Components\Validation\Factory;
use Somnambulist\Components\Validation\Rules\In;

$factory = new Factory();
$validation = $factory->validate($data, [
    'enabled' => [
        'required',
        In::make([true, 1])
    ]
]);

此规则使用 in_array 进行验证,默认不进行严格检查。如果您需要严格检查,可以像这样调用规则:

use Somnambulist\Components\Validation\Factory;

$factory = new Factory();
$validation = $factory->validate($data, [
    'enabled' => [
        'required',
        $factory->rule('in')->values([true, 1])->strict()
    ]
]);

然后 'enabled' 值应为布尔值 true,或整数 1

整数

正在验证的字段必须为整数。

ip

此规则下的字段必须是有效的 ipv4 或 ipv6 地址。

ipv4

此规则下的字段必须是有效的 ipv4 地址。

ipv6

此规则下的字段必须是有效的 ipv6 地址。

json

此验证下的字段必须是有效的 JSON 字符串。

lowercase

此验证下的字段必须为小写。

max:数字

此规则下的字段大小必须小于或等于给定的数字。值大小以与 min 规则相同的方式计算。

您还可以使用此规则验证上传文件的最大大小。

$validation = $validator->validate([
    'photo' => $_FILES['photo']
], [
    'photo' => 'required|max:2M'
]);
mimes:扩展名_a,扩展名_b,...

正在验证的 $_FILES 项必须具有与列出的扩展名之一对应的 MIME 类型。

这适用于文件扩展名,而不是客户端发送的头部或嵌入的文件类型。如果您需要严格的 MIME 类型验证,建议实现一个使用完整 MIME 类型查找库的 MimeTypeGuesser 并替换内置的 MIME 规则。

可以通过依赖注入和将 MIME 类型猜测器保留为服务来向现有的猜测器添加额外的 MIME 类型。

min:数字

此规则下的字段大小必须大于或等于给定的数字。

对于字符串值,大小对应于字符数。对于整数或浮点值,大小对应于其数值。对于数组,大小对应于数组中的计数。如果您的值是数值字符串,可以使用 numeric 规则将其大小视为数值而不是字符数。

您还可以使用此规则验证上传文件的最小大小。

$validation = $validator->validate([
    'photo' => $_FILES['photo']
], [
    'photo' => 'required|min:1M'
]);
not_in:值_1,值_2,...

此规则下的字段不得包含在给定的值列表中。

此规则也使用 in_array 并可以启用与 In 相同的严格检查。

nullable

此规则下的字段可以是空的。

numeric

此规则下的字段必须是数值。

present

此规则下的字段必须在输入集中,无论值是什么。

prohibited

此规则下的字段不允许。

prohibited_if

如果 another_field 字段提供了任何值,则此规则下的字段不允许。

prohibited_unless

除非 another_field 具有这些值之一,否则此规则下的字段不允许。这是 prohibited_if 的逆。

regex:/your-regex/

此规则下的字段必须匹配给定的正则表达式。注意:如果您需要使用 |,则正则表达式规则必须以数组格式编写,而不是字符串。例如

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory())->validate([
    'field' => 'value'
], [
    'field' => [
        'required',
        'regex' => '/(this|that|value)/'
    ]
])
rejected

此规则下的字段必须具有与拒绝相对应的值,即 0(零)、"0"、false、no、"false"、off。这是 accepted 规则的逆。

required

此验证下的字段必须存在且不是 '空'。

以下是一些示例

对于上传的文件,$_FILES['key']['error'] 必须不是 UPLOAD_ERR_NO_FILE

required_if:another_field,value_1,value_2,...

如果 another_field 字段等于任何值,则此规则下的字段必须存在且不为空。

例如,required_if:something,1,yes,on 将在 something 的值为 1'1''yes''on' 时要求必须存在。

required_unless:another_field,value_1,value_2,...

除非 another_field 字段等于任何值,否则验证下的字段必须存在且不为空。

required_with:field_1,field_2,...

只有当指定的其他字段之一存在时,验证字段必须存在且不为空。

required_without:field_1,field_2,...

只有当指定的其他字段之一不存在时,验证字段必须存在且不为空。

required_with_all:field_1,field_2,...

只有当所有指定的其他字段都存在时,验证字段才必须存在且不为空。

required_without_all:field_1,field_2,...

只有当所有指定的其他字段都不存在时,验证字段才必须存在且不为空。

same:another_field

此规则下的字段值必须与another_field相同。

sometimes

只有当字段存在于输入数据中时,才应对该字段进行验证。例如:field => sometimes|required|email

string

此规则下的字段必须是PHP字符串。

unique:table,column,ignore,ignore_column (数据库)

此验证下的字段在给定表中必须是唯一的。可选:可以忽略一个值,这可以是一个替代列值,如果提供了ignore_column。

要使用此规则,您必须提供一个DBAL连接。这应该通过依赖注入来完成。

例如

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory)->validate([
    'email' => 'foo@example.org'
], [
    'email' => 'email|unique:users,email',
]);

$validation->passes(); // true if table users does not contain the email

忽略当前用户的电子邮件地址

use Somnambulist\Components\Validation\Factory;

$validation = (new Factory)->validate([
    'email' => 'foo@example.org'
], [
    'email' => 'email|unique:users,email,10,id',
]);

$validation->passes(); // true if table users ignoring id 10, does not contain email

为了进行更精细的验证,可以通过调用->where()设置闭包来修改底层查询。闭包将传递一个Doctrine\DBAL\Query\QueryBuilder实例。

use Doctrine\DBAL\Query\QueryBuilder;
use Somnambulist\Components\Validation\Factory;
use Somnambulist\Components\Validation\Rules\Unique;

$factory    = new Factory;
$factory->addRule('unique', new Unique($dbalConn));

$validation = $factory->validate([
    'email' => 'foo@example.org'
], [
    'email' => $factory->rule('unique')->table('users')->column('email')->where(fn (QueryBuilder $qb) => $qb->andWhere('active = 1')),
]);

$validation->passes(); // true if table users does not contain an active email
uploaded_file:min_size,max_size,extension_a,extension_b,...

此规则将验证来自$_FILES的数据。此规则下的字段有以下条件

  • $_FILES['key']['error']必须是UPLOAD_ERR_OKUPLOAD_ERR_NO_FILE。对于UPLOAD_ERR_NO_FILE,可以使用required规则进行验证。
  • 如果指定了最小大小,上传文件的大小不得低于最小大小。
  • 如果指定了最大大小,上传文件的大小不得高于最大大小。
  • 如果指定了文件类型,MIME类型必须是给定类型之一。

对于大小约束,在使用字符串定义时必须同时给出。要指定仅最大大小,请使用工厂方法获取规则,并使用方法链。

以下是一些示例定义和说明

  • uploaded_file:上传文件是可选的。当它不为空时,它必须是ERR_UPLOAD_OK
  • required|uploaded_file:上传文件是必需的,并且必须是ERR_UPLOAD_OK
  • uploaded_file:0,1M:上传文件大小必须在0 - 1MB之间,但上传文件是可选的。
  • required|uploaded_file:0,1M,png,jpeg:上传文件大小必须在0 - 1MB之间,并且MIME类型必须是image/jpegimage/png

对于多文件上传,PHP使用格式_FILES[key][name][0..n+1]请参阅PHP手册以获取更多详细信息)。相反,文件数组会自动重新排序为相关属性的嵌套数组。这允许使用相同的规则对多个文件进行验证。

例如,如果您有以下输入文件

<input type="file" name="photos[]"/>
<input type="file" name="photos[]"/>
<input type="file" name="photos[]"/>

您可以使用以下方式验证所有文件

$validation = (new Factory)->validate($_FILES, [
    'photos.*' => 'uploaded_file:0,2M,jpeg,png'
]);

// or

$validation = (new Factory)->validate($_FILES, [
    'photos.*' => 'uploaded_file|max:2M|mimes:jpeg,png'
]);

或者,如果您有以下输入文件

<input type="file" name="images[profile]"/>
<input type="file" name="images[cover]"/>

您可以像这样验证它

$validation = (new Factory)->validate($_FILES, [
    'images.*' => 'uploaded_file|max:2M|mimes:jpeg,png',
]);

// or

$validation = (new Factory)->validate($_FILES, [
    'images.profile' => 'uploaded_file|max:2M|mimes:jpeg,png',
    'images.cover' => 'uploaded_file|max:5M|mimes:jpeg,png',
]);
uppercase

此验证下的字段必须是大写。

url

此规则下的字段必须是有效的URL格式。默认情况下,它验证常见的格式:any_scheme://...。如果您愿意,可以指定特定的URL方案。

例如

$validation = (new Factory)->validate($inputs, [
    'random_url' => 'url',          // value can be `any_scheme://...`
    'https_url' => 'url:http',      // value must be started with `https://`
    'http_url' => 'url:http,https', // value must be started with `http://` or `https://`
    'ftp_url' => 'url:ftp',         // value must be started with `ftp://`
    'custom_url' => 'url:custom',   // value must be started with `custom://`
]);

rakit、mailto和JDBC不同,不支持。请实现自定义规则或正则表达式进行验证。

uuid

此验证下的字段必须是有效的UUID,而不是nil UUID字符串。

注册/覆盖规则

默认情况下,所有内置规则都会自动注册到Factory实例。其中一些规则是内部必需的(例如requiredcallback);但是,您可以覆盖或添加任意数量的新规则到工厂中,用于您的验证。

这是通过在Factory上访问addRule()方法并添加一个新的规则实例来实现的。

例如,您想创建一个检查数据库中字段可用性的unique验证器。

首先,让我们创建UniqueRule

<?php declare(strict_types=1);

use Somnambulist\Components\Validation\Rule;

class UniqueRule extends Rule
{
    protected string $message = ":attribute :value has been used";
    protected array $fillableParams = ['table', 'column', 'except'];
    protected PDO $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function check($value): bool
    {
        // make sure required parameters exists
        $this->assertHasRequiredParameters(['table', 'column']);

        // getting parameters
        $column = $this->parameter('column');
        $table = $this->parameter('table');
        $except = $this->parameter('except');

        if ($except && $except == $value) {
            return true;
        }

        // do query
        $stmt = $this->pdo->prepare(sprintf('select count(*) as count from %s where %s = :value', $table, $column));
        $stmt->bindParam(':value', $value);
        $stmt->execute();
        $data = $stmt->fetch(PDO::FETCH_ASSOC);

        // true for valid, false for invalid
        return intval($data['count']) === 0;
    }
}

现在要注册这个规则,需要将其添加到Factory实例中

use Somnambulist\Components\Validation\Factory;

$factory = new Factory();
$factory->addRule('unique', new UniqueRule($pdo));

现在您可以使用它这样

$validation = $factory->validate($_POST, [
    'email' => 'email|unique:users,email,exception@mail.com'
]);

在上面的UniqueRule中,属性$message用于无效消息。属性$fillableParams定义了规则参数的顺序和名称。默认情况下,fillParameters将从字符串规则填充在$fillableParams中列出的参数。例如,上面的例子中的unique:users,email,exception@mail.com将设置

$params['table'] = 'users';
$params['column'] = 'email';
$params['except'] = 'exception@mail.com';

如果您希望您的自定义规则接受类似于innot_inuploaded_file规则的参数列表,您需要在您的自定义规则类中覆盖fillParameters(array $params)方法。

注意,我们上面创建的unique规则也可以这样使用

$validation = $factory->validate($_POST, [
    'email' => [
    	'required', 'email',
    	$factory('unique', 'users', 'email')
    ]
]);

您可以通过添加一些方法来设置参数,而不是使用字符串格式来改进上面的UniqueRule

<?php

class UniqueRule extends Rule
{
    public function table(string $table): self
    {
        $this->params['table'] = $table;
        
        return $this;
    }

    public function column(string $column): self
    {
        $this->params['column'] = $column;
        
        return $this;
    }

    public function except(string $value): self
    {
        $this->params['except'] = $value;
        
        return $this;
    }
}

现在配置规则变为

$validation = $factory->validate($_POST, [
    'email' => [
    	'required', 'email',
    	$validator('unique')->table('users')->column('email')->except('exception@mail.com')
    ]
]);

隐式规则

隐式规则是一种规则,如果它无效,则忽略后续规则。例如,如果属性未通过required*规则,则下一个规则将是无效的。为了避免不必要的验证和错误消息,我们将required*规则设置为隐式。

要使您的自定义规则隐式,可以将$implicit属性值设置为true。例如

<?php
use Somnambulist\Components\Validation\Rule;

class YourCustomRule extends Rule
{
    protected bool $implicit = true;
}

修改值

在某些情况下,您可能希望您的自定义规则能够像default/defaults规则一样修改属性值。在当前和下一个规则检查中,将使用您修改的值。

要这样做,您应该在您的自定义规则类中实现Somnambulist\Components\Validation\Rules\Contracts\ModifyValue并创建modifyValue(mixed $value)方法。

例如

<?php

use Somnambulist\Components\Validation\Rule;
use Somnambulist\Components\Validation\Rules\Contracts\ModifyValue;

class YourCustomRule extends Rule implements ModifyValue
{
    public function modifyValue(mixed $value): mixed
    {
        // Do something with $value

        return $value;
    }
}

验证前钩子

您可能在运行验证之前做一些准备工作。例如,uploaded_file规则将解析来自$_FILES(不希望)数组的属性值,使其成为一个有组织的数组。

要这样做,您应该在您的自定义规则类中实现Somnambulist\Components\Validation\Rules\Contracts\BeforeValidate并创建beforeValidate()方法。

例如

<?php

use Somnambulist\Components\Validation\Rule;
use Somnambulist\Components\Validation\Rules\Contracts\BeforeValidate;

class YourCustomRule extends Rule implements BeforeValidate
{
    public function beforeValidate(): void
    {
        $attribute = $this->getAttribute();
        $validation = $this->validation;

        // Do something with $attribute and $validation
        // For example change attribute value
        $validation->setValue($attribute->getKey(), "your custom value");
    }
}

测试

使用PHPUnit 9+进行测试。通过vendor/bin/phpunit运行测试。