一、为什么要做这件事
二、什么是json-schema,为什么用它
三、如何使用json-schema
static $wording = array(
'integer' => 'an integer',
'number' => 'a number',
'boolean' => 'a boolean',
'object' => 'an object',
'array' => 'an array',
'string' => 'a string',
'null' => 'a null',
'any' => NULL, // validation of 'any' is always true so is not needed in message wording
0 => NULL, // validation of a false-y value is always true, so not needed as well
);
各个类型如何表达,主要讲array和object
object 表达式
{
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
}
},
"patternProperties": {
"^[a-zA-Z]+$": {
"类似于properties"
}
},
"additionalProperties": false, //不能有而外的属性
"required": ["firstName", "lastName"] //必须有firstName 和 lastName
}
array 表达式
{
"type": "array",
"items": {
"type": "string" //一个string数组
},
"minItems": 1, //至少有1个
"uniqueItems": true //不能有重复的
}
其中items还可以是一个数组,表示可以有多种类型的元素
"items": [
{
"type": "string"
},
{
"type": "object"
},
]
引用$ref,实现一个属性只用写一次的关键,例如:奖励
{
"id": "http://some.site.somewhere/entry-schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for an fstab entry",
"type": "object",
"required": [ "storage" ],
"properties": {
"storage": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/diskDevice" },
{ "$ref": "#/definitions/diskUUID" },
{ "$ref": "#/definitions/nfs" },
{ "$ref": "#/definitions/tmpfs" }
]
}
},
"definitions": {
"diskDevice": {},
"diskUUID": {},
"nfs": {},
"tmpfs": {}
}
}
也可以写成这样
"$ref": "properties/common.json" //相对路径
"$ref": "http://some.site.somewhere/entry-schema#" //url
其他参数:枚举enum,maximum,minimum,minLength,maxLength 等等
四、如何用json-schema来适应我们多变的验证
现有的需求
a.验证奖励,奖励的物品必须在allItems里面配置了
b.卖出价格必须小于买入价格
c.配置物品关联任务时,验证是否是一个任务
加入特殊参数$function_valid 加入一个函数,来应对不同的需求
例子
validate.php
$data = json_decode(json_encode($data));
// schema
$retriever = new JsonSchema\Uri\UriRetriever;
$schema = $retriever->retrieve('file://' . __DIR__ . '/schema/' . $sJson . '.json');
$refResolver = new JsonSchema\RefResolver($retriever);
//在扫描$ref时同时扫描$function_valid
$refResolver->resolve($schema, 'file://' . __DIR__ . '/schema/' . $sJson . '/', __DIR__ . '/function/');
// Validate
$validator = new JsonSchema\Validator();
$validator->check($data, $schema);
if ($validator->isValid()) {
echo "OK\n";
} else {
$bError = true;
echo "\n======================================== ERROR =======================================\n\n";
foreach ($validator->getErrors() as $error) {
echo sprintf("[%s] %s\n", $error['property'], $error['message']);
}
echo "\n======================================== ERROR =======================================\n\n";
}
方法resolve
public function resolve($schema, $sourceUri = null, $functionDir = null) {
.....
// Resolve $ref first
$this->resolveRef($schema, $sourceUri, $functionDir);
// Resolve $function_valid (Royal Story)
$this->resolveFunctionValid($schema, $functionDir);
.....
}
方法resolveFunctionValid
private function resolveFunctionValid($schema, $functionDir){
if($this->notIncludeFunction) {
return;
}
$function = '$function_valid';
if (empty($schema->$function)) {
return;
}
if(is_string($schema->$function)) {
$schema->$function = $this->fetchFunctionValid($schema->$function, $functionDir);
}elseif(is_array($schema->$function)) {
$lFunction = [];
foreach($schema->$function as $sFunction) {
$lFunction[] = $this->fetchFunctionValid($sFunction, $functionDir);
}
$schema->$function = $lFunction;
}
}
方法fetchFunctionValid
private function fetchFunctionValid($function, $functionDir)
{
if(!isset($this->lFunction[$function])) {
$oFunction = include rtrim($functionDir, '/') . '/' . $function . '.php';
$this->lFunction[$function] = $oFunction;
}
return $this->lFunction[$function];
}
验证过程中加入验证
public function check($value, $schema = null, $path = null, $i = null){
if (is_null($schema)) {
return;
}
if (!is_object($schema)) {
throw new InvalidArgumentException(
'Given schema must be an object in ' . $path
. ' but is a ' . gettype($schema)
);
}
$i = is_null($i) ? "" : $i;
$path = $this->incrementPath($path, $i);
// check function (Royal Story)
$this->validateFunction($value, $schema, $path, $i);
// check special properties
$this->validateCommonProperties($value, $schema, $path);
// check allOf, anyOf, and oneOf properties
$this->validateOfProperties($value, $schema, $path);
// check known types
$this->validateTypes($value, $schema, $path, $i);
}
function例子,验证item的ident
return function ($value) {
if($value === '') {
return true;
}
$lIdent = Validate::getIdentList();
if(strpos($value, ',') !== false){
$value = explode(',', $value);
}
if(is_array($value)) {
foreach($value as $sVal) {
if(!isset($lIdent[$sVal])) {
return $value . ' is not in allItems.php';
}
}
}else{
if(!isset($lIdent[$value])) {
return $value . ' is not in allItems.php';
}
}
return true;
};
五、现在完成的编辑工具 (http://192.168.22.17/validate/index.html )
基于3个开源库
https://github.com/jdorn/json-editor => 提取了js的json验证部分
https://github.com/josdejong/jsoneditor => json的编辑工具
https://github.com/justinrainbow/json-schema => php的json验证
现在完成的功能
a.配置文件中单项的增删改查
b.描述展示
c.实时验证
d.后端验证
六、将来要做成什么样