jsl/ensure

验证库

0.3.1.1 2022-12-08 09:03 UTC

This package is auto-updated.

Last update: 2024-09-08 23:33:03 UTC


README

安装

使用Composer

composer require jsl/ensure

基本示例

use Jsl\Ensure\Ensure;

$values = [
    'name' => 'Mr Magoo',
    'age'  => 77,
];

$rules = [
    'name' => ['required', 'type' => 'string', 'minSize' => 20],
    'age'  => ['required', 'type' => 'integer', 'minSize' => 80],
];

// Create a new validation instance
$ensure = new Ensure($rules, $values);

// Validate the values against the rules
$result = $ensure->validate();

// Check if the validation was successful
$result->isValid(); // Returns true or false

// If validation failed, get array of validation errors
print_r($result->getErrors());

// Returns:
// 
// Array
// (
//     [name] => Array
//         (
//             [0] => Size of name must be at least 20
//         )
//     [age] => Array
//         (
//             [0] => Size of age must be at least 80
//         )
// )

管理规则

$rules = [
    'name' => ['required', 'type' => 'string', 'minSize' => 20],
    'age'  => ['required', 'type' => 'integer', 'minSize' => 80],
];

// Pass them through the constructor
$ensure = new Ensure($rules, $values);

// Add/replace a rule on an existing instance
// setFieldRule(string $field, string $rule, ...$args)
$ensure->setFieldRule('name', 'minSize', 10);

// Add/replace multiple rules on an existing instance
// setFieldRules(string $field, array $rules)
$ensure->setFieldRules('age', ['type' => 'string', 'minSize' => 70]);

// Remove a field rule
// removeRule(string $field, string $rule)
$ensure->removeFieldRule('age', 'type');

管理值

$values = [
    'name' => 'Mr Magoo',
    'age'  => 77,
];

// Pass them through the constructor
// You can pass $_POST or $_GET directly as well
$ensure = new Ensure($rules, $values);

// Add/replace a value on an existing instance
// seFieldValue(string $field, mixed $value)
$ensure->setFieldValue('name', 'Mrs Magoo');

// Replace all values
// replaceValues(array $values)
$ensure->replaceValues([
    'name' => 'Mrs Magoo', 
    'age' => 70
]);

获取结果 & 错误

// Validate the values against the rules and get the result
$result = $ensure->validate();

// Check if the validation was successful
$result->isValid(); // Returns true or false

// Getting potential errors (returns all failed rules for the fields)
// This will return an array [fieldname => [error1, error2, ...]]
$errors = $result->getErrors();

// To only get the first failed rule, pass "true" to the method
// This will return an array [fieldname => error1, fieldname2 => error1, ...]
$errors = $result->getErrors(true);

管理错误模板

由于您可能不喜欢验证器返回的默认错误模板/消息,因此有几种方法可以自定义它们

// Set the default error template for a specific rule
// This will replace the error template for this rule for all fields
$ensure->setRuleTemplate('rule', '{field} has failed {a:0}');

// Set the default error template for a specific rule for a specific field
// This will only replace the error template for this rule for the specific field
$ensure->setFieldRuleTemplate('field', 'rule', '{field} has failed {a:0}');

// Set a single error template for a specific field, regardless of which rule failed
// Note: This will only replace rule templates, not field rule templates set with setFieldRuleTemplate()
$ensure->setFieldTemplate('field', 'rule', '{field} has failed {a:0}');

// To remove a previously added error template, pass in null as the message
// This works on all the above methods
$ensure->setRuleTemplate('rule', null);

注意:这些方法也适用于 Result 实例,因此您不需要在验证之前在 Ensure 实例上定义它们。

错误模板解释

错误模板是当规则/字段失败时返回的错误消息。它们可以包含将在错误渲染时解决的占位符。

$template = '{field} must be {a:0}';

// {field} will be replaced with the field name
// {a:0} will be replaced with the value from the first argument
// {a:1} will be replaced with the value from the second argument
// ...you can have as many `{a:x}` as there are arguments for the rule

注意:仅当使用 setFieldTemplate() 添加模板时,才会替换 {field} 占位符,因为这是该字段的通用消息,而不是特定规则的。

设置花哨的字段名

当向用户显示错误(特别是在网页上)时,您不希望使用输入名称。为了解决这个问题,您可以设置“花哨”的字段名,这些字段名将在渲染错误模板时使用。

// Set multiple fancy names in one go
$ensure->setFancyNames([
    'name' => 'The name',
    'age' => 'The age',
]);

设置花哨名称的另一种方法是使用规则 as

// Either through the rules array
$rules = [
    'name' => [
        'required',
        'as' => 'A fancy field name', 
    ],
];

// Or adding it as any other rule
$ensure->setFieldRule('fieldname', 'as', 'Fancy field name');

管理验证器

验证器是验证库的核心和灵魂。没有它们,其余部分将相当无意义。

如果您缺少/需要默认集合中未包含的某些验证器,您可以轻松地添加自己的。您可以添加任意多个。

自定义验证器

要添加验证器,您可以使用

// addValidator(string $name, mixed $callback, ?string $template = null)
$ensure->addValidator($name, $callback, $optionalTemplate);
  • $name 将是验证器的规则名称。
  • $callback 是验证器。它可以是许多类型之一的回调。有关更多信息,请参阅下文。
  • $template 是验证器失败时返回的错误模板。它是可选的,但可能很有用。

您的验证器应在通过时返回 true,在失败时返回 false

您可以添加任意多的自定义验证器,并且可以以多种不同的方式创建它们。

验证器可以是可调用的,完全限定的类名,类实例,包含类名/实例和方法的数组。

无论您使用哪种类型的回调,您都可以在添加验证器时将错误模板作为第三个参数传递。但是,为了可读性,我省略了它们。

闭包

添加简单验证器最简单的方法

$ensure->addValidator('between', function ($value, $min, $max): bool {
    return $value >= $min && $value <= $max;
});

完全限定的类名

这要求类使用魔法方法 __invoke()

class BetweenValidator
{
    public function __invoke($value, $min, $max): bool
    {
        return $value >= $min && $value <= $max;;
    }
}

$ensure->addValidator('between', BetweenValidator::class);

// You can also pass it as an instance

$ensure->addValidator('between', new BetweenValidator);

包含完全限定的类名 & 方法的数组

class MyValidators
{
    public function myBetweenMethod($value, $min, $max): bool
    {
        return $value >= $min && $value <= $max;
    }
}

$ensure->addValidator('between', [MyValidators::class, 'myBetweenMethod']);

// You can also use an instance

$ensure->addValidator('between', [new MyValidators, 'myBetweenMethod']);

命名函数

function myBetweenFunc($value, $min, $max): bool
{
    return $value >= $min && $value <= $max;
}

$ensure->addValidator('between', 'myBetweenFunc');

在验证器中使用其他字段值

如果您想在验证器中访问其他字段值,则选项有限。创建一个实现 Jsl\Ensure\Contracts\ValidatorInterface 的类

最简单的方法是扩展 Jsl\Ensure\Abstracts\Validator,它实现了该接口并带有所有必要的方法

想象一下规则

$rule = [
    'theValueField' => [
        'sameAsField' => ['anotherValueField']
    ],
];

实现可能如下所示

class AreFieldsSameValidator extends \Jsl\Ensure\Abstracts\Validator
{
    /**
     * Check if two values are the same
     *
     * @param mixed $value  The value
     * @param string $field The name of the other field
     *
     * @return bool
     */
    public function __invoke($value, $field): bool
    {
        return $value === $this->getValue($field);
    }


    /**
     * For classes implementing the ValidatorInstance,
     * we should add the error template like this
     *
     * @return string
     */
    public function getTemplate(): string
    {
        return '{field} must be the same as {a:0}';
    }
}

$ensure->addValidator('sameAsField', AreFieldsSameValidator::class);

类解析器

默认情况下,Ensure 将以最简单的方式创建任何完全限定的类的实例

return new $className;

这完全正常,除非您想使用一些 IoC/依赖注入容器来实例化您的验证器类并注入一些依赖项。

幸运的是,您可以通过闭包的形式添加自己的类解析器。

它可能看起来像这样

$ensure->setClassResolver(function (string $className) use ($yourContainer) {
    return $yourContainer->has($className)
        ? $yourContainer->get($className)
        : new $className;
});

现在所有验证器类都将使用该闭包进行解析(包括默认验证器)

工厂

到目前为止,我们只讨论了如何向特定的Ensure实例添加错误模板和验证器

通过使用工厂,您可以在更高的层面完成所有这些操作,确保所有新实例继承这些设置

use Jsl\Ensure\EnsureFactory;

$factory = new EnsureFactory;

$factory->setFieldTemplate(...)
    ->setFieldRuleTemplate(...)
    ->setRuleTemplate(...)
    ->setClassResolver(...)
    ->addValidator(...);

// To get an Ensure instance that inherits those settings
$ensure = $factory->create($rules, $data);

现有规则

这些是默认规则
如果您想替换其中任何一个的实现,只需添加一个同名验证器即可

如果规则只有一个参数,您可以直接传递
'rule' => 'arg'
如果规则需要多个参数,可以将它们作为一个数组传递
'rule' => ['arg1', 'arg2']

required - 不能替换 将字段设置为必填。如果不要求且缺失,则将其忽略。如果设置为必填且缺失,则验证失败。
参数: N/A

nullable - 不能替换
将字段设置为可空。如果值为可空且为 null,则跳过任何进一步的规则。如果不可空且值为 null,则验证失败。
参数: N/A

as - 不能替换
为要在错误模板中使用的字段设置一个花哨的名称。
参数: (string $fancyName)
示例: 'as' => 'A fancy name'

alphanum
检查字符串是否只包含字母数字字符
参数: N/A

alpha
检查字符串是否只包含字母字符
参数: N/A

email
检查字符串是否为有效的电子邮件地址
参数: N/A

hex
检查字符串是否为十六进制十进制值
参数: N/A

ip
检查字符串是否为有效的IP地址
参数: N/A

mac
检查字符串是否为有效的MAC地址
参数: N/A

url
检查字符串是否为有效的URL
参数: N/A

size
检查值是否为特定的大小。

  • 如果是数组,则使用 count()
  • 如果是字符串,则使用 strlen()
  • 如果是整数或十进制数,则比较值

参数: (int $size)
示例: 'size' => 10

minSize
检查值的尺寸是否至少为 x

  • 如果是数组,则使用 count()
  • 如果是字符串,则使用 strlen()
  • 如果是整数或十进制数,则比较值

参数: (int $size)
示例: 'minSize' => 5

maxSize
检查值的尺寸是否最多为 x。

  • 如果是数组,则使用 count()
  • 如果是字符串,则使用 strlen()
  • 如果是整数或十进制数,则比较值

参数: (int $size)
示例: 'maxSize' => 30

in
检查值是否存在于值列表中。类似于 in_array()
参数: (array $haystack)
示例: 'in' => [1,2,3,4]

notIn
检查值是否不在值列表中。类似于 in_array() === false
参数: (array $haystack)
示例: 'notIn' => [1,2,3,4]

same
检查值是否与另一个字段的值相同
参数: (string $fieldname)
示例: 'same' => 'nameOfAnotherField'

different
检查值是否与另一个字段的值不同
参数: (string $fieldname)
示例: 'different' => 'nameOfAnotherField'

type
检查值是否为特定类型
参数: (string $type)
示例: 'type' => 'string'
可能的值: string, numeric, integer, decimal, array, boolean

规则集

如果您需要在多个地方使用相同的规则列表,手动在所有这些地方添加它们可能不太有效。

而不是传递包含规则的数组,您可以将它们作为规则集添加到您的主 EnsureFactory-实例

$factory->addRuleset('myRuleset', [
    'name' => [
        'required',
        'minSize' => 5,
    ],
    'age' => [
        'required',
        'minSize' => 18,
    ],
]);

要使用规则集,在创建新的 Ensure-实例时,使用工厂传递规则集名称而不是规则列表

$ensure = $factory->create('myRuleset', $_POST);