amsify42 / php-typestruct
PHP 数据验证包,用于验证数据是否符合定义的结构
Requires
- php: >=7.0.0
- amsify42/php-vars-data: dev-master
Requires (Dev)
- phpunit/phpunit: ^7.0
This package is not auto-updated.
Last update: 2024-09-25 00:48:59 UTC
README
PHP 数据验证包,用于验证数据是否符合定义的结构。
安装
$ composer require amsify42/php-typestruct
目录
1. 简介
这个 PHP 包的目的是使验证变得简单,并且定义的验证结构应该是可读的。传入的数据可以与定义的结构进行验证。
2. 验证
假设我们有以下数组的格式数据。
$data = [ 'id' => 42, 'name' => 'amsify', 'price' => 4.2 ];
并且我们希望对这些数据进行严格验证。现在我们可以定义一个结构,以这个结构来验证数据。
namespace App\TypeStruct; export typestruct Simple { id: int, name: string, price: float }
注意我们定义的结构看起来不完全像 PHP 语法,但它将作为一个结构来验证数据。
$data = [ 'id' => 42, 'name' => 'amsify', 'price' => 4.2 ]; $typeStruct = new Amsify42\TypeStruct\TypeStruct(); $typeStruct->setClass(App\TypeStruct\Simple::class); $result = $typeStruct->validate($data);
注意我们正在创建一个 Amsify42\TypeStruct\TypeStruct 的新实例,传递类型结构类的完整类名 App\TypeStruct\Simple,并将数据传递给 validate() 方法。
validate 方法将返回信息,说明传入的数据是否已通过结构验证,并返回
array(2) {
["is_validated"]=>
bool(true)
["messages"]=>
array(0) {
}
}
is_validated 将根据数据是否验证通过返回 true 或 false,而 messages 将根据未验证的元素返回错误消息的层次结构。
辅助方法
我们还可以使用辅助方法来获取 Amsify42\TypeStruct\TypeStruct 的新实例。
/** * If we have direct of the typestruct file */ $typeStruct = get_typestruct('/path/to/Simple.php'); $result = $typeStruct->validate($data);
/** * For class, we need to pass full class name and 2nd param as 'class' */ $typeStruct = get_typestruct(App\TypeStruct\Simple::class, 'class'); $result = $typeStruct->validate($data);
自动加载
如果类型结构文件的名字和路径符合 psr-4 标准,则类型结构文件的自动加载将自动完成,否则您需要使用带有类型结构实例的 setPath() 方法,该方法期望直接路径的类型结构文件。
选项
使用类型结构实例,我们可以在调用 validate() 方法之前设置以下选项
/** * To tell the typestruct that data we are passing is of type object(stdClass) * default is false */ $typeStruct->isDataObject(true); /** * If true, it will validate and collect all error messages else it will get the first error and exit * Default is true */ $typeStruct->validateFull(false); /** * Default is empty string, you can either pass 'json' or 'xml' based on the type of data you are passing for validation. */ $typeStruct->contentType('json'); /** * Absolute path to the typestruct file */ $typeStruct->setPath('/path/to/Sample.php'); /** * Full class name of typestruct file */ $typeStruct->setClass(App\TypeStruct\Simple::class);
3. 数据
您可以传递以下数据进行验证
Array Object(stdClass) Json XML
正如我们已经在数组示例中看到的那样,让我们看看其他示例
Object(stdClass)
$data = new \stdClass(); $data->id = 42; $data->name = 'amsify'; $data->price = 4.2; $typeStruct = new Amsify42\TypeStruct\TypeStruct(); $typeStruct->isDataObject(true)->setClass(App\TypeStruct\Simple::class); $result = $typeStruct->validate($data);
注意: 我们将 true 传递给 isDataObject() 方法来告诉 TypeStruct 我们传递的数据是 Object(stdClass) 类型。
Json
$jsonData = '{"id":42,"name":"amsify","price":4.2}'; $typeStruct = new TypeStruct(); $typeStruct->contentType('json')->setClass(App\TypeStruct\Simple::class); $result = $typeStruct->validate($jsonData);
XML
$xmlData = '<?xml version="1.0" encoding="UTF-8" ?> <root> <id>42</id> <name>amsify</name> <price>4.2</price> </root>'; $typeStruct = new TypeStruct(); $typeStruct->contentType('xml')->setClass(App\TypeStruct\Simple::class); $result = $typeStruct->validate($xmlData);
注意: 我们调用 contentType() 方法来设置其类型,无论是 Json 还是 XML。
4. 类验证
我们可以通过创建类并扩展它到 Amsify42\TypeStruct\Validator 来进行验证
<?php namespace App\Validators; use Amsify42\TypeStruct\Validator; class Sample extends Validator { protected $tsClass = \App\TypeStruct\Simple::class; protected $data = [ 'id' => 42, 'name' => 'amsify', 'price' => 4.2 ]; }
由于我们已经设置了 TypeStruct 类名和 data 在 protected 属性中。我们可以直接创建这个类的实例并验证
$sample = new \Amsify42\Validators\Sample(); $result = $sample->validate();
您也可以像这样在验证类型结构之前设置数据
$sample = new \Amsify42\Validators\Sample(); $sample->setData(['id' => 42, 'name' => 'amsify']); $result = $sample->validate();
并且我们还可以使用这些扩展 Amsify42\TypeStruct\Validator 的受保护属性
/** * Instead of setting typestruct class name, we can also set direct path of that typestruct file */ protected $tsPath; /** * This will decide whether validation will stop at first error itself or when completing all validation errors. Default is true */ protected $validateFull; /** * You can set to json or xml, default is empty string */ protected $contentType; /** * Tells the typestruct whether the data we setting/passing is of type Object(stdClass) */ protected $isDataObject;
5. 规则
基本
这些是我们可以用作元素的类型。它将检查键是否存在以及其类型。
export typestruct Sample {
id: int,
name: string,
price: float,
points: numeric,
is_active: boolean,
is_public: tinyInt,
items: array
some: any
}
numeric 类似于 PHP 的 is_numeric() 方法,允许数字甚至带有引号。 tinyInt 期望值为 0 或 1,而 any 意味着元素值可以是任何类型。
可选
要使元素可选,我们只需用问号 ? 预先加在其前面即可
export typestruct Sample {
id: int,
name: string,
email: ?string
}
可选也可以应用于子字典
export typestruct Sample {
id: int,
name: string,
email: ?string,
details : ?{
address: string,
pincode: ?int
}
}
长度
我们还可以设置这些类型的长度限制,如下所示
export typestruct Sample { id: int(5), name: string(20), price: float(5.2), is_active: boolean, items: [5] }
数组
以下是我们可以使用的数组类型
items: int[] items: string[] items: float[] items: numeric[] items: boolean[] items: tinyInt[]
作为子元素的扩展
我们还可以使用其他外部 TypeStruct 文件作为元素
namespace App\TypeStruct; export typestruct Category { id: int, name: string }
现在我们可以这样使用 Category 作为类型
namespace App\TypeStruct; use App\TypeStruct\Category; export typestruct Product { id: int, name: string, price: float, active: boolean, category: Category }
或者作为这种类型的数组
namespace App\TypeStruct; use App\TypeStruct\Category; export typestruct Product { id: int, name: string, price: float, active: boolean, categories: Category[] }
更多规则
您还可以这样附加更多规则到输入上
namespace App\TypeStruct; export typestruct User { id: int, name: string, email: string<email> }
如您所见,我们已将规则 email 添加到电子邮件元素中,用于检查有效的电子邮件地址。您可以在元素中添加更多规则,并用点 . 分隔,如下所示
namespace App\TypeStruct; export typestruct User { id: int, url: string<url.checkHost> }
以下是您可以使用的预定义规则
nonEmpty - Check for non empty value just like php method empty() checks email - Check for valid email url - Check if string is a valid url date - Check if string is a valid date
6. 自定义规则
我们还可以编写方法执行自定义验证,但只能在创建类并扩展到 Amsify42\TypeStruct\Validator 时实现
namespace App\TypeStruct; export typestruct Simple { id: int, name: string<checkName>, price: float }
现在我们可以在验证器类中编写 checkName 方法,如下所示
<?php namespace App\Validators; use Amsify42\TypeStruct\Validator; use App\TypeStruct\Simple; class Sample extends Validator { protected $tsClass = Simple::class; protected $data = [ 'id' => 42, 'name' => 'amsify', 'price' => 4.2 ]; public function checkName() { if($this->value() !== 'amsify') { return 'Name should be amsify'; } return true; } }
我们可以使用 $this->name() 来获取当前元素的名称,使用 $this->value() 来获取当前元素的值,该值适用于规则。要获取其他元素的值,我们已经可以从这些自定义规则方法中访问 $this->data
如果您想更轻松地访问自定义方法中的数据,您还可以使用 $this->path() 方法,它将直接从多级路径获取元素。
class Sample extends Validator { ... protected $data = [ 'id' => 42, 'detail' => [ 'more' => [ 'location' => 'City' ] ] ]; public function checkCustom() { echo $this->path('detail.more.location'); /* It will print `City` */ } }
注意: $this->path 预期参数为点(如果多个键)分隔的键名,如果键不存在,则返回 NULL,或者返回目标键值。
7. 复杂示例
namespace App\TypeStruct; use App\TypeStruct\User; export typestruct Sample { name: string, email: string, is_test: tinyInt, id: int, address: { door: string, zip: int }, items: [], user : User, someEl: { key1: string, key2: int, key12: array, records: \App\TypeStruct\Record[], someChild: { key3: boolean, key4: float, someAgainChild: { key5: string, key6: float, key56: boolean[] } } } }
<?php namespace App\TypeStruct; export typestruct User { id: int, name: string, email: string<email> }
<?php namespace App\TypeStruct; export typestruct Record { id: int, name: string }
上述复杂的多级类型结构示例文件将使用以下数据进行验证
[
'name' => 'amsify',
'is_test' => '1',
'user' => [
'id' => 1,
'name' => 'some',
'email' => 'some@site.com'
],
'address' => [
'door' => '12-3-534',
'zip' => 600035
],
'url' => 'https://www.site.com/page.html',
'items' => [1,2,3,4,5,6,7],
'someEl' => [
'key1' => 'val1',
'key2' => 2,
'key12' => [1,2,12],
'records' => [
[
'id' => 1,
'name' => 'r1'
],
[
'id' => 2,
'name' => 'r2'
]
],
'someChild' => [
'key3' => true,
'key4' => 4.01,
'someAgainChild' => [
'key5' => 'val5',
'key6' => 6.4,
'key56' => [true,false,true]
]
]
]
]