mizmoz/validate

受React Prop Types启发的验证

1.0.1 2024-09-27 11:21 UTC

README

为PHP 7提供的验证,旨在减少冗余。

随着时间的推移,我们使用过很多不同的验证库,但我对它们都不甚满意。

主要目标是创建一个可以处理复杂项、解析它们并生成自身良好描述的验证器。梦想是创建一个可以处理REST API数据、向用户发送有用的错误消息以及端点的良好描述的验证器。这将是Mizmoz API的界面。

目录

入门

Composer安装

API其实非常新,很可能会有所变化。

composer require mizmoz/validate

保持资源更新

如果你使用IsEmailDisposable验证器,请确保你使用的是最新的可丢弃电子邮件主机名列表。

最佳实践是创建一个cron作业,执行以下更新。

php bin/mizmoz update

在资源文件夹中查看示例cron文件,应放置在/etc/cron.d。

基本验证

Validate::isString()->validate('Hello there!'); // true

Validate::isObject()->validate(new DateTime); // true

Validate::isArray()->validate([]); // true
Validate::isArray()->validate(new ObjectWithToArray); // true

Validate::isOneOf(['on', 'off'])->validate('on'); // true
Validate::isOneOf(['on', 'off'])->validate('oops'); // false

// Validate a value and return it's object 
$result = Validate::isObjectOfType(DateTime::class)->validate('2016-01-01 00:00:00');
$result->isValid(); // true
$result->getValue(); // DateTime 2016-01-01 00:00:00

将验证器解析为新值

$result = Validate::isSame('me')
    ->toValue(\User::current()->userId)
    ->validate($userId);

// get the user id
$userId = $result->getValue();

更复杂和有用的示例

// Validate a set of items
$result = Validate::set([
    'name' => Validate::isString()
        ->setDescription('Subscriber name')
        ->isRequired(),
    'email' => Validate::isEmail()
        ->isRequired(),
    'sendNewsletter' => Validate::isBoolean()
        ->setDescription('Subscribe the email address to the newsletter?')
        ->setDefault(false)
])->validate($_POST);

// Get the sanitised data as an array.
$values = $result->getValue();

验证ACL

虽然目前没有ACL验证器(它们可能以后会提供)。可以在你的应用程序中返回或抛出异常。这样,你可以使用一组标准的异常来处理ACL失败。例如,我们在API上使用验证,并捕获AclException来显示错误消息。

// Add custom validator
ValidateFactory::setHelper('aclOwner', function () {
    // add your custom validator
    return new IsOwner();
});

Validate::aclAuthenticated(\User::current())->validate(\User::get(1));

测试

可以使用ValidatorFactory::mock()方法来模拟任何验证器或解析器。

模拟非常简单,只需通过调用模拟对象的方法来设置返回的Result对象。

# Setup the Mock of isString
$mock = ValidatorFactory::mock('isString')
    ->valid(false)
    ->value('fail-value')
    ->message('boo');
    
Validator::isString()->validate('hello')->isValid(); // false as we've overriden the result

# Reset the container
ValidatorFactory::unMock('isString');

# ... or using the original mock
$mock->unMock();

# You can also make a mock go away after it's called by adding `once()` when setting it up
ValidatorFactory::mock('isString')
    // ... extra setup
    ->once();

获取传递给模拟对象参数

# return an array with the param names and the called method either __constructor, validate or resolve
$mock->getCallArguments();

验证器

IsArray

检查值是否为数组

(new IsArray())
    ->validate([1, 2, 3]); // true

IsArrayOf

检查数组是否只包含提供的值。对于允许多个值的枚举很有用。对于只有一个值,设置IsOneOf

$validate = (new IsArrayOf(['yes', 'no', 'maybe']));
$validate->validate(['yes']); // pass
$validate->validate(['no']); // pass
$validate->validate(['yes', 'no']); // pass
$validate->validate(['definitely']); // fail

IsArrayOfShape

IsShape相同,但$value必须是数组。

IsArrayOfType

检查数组是否只包含特定类型的项

针对单个类型进行检查

$validate = (new IsArrayOfType(
    new IsString()
));

$validate->validate(['Hello']); // pass
$validate->validate([1, 'World']); // fail

针对多个类型进行检查

$validate = (new IsArrayOfType([
    new IsString(),
    new IsInteger(),
]));

$validate->validate(['Hello']); // pass
$validate->validate([1, 'World']); // pass

IsBoolean

检查值是否为布尔类型,即1、'1'、true、'true'、0、'0'、false、'false'。

(new IsBoolean())
    ->validate(true); // true

IsDate

检查值是否是格式正确的有效日期。

$options

  • string format - 值期望的日期格式
  • bool setValueToDateTime - 当日期有效时,将值从结果设置到值。
  • bool strict - 使用严格模式将强制空字符串失败
(new IsDate())
    ->validate('2016-01-01'); // true
    

(new IsDate(['format' => 'd/m/Y']))
    ->validate('01/01/2016'); // true    

IsEmailDisposable

检查值是否是类似guerillamail.com的可丢弃电子邮件地址

(new IsEmailDisposable())
    ->validate('bob@guerillamail.com'); // true

IsEmail

检查值是否是有效的电子邮件地址

(new IsEmail())
    ->validate('support@mizmoz.com'); // true

不允许可丢弃电子邮件地址

(new IsEmail(['allowDisposable' => false]))

IsFilter

过滤器是一个很酷的字符串解析辅助工具。

基本哈希标签及其用法示例

我们使用过滤器将列名映射到状态等事物上。只支持@tag#tag,其他任何内容都将作为纯文本返回过滤器键中。

$validate = new IsFilter([
    '#active|#deleted' => 'userStatus'
]);

$result = $validate->validate('#deleted')->getValue(); // returns ['userStatus' => ['delete'], 'filter' => '']

$model = User::create();
foreach ($result as $column => $value) {
    // we have some magic attached to our models for filtering also but you get the idea of how this can be used ;)
    $model->where($column, $value);
}
$model->fetch();

特殊的:isInteger标记

$validate = new IsFilter([
    '@:isInteger' => 'userId'
]);

$result = $validate->validate('@123 @456')->getValue(); // returns returns ['userId' => [123, 456], 'filter' => '']

过滤值中删除了所有标签

$validate = new IsFilter([
    '#subscribed' => 'userStatus'
]);

$result = $validate->validate('Bob')->getValue(); // returns ['filter' => 'Bob']

// or with tags

$result = $validate->validate('Bob #subscribed')->getValue(); // returns ['userStatus' => ['subscribed'], 'filter' => 'Bob']

当没有标签时使用*作为默认标签

// active is marked as the default
$validate = new IsFilter([
    '#active*|#inactive' => 'status'
]);

$validate->validate('')->getValue(); // returns ['status' => ['active']]

// Or with a filter
$validate->validate('Bob')->getValue(); // returns ['status' => ['active'], 'filter' => 'Bob']

默认标签适用于定义的组,因此您可以拥有其他没有默认值的标签

// active is marked as the default
$validate = new IsFilter([
    '#active*|#inactive' => 'status',
    '#admin|#user' => 'role',
]);

$validate->validate('')->getValue(); // returns ['status' => ['active']]

// Or with a tag
$validate->validate('#admin')->getValue(); // returns ['status' => ['active'], 'role' => ['admin']]

IsInteger

检查值是否为整数

bool $strict - 设置为严格模式以只允许整数,不允许数字字符串或浮点数。

(new IsInteger())
    ->validate(1); // valid

IsNumeric

检查值是否为数字

(new IsNumeric())
    ->validate(1); // valid
    
(new IsNumeric())
    ->validate('100'); // valid

IsObject

IsOneOf

IsOneOfType

IsReCaptcha

验证reCAPTCHA响应

(new IsReCaptcha($secret))
    ->validate($response);

IsRequired

IsSame

IsShape

检查值是否具有特定的形状,有时用例子解释会更简单...

(new IsShape([
    'name' => new IsString(),
    'age' => new IsInteger(),
]))->validate([
    'name' => 'Bob',
    'age' => 45,
]); // valid

形状可以嵌套以验证形状的形状。

使用Validate::set()提供辅助函数以返回形状的优美描述。

$validate = Validate::set([
    'name' => Validate::isString()
        ->setDescription('Full name')
        ->isRequired(),
]);

// return an array describing the set / shape.
$validate->getDescription();

IsString

检查值是否为字符串

(new IsString)
    ->validate('Hello world'); // valid

路线图

待办事项列表

  • 正式化API
  • OpenAPI格式的可选描述:[https://github.com/OAI/OpenAPI-Specification](https://github.com/OAI/OpenAPI-Specification)
  • 将验证器作为ReactJS组件创建。从Chain解析描述以形成组件。
  • 为所有剩余的验证器添加文档...这里列出的验证器还有很多,所以请务必查看src/Validator目录。
  • 添加更多验证器!

任务

  • 为isOneOfType创建描述

通用

允许正匹配或负匹配。可能如下所示

// Positive match
Validate::is()->email();

// Negative match
Validate::not()->email();

验证器

IsPassword

检查字符串是否满足密码的要求。

  • 最小长度
  • 大写字母
  • 小写字母
  • 特殊字符
  • 数字

解析器

ToHash

使用各种技术创建给定数据的散列。MD5、SHA1、password_hash等。

生成API发布版本

在Mizmoz,我们已使用验证器链在JSON中生成我们的API模式。

下一步将是通过比较新旧API端点来创建新版本或发布。这将使我们能够为每个更改创建离散的版本,并有助于通过突出显示每个更改来编制文档。我们甚至可以更进一步,当默认值等更改时突出显示API的破坏性更改。