mirror of
https://github.com/justinrainbow/json-schema.git
synced 2025-01-17 21:28:20 +01:00
cleanup, refactoring, splitted validators, tweaks
This commit is contained in:
parent
81532ea503
commit
b395922ae0
32
README.md
32
README.md
@ -1,6 +1,25 @@
|
||||
# JSON Schema for PHP [![Build status...](https://secure.travis-ci.org/justinrainbow/json-schema.png)](http://travis-ci.org/justinrainbow/json-schema)
|
||||
# JSON Schema for PHP [![Build Status](https://secure.travis-ci.org/digitalkaoz/json-schema.png)](http://travis-ci.org/digitalkaoz/json-schema)
|
||||
|
||||
Documentation can be found at http://jsonschema.readthedocs.org/
|
||||
A PHP Implementation for validating `JSON` Structures against a given `Schema`.
|
||||
|
||||
See [json-schema](http://json-schema.org/) for more details.
|
||||
|
||||
## Installation
|
||||
|
||||
### Library
|
||||
|
||||
$ git clone https://github.com/justinrainbow/json-schema.git
|
||||
|
||||
### Dependencies
|
||||
|
||||
#### via `submodules` (*will use the Symfony ClassLoader Component*)
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
#### via [`composer`](https://github.com/composer/composer) (*will use the Composer ClassLoader*)
|
||||
|
||||
$ wget http://getcomposer.org/composer.phar
|
||||
$ php composer.phar install
|
||||
|
||||
## Usage
|
||||
|
||||
@ -8,19 +27,18 @@ Documentation can be found at http://jsonschema.readthedocs.org/
|
||||
<?php
|
||||
|
||||
$validator = new JsonSchema\Validator();
|
||||
$result = $validator->validate(json_decode($json), json_decode($schema));
|
||||
$validator->check(json_decode($json), json_decode($schema));
|
||||
|
||||
if ($result->valid) {
|
||||
if ($validator->isValid()) {
|
||||
echo "The supplied JSON validates against the schema.\n";
|
||||
} else {
|
||||
echo "JSON does not validate. Violations:\n";
|
||||
foreach ($result->errors as $error) {
|
||||
echo "[{$error['property']}] {$error['message']}\n";
|
||||
foreach ($validator->getErrors() as $error) {
|
||||
echo sprintf("[%s] %s\n",$error['property'], $error['message']);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
|
||||
$ git submodule update --init
|
||||
$ phpunit
|
||||
|
@ -5,7 +5,7 @@
|
||||
"homepage": "https://github.com/justinrainbow/json-schema",
|
||||
"type": "library",
|
||||
"license": "NewBSD",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bruno Prieto Reis",
|
||||
@ -14,6 +14,14 @@
|
||||
{
|
||||
"name": "Justin Rainbow",
|
||||
"email": "justin.rainbow@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Igor Wiedler",
|
||||
"email": "igor@wiedler.ch"
|
||||
},
|
||||
{
|
||||
"name": "Robert Schönthal",
|
||||
"email": "seroscho@googlemail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
|
@ -12,9 +12,15 @@
|
||||
bootstrap="tests/bootstrap.php"
|
||||
verbose="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="JSON Schema Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<testsuites>
|
||||
<testsuite name="JSON Schema Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./src/JsonSchema/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of JsonSchema.
|
||||
*
|
||||
* (c) Bruno Prieto Reis <bruno.p.reis@gmail.com>, Gradua Networks
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace JsonSchema;
|
||||
|
||||
class Undefined
|
||||
{
|
||||
}
|
@ -1,397 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of JsonSchema.
|
||||
*
|
||||
* (c) Bruno Prieto Reis <bruno.p.reis@gmail.com>, Gradua Networks
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace JsonSchema;
|
||||
|
||||
class Validator
|
||||
use JsonSchema\Validator\Schema;
|
||||
use JsonSchema\Validator\Validator as BaseValidator;
|
||||
|
||||
/**
|
||||
* A JsonSchema Validator
|
||||
*
|
||||
* @see README.md
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Validator extends BaseValidator
|
||||
{
|
||||
public $checkMode = self::CHECK_MODE_NORMAL;
|
||||
private $errors = array();
|
||||
|
||||
const CHECK_MODE_NORMAL = 1;
|
||||
const CHECK_MODE_TYPE_CAST = 2;
|
||||
|
||||
/**
|
||||
* Validates a php object against a schema. Both the php object and the schema
|
||||
* are supposed to be a result of a json_decode call.
|
||||
* The validation works as defined by the schema proposal in
|
||||
* http://json-schema.org
|
||||
* validates the given data against the schema and returns an object containing the results
|
||||
* Both the php object and the schema are supposed to be a result of a json_decode call.
|
||||
* The validation works as defined by the schema proposal in http://json-schema.org
|
||||
*
|
||||
* @param \stdClass $instance
|
||||
* @param \stdClass $schema
|
||||
* @return unknown
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function validate($instance, $schema = null)
|
||||
function check($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$this->errors = array();
|
||||
|
||||
$_changing = false;
|
||||
|
||||
// verify passed schema
|
||||
if ($schema) {
|
||||
$this->checkProp($instance, $schema, '', '', $_changing);
|
||||
}
|
||||
// verify "inline" schema
|
||||
$propName = '$schema';
|
||||
if (!$_changing && isset($instance->$propName)) {
|
||||
$this->checkProp($instance, $instance->$propName, '', '', $_changing);
|
||||
}
|
||||
// show results
|
||||
$obj = new \stdClass();
|
||||
$obj->valid = ! ((boolean)count($this->errors));
|
||||
$obj->errors = $this->errors;
|
||||
return $obj;
|
||||
$validator = new Schema($this->checkMode);
|
||||
$validator->check($value, $schema);
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
protected function incrementPath($path, $i)
|
||||
{
|
||||
if ($path !== '') {
|
||||
if (is_int($i)) {
|
||||
$path .= '['.$i.']';
|
||||
} else if ($i == '') {
|
||||
$path .= '';
|
||||
} else {
|
||||
$path .= '.'.$i;
|
||||
}
|
||||
} else {
|
||||
$path = $i;
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function checkArray($value, $schema, $path, $i, $_changing)
|
||||
{
|
||||
//verify items
|
||||
if (isset($schema->items)) {
|
||||
//tuple typing
|
||||
if (is_array($schema->items)) {
|
||||
foreach ($value as $k => $v) {
|
||||
if (array_key_exists($k, $schema->items)) {
|
||||
$this->checkProp($v, $schema->items[$k], $path, $k, $_changing);
|
||||
}
|
||||
else {
|
||||
// aditional array properties
|
||||
if (array_key_exists('additionalProperties', $schema)) {
|
||||
if ($schema->additionalProperties === false) {
|
||||
$this->adderror(
|
||||
$path,
|
||||
'The item '.$i.'['.$k.'] is not defined in the objTypeDef and the objTypeDef does not allow additional properties'
|
||||
);
|
||||
}
|
||||
else {
|
||||
$this->checkProp($v, $schema->additionalProperties, $path, $k, $_changing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//foreach ($value as $k => $v) {
|
||||
// treat when we have more schema definitions than values
|
||||
for ($k = count($value); $k < count($schema->items); $k++) {
|
||||
$this->checkProp(
|
||||
new Undefined(),
|
||||
$schema->items[$k], $path, $k, $_changing
|
||||
);
|
||||
}
|
||||
}
|
||||
// just one type definition for the whole array
|
||||
else {
|
||||
foreach ($value as $k => $v) {
|
||||
$this->checkProp($v, $schema->items, $path, $k, $_changing);
|
||||
}
|
||||
}
|
||||
}
|
||||
// verify number of array items
|
||||
if (isset($schema->minItems) && count($value) < $schema->minItems) {
|
||||
$this->adderror($path,"There must be a minimum of " . $schema->minItems . " in the array");
|
||||
}
|
||||
if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
|
||||
$this->adderror($path,"There must be a maximum of " . $schema->maxItems . " in the array");
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkProp($value, $schema, $path, $i = '', $_changing = false)
|
||||
{
|
||||
if (!is_object($schema)) {
|
||||
return;
|
||||
}
|
||||
$path = $this->incrementPath($path, $i);
|
||||
// verify readonly
|
||||
if ($_changing && $schema->readonly) {
|
||||
$this->adderror($path,'is a readonly field, it can not be changed');
|
||||
}
|
||||
// I think a schema cant be an array, only the items property
|
||||
/*if (is_array($schema)) {
|
||||
if (!is_array($value)) {
|
||||
return array(array('property' => $path,'message' => 'An array tuple is required'));
|
||||
}
|
||||
for ($a = 0; $a < count($schema); $a++) {
|
||||
$this->errors = array_merge(
|
||||
$this->errors,
|
||||
$this->checkProp($value->$a, $schema->$a, $path, $i, $_changing)
|
||||
);
|
||||
return $this->errors;
|
||||
}
|
||||
}*/
|
||||
// if it extends another schema, it must pass that schema as well
|
||||
if (isset($schema->extends)) {
|
||||
$this->checkProp($value, $schema->extends, $path, $i, $_changing);
|
||||
}
|
||||
// verify required values
|
||||
if (is_object($value) && $value instanceOf Undefined) {
|
||||
if (isset($schema->required) && $schema->required) {
|
||||
$this->adderror($path,"is missing and it is required");
|
||||
}
|
||||
} else {
|
||||
// normal verifications
|
||||
$this->errors = array_merge(
|
||||
$this->errors,
|
||||
$this->checkType(isset($schema->type) ? $schema->type : null , $value, $path)
|
||||
);
|
||||
}
|
||||
if (array_key_exists('disallow', $schema)) {
|
||||
$errorsBeforeDisallowCheck = $this->errors;
|
||||
$response = $this->checkType($schema->disallow, $value, $path);
|
||||
if (
|
||||
( count($errorsBeforeDisallowCheck) == count($this->errors) ) &&
|
||||
!count($response)
|
||||
) {
|
||||
$this->adderror($path," disallowed value was matched");
|
||||
}
|
||||
else {
|
||||
$this->errors = $errorsBeforeDisallowCheck;
|
||||
}
|
||||
}
|
||||
//verify the itens on an array and min and max number of items.
|
||||
if (is_array($value)) {
|
||||
if (
|
||||
$this->checkMode == $this::CHECK_MODE_TYPE_CAST &&
|
||||
$schema->type == 'object'
|
||||
) {
|
||||
$this->checkObj(
|
||||
$value,
|
||||
$schema->properties,
|
||||
$path,
|
||||
isset($schema->additionalProperties) ? $schema->additionalProperties : null,
|
||||
$_changing
|
||||
);
|
||||
}
|
||||
$this->checkArray($value, $schema, $path, $i, $_changing);
|
||||
} else if (isset($schema->properties) && is_object($value)) {
|
||||
############ verificar!
|
||||
$this->checkObj(
|
||||
$value,
|
||||
$schema->properties,
|
||||
$path,
|
||||
isset($schema->additionalProperties) ? $schema->additionalProperties : null,
|
||||
$_changing
|
||||
);
|
||||
}
|
||||
// verify a regex pattern
|
||||
if (isset($schema->pattern) && is_string($value) && !preg_match('/'.$schema->pattern.'/', $value)) {
|
||||
$this->adderror($path,"does not match the regex pattern " . $schema->pattern);
|
||||
}
|
||||
// verify maxLength, minLength, maximum and minimum values
|
||||
if (isset($schema->maxLength) && is_string($value) && (strlen($value) > $schema->maxLength)) {
|
||||
$this->adderror($path,"must be at most " . $schema->maxLength . " characters long");
|
||||
}
|
||||
if (isset($schema->minLength) && is_string($value) && strlen($value) < $schema->minLength) {
|
||||
$this->adderror($path,"must be at least " . $schema->minLength . " characters long");
|
||||
}
|
||||
|
||||
if (
|
||||
isset($schema->minimum) &&
|
||||
gettype($value) == gettype($schema->minimum) &&
|
||||
$value < $schema->minimum
|
||||
) {
|
||||
$this->adderror($path,"must have a minimum value of " . $schema->minimum);
|
||||
}
|
||||
if (isset($schema->maximum) && gettype($value) == gettype($schema->maximum) && $value > $schema->maximum) {
|
||||
$this->adderror($path,"must have a maximum value of " . $schema->maximum);
|
||||
}
|
||||
// verify enum values
|
||||
if (isset($schema->enum)) {
|
||||
$found = false;
|
||||
foreach ($schema->enum as $possibleValue) {
|
||||
if ($possibleValue == $value) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$this->adderror($path,"does not have a value in the enumeration " . implode(', ', $schema->enum));
|
||||
}
|
||||
}
|
||||
if (
|
||||
isset($schema->maxDecimal) &&
|
||||
( ($value * pow(10, $schema->maxDecimal)) != (int)($value * pow(10, $schema->maxDecimal)) )
|
||||
) {
|
||||
$this->adderror($path,"may only have " . $schema->maxDecimal . " digits of decimal places");
|
||||
}
|
||||
}
|
||||
|
||||
protected function adderror($path, $message)
|
||||
{
|
||||
$this->errors[] = array(
|
||||
'property' => $path,
|
||||
'message' => $message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take Care: Value is being passed by ref to continue validation with proper format.
|
||||
* @return array
|
||||
*/
|
||||
protected function checkType($type, &$value, $path)
|
||||
{
|
||||
if ($type) {
|
||||
$wrongType = false;
|
||||
if (is_string($type) && $type !== 'any') {
|
||||
if ($type == 'null') {
|
||||
if (!is_null($value)) {
|
||||
$wrongType = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($type == 'number') {
|
||||
if ($this->checkMode == $this::CHECK_MODE_TYPE_CAST) {
|
||||
$wrongType = !$this->checkTypeCast($type, $value);
|
||||
}
|
||||
else if (!in_array(gettype($value), array('integer','double'))) {
|
||||
$wrongType = true;
|
||||
}
|
||||
} else{
|
||||
if (
|
||||
$this->checkMode == $this::CHECK_MODE_TYPE_CAST
|
||||
&& $type == 'integer'
|
||||
) {
|
||||
$wrongType = !$this->checkTypeCast($type, $value);
|
||||
} else if (
|
||||
$this->checkMode == $this::CHECK_MODE_TYPE_CAST
|
||||
&& $type == 'object' && is_array($value)
|
||||
) {
|
||||
$wrongType = false;
|
||||
} else if ($type !== gettype($value)) {
|
||||
$wrongType = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($wrongType) {
|
||||
return array(
|
||||
array(
|
||||
'property' => $path,
|
||||
'message' => gettype($value)." value found, but a ".$type." is required"
|
||||
)
|
||||
);
|
||||
}
|
||||
// Union Types :: for now, just return the message for the last expected type!!
|
||||
if (is_array($type)) {
|
||||
$validatedOneType = false;
|
||||
$errors = array();
|
||||
foreach ($type as $tp) {
|
||||
$error = $this->checkType($tp, $value, $path);
|
||||
if (!count($error)) {
|
||||
$validatedOneType = true;
|
||||
break;
|
||||
} else {
|
||||
$errors[] = $error;
|
||||
$errors = $error;
|
||||
}
|
||||
}
|
||||
if (!$validatedOneType) {
|
||||
return $errors;
|
||||
}
|
||||
} else if (is_object($type)) {
|
||||
$this->checkProp($value, $type, $path);
|
||||
}
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Take Care: Value is being passed by ref to continue validation with proper format.
|
||||
*/
|
||||
protected function checkTypeCast($type, &$value)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'integer':
|
||||
$castValue = (integer)$value;
|
||||
break;
|
||||
case 'number':
|
||||
$castValue = (double)$value;
|
||||
break;
|
||||
default:
|
||||
trigger_error('this method should only be called for the above supported types.');
|
||||
break;
|
||||
}
|
||||
if ((string)$value == (string)$castValue ) {
|
||||
$res = true;
|
||||
$value = $castValue;
|
||||
} else {
|
||||
$res = false;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function checkObj($instance, $objTypeDef, $path, $additionalProp, $_changing)
|
||||
{
|
||||
if ($objTypeDef instanceOf \stdClass) {
|
||||
if (! (($instance instanceOf \stdClass) || is_array($instance)) ) {
|
||||
$this->errors[] = array(
|
||||
'property' => $path,
|
||||
'message' => "an object is required"
|
||||
);
|
||||
}
|
||||
foreach ($objTypeDef as $i => $value) {
|
||||
$value =
|
||||
array_key_exists($i, $instance) ?
|
||||
(is_array($instance) ? $instance[$i] : $instance->$i) :
|
||||
new Undefined();
|
||||
$propDef = $objTypeDef->$i;
|
||||
$this->checkProp($value, $propDef, $path, $i, $_changing);
|
||||
}
|
||||
}
|
||||
// additional properties and requires
|
||||
foreach ($instance as $i => $value) {
|
||||
// verify additional properties, when its not allowed
|
||||
if (!isset($objTypeDef->$i) && ($additionalProp === false) && $i !== '$schema' ) {
|
||||
$this->errors[] = array(
|
||||
'property' => $path,
|
||||
'message' => "The property " . $i . " is not defined in the objTypeDef and the objTypeDef does not allow additional properties"
|
||||
);
|
||||
}
|
||||
// verify requires
|
||||
if ($objTypeDef && isset($objTypeDef->$i) && isset($objTypeDef->$i->requires)) {
|
||||
$requires = $objTypeDef->$i->requires;
|
||||
if (!array_key_exists($requires, $instance)) {
|
||||
$this->errors[] = array(
|
||||
'property' => $path,
|
||||
'message' => "the presence of the property " . $i . " requires that " . $requires . " also be present"
|
||||
);
|
||||
}
|
||||
}
|
||||
$value = is_array($instance) ? $instance[$i] : $instance->$i;
|
||||
|
||||
// To verify additional properties types.
|
||||
if ($objTypeDef && is_object($objTypeDef) && !isset($objTypeDef->$i)) {
|
||||
$this->checkProp($value, $additionalProp, $path, $i);
|
||||
}
|
||||
// Verify inner schema definitions
|
||||
$schemaPropName = '$schema';
|
||||
if (!$_changing && $value && isset($value->$schemaPropName)) {
|
||||
$this->errors = array_merge(
|
||||
$this->errors,
|
||||
checkProp($value, $value->$schemaPropname, $path, $i)
|
||||
);
|
||||
}
|
||||
}
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
||||
}
|
95
src/JsonSchema/Validator/Collection.php
Normal file
95
src/JsonSchema/Validator/Collection.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Collection Validator, validates an array against a given schema
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Collection extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function check($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
// verify minItems
|
||||
if (isset($schema->minItems) && count($value) < $schema->minItems) {
|
||||
$this->addError($path, "There must be a minimum of " . $schema->minItems . " in the array");
|
||||
}
|
||||
// verify maxItems
|
||||
if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
|
||||
$this->addError($path, "There must be a maximum of " . $schema->maxItems . " in the array");
|
||||
}
|
||||
// verify uniqueItems
|
||||
//TODO array_unique doesnt work with objects
|
||||
if (isset($schema->uniqueItems) && array_unique($value) != $value) {
|
||||
$this->addError($path, "There are no duplicates allowed in the array");
|
||||
}
|
||||
|
||||
//verify items
|
||||
if (isset($schema->items)) {
|
||||
$this->validateItems($value, $schema, $path, $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validates the items
|
||||
*
|
||||
* @param array $value
|
||||
* @param \stdClass $schema
|
||||
* @param string $path
|
||||
* @param string $i
|
||||
*/
|
||||
protected function validateItems($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
if (!is_array($schema->items)) {
|
||||
// just one type definition for the whole array
|
||||
foreach ($value as $k => $v) {
|
||||
$initErrors = $this->getErrors();
|
||||
|
||||
//first check if its defined in "items"
|
||||
if (!isset($schema->additionalItems) || $schema->additionalItems === false) {
|
||||
$this->checkUndefined($v, $schema->items, $path, $k);
|
||||
}
|
||||
|
||||
//recheck with "additionalItems" if the first test fails
|
||||
if (count($initErrors) < count($this->getErrors()) && (isset($schema->additionalItems) && $schema->additionalItems !== false)) {
|
||||
$secondErrors = $this->getErrors();
|
||||
$this->checkUndefined($v, $schema->additionalItems, $path, $k);
|
||||
}
|
||||
|
||||
//reset errors if needed
|
||||
if (isset($secondErrors) && count($secondErrors) < $this->getErrors()) {
|
||||
$this->errors = $secondErrors;
|
||||
} elseif (isset($secondErrors) && count($secondErrors) == count($this->getErrors())) {
|
||||
$this->errors = $initErrors;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//defined item type definitions
|
||||
foreach ($value as $k => $v) {
|
||||
if (array_key_exists($k, $schema->items)) {
|
||||
$this->checkUndefined($v, $schema->items[$k], $path, $k);
|
||||
} else {
|
||||
// additional items
|
||||
if (array_key_exists('additionalItems', $schema) && $schema->additionalItems !== false) {
|
||||
$this->checkUndefined($v, $schema->additionalItems, $path, $k);
|
||||
} else {
|
||||
$this->addError(
|
||||
$path,
|
||||
'The item ' . $i . '[' . $k . '] is not defined in the objTypeDef and the objTypeDef does not allow additional properties'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// treat when we have more schema definitions than values
|
||||
for ($k = count($value); $k < count($schema->items); $k++) {
|
||||
$this->checkUndefined(new Undefined(), $schema->items[$k], $path, $k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
src/JsonSchema/Validator/Enum.php
Normal file
29
src/JsonSchema/Validator/Enum.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Enum Validator, validates an element against a given set of possibilities
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Enum extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function check($element, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
foreach ($schema->enum as $possibleValue) {
|
||||
if ($possibleValue == $element) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($found)) {
|
||||
$this->addError($path, "does not have a value in the enumeration " . implode(', ', $schema->enum));
|
||||
}
|
||||
}
|
||||
}
|
33
src/JsonSchema/Validator/Number.php
Normal file
33
src/JsonSchema/Validator/Number.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Number Validator, validates an number against a given schema
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Number extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function check($element, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
//verify minimum
|
||||
if (isset($schema->minimum) && $element < $schema->minimum) {
|
||||
$this->addError($path, "must have a minimum value of " . $schema->minimum);
|
||||
}
|
||||
|
||||
//verify maximum
|
||||
if (isset($schema->maximum) && $element > $schema->maximum) {
|
||||
$this->addError($path, "must have a maximum value of " . $schema->maximum);
|
||||
}
|
||||
|
||||
//verify divisibleBy
|
||||
if (isset($schema->divisibleBy) && $element % $schema->divisibleBy != 0) {
|
||||
$this->addError($path, "is not divisible by " . $schema->divisibleBy);
|
||||
}
|
||||
}
|
||||
}
|
98
src/JsonSchema/Validator/Object.php
Normal file
98
src/JsonSchema/Validator/Object.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Object Validator, validates an object against a given schema
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Object extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
function check($element, $definition = null, $path = null, $additionalProp = null)
|
||||
{
|
||||
// validate the definition properties
|
||||
$this->validateDefinition($element, $definition, $path);
|
||||
|
||||
// additional the element properties
|
||||
$this->validateElement($element, $definition, $path, $additionalProp);
|
||||
}
|
||||
|
||||
/**
|
||||
* validates the element properties
|
||||
*
|
||||
* @param \stdClass $element
|
||||
* @param \stdClass $objectDefinition
|
||||
* @param string $path
|
||||
* @param mixed $additionalProp
|
||||
*/
|
||||
public function validateElement($element, $objectDefinition = null, $path = null, $additionalProp = null)
|
||||
{
|
||||
foreach ($element as $i => $value) {
|
||||
|
||||
$property = $this->getProperty($element, $i, new Undefined());
|
||||
$definition = $this->getProperty($objectDefinition, $i);
|
||||
|
||||
//required property
|
||||
if ($this->getProperty($definition, 'required') && !$property) {
|
||||
$this->addError($path, "the property " . $i . " is required");
|
||||
}
|
||||
|
||||
//no additional properties allowed
|
||||
if ($additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
|
||||
$this->addError($path, "The property " . $i . " is not defined and the definition does not allow additional properties");
|
||||
}
|
||||
|
||||
// additional properties defined
|
||||
if ($additionalProp && !$definition) {
|
||||
$this->checkUndefined($value, $additionalProp, $path, $i);
|
||||
}
|
||||
|
||||
// property requires presence of another
|
||||
$require = $this->getProperty($definition, 'requires');
|
||||
if ($require && !$this->getProperty($element, $require)) {
|
||||
$this->addError($path, "the presence of the property " . $i . " requires that " . $require . " also be present");
|
||||
}
|
||||
|
||||
//normal property verification
|
||||
$this->checkUndefined($value, $definition ? : new \stdClass(), $path, $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validates the definition properties
|
||||
*
|
||||
* @param \stdClass $element
|
||||
* @param \stdClass $objectDefinition
|
||||
* @param string $path
|
||||
*/
|
||||
public function validateDefinition($element, $objectDefinition = null, $path = null)
|
||||
{
|
||||
foreach ($objectDefinition as $i => $value) {
|
||||
$property = $this->getProperty($element, $i, new Undefined());
|
||||
$definition = $this->getProperty($objectDefinition, $i);
|
||||
$this->checkUndefined($property, $definition, $path, $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves a property from an object or array
|
||||
*
|
||||
* @param mixed $element
|
||||
* @param string $property
|
||||
* @param mixed $fallback
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getProperty($element, $property, $fallback = null)
|
||||
{
|
||||
if (is_array($element) /*$this->checkMode == self::CHECK_MODE_TYPE_CAST*/) {
|
||||
return array_key_exists($property, $element) ? $element[$property] : $fallback;
|
||||
} else {
|
||||
return isset($element->$property) ? $element->$property : $fallback;
|
||||
}
|
||||
}
|
||||
}
|
28
src/JsonSchema/Validator/Schema.php
Normal file
28
src/JsonSchema/Validator/Schema.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Schema Validator, validates an element against a given schema
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Schema extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function check($element, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
if ($schema !== null) {
|
||||
// passed schema
|
||||
$this->checkUndefined($element, $schema, '', '');
|
||||
} elseif (isset($element->{$this->inlineSchemaProperty})) {
|
||||
// inline schema
|
||||
$this->checkUndefined($element, $element->{$this->inlineSchemaProperty}, '', '');
|
||||
} else {
|
||||
throw new \InvalidArgumentException('no schema found to verify against');
|
||||
}
|
||||
}
|
||||
}
|
33
src/JsonSchema/Validator/String.php
Normal file
33
src/JsonSchema/Validator/String.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The String Validator, validates an string against a given schema
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class String extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function check($element, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
// verify maxLength
|
||||
if (isset($schema->maxLength) && strlen($element) > $schema->maxLength) {
|
||||
$this->addError($path, "must be at most " . $schema->maxLength . " characters long");
|
||||
}
|
||||
|
||||
//verify minLength
|
||||
if (isset($schema->minLength) && strlen($element) < $schema->minLength) {
|
||||
$this->addError($path, "must be at least " . $schema->minLength . " characters long");
|
||||
}
|
||||
|
||||
// verify a regex pattern
|
||||
if (isset($schema->pattern) && !preg_match('/' . $schema->pattern . '/', $element)) {
|
||||
$this->addError($path, "does not match the regex pattern " . $schema->pattern);
|
||||
}
|
||||
}
|
||||
}
|
90
src/JsonSchema/Validator/Type.php
Normal file
90
src/JsonSchema/Validator/Type.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Type Validator, validates an element against a given type
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Type extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
function check($value = null, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$type = isset($schema->type) ? $schema->type : null;
|
||||
$isValid = true;
|
||||
|
||||
if (is_array($type)) {
|
||||
//TODO refactor
|
||||
$validatedOneType = false;
|
||||
$errors = array();
|
||||
foreach ($type as $tp) {
|
||||
$validator = new Type($this->checkMode);
|
||||
$subSchema = new \stdClass();
|
||||
$subSchema->type = $tp;
|
||||
$validator->check($value, $subSchema, $path, null);
|
||||
$error = $validator->getErrors();
|
||||
|
||||
if (!count($error)) {
|
||||
$validatedOneType = true;
|
||||
break;
|
||||
} else {
|
||||
$errors = $error;
|
||||
}
|
||||
}
|
||||
if (!$validatedOneType) {
|
||||
return $this->addErrors($errors);
|
||||
}
|
||||
} elseif (is_object($type)) {
|
||||
$this->checkUndefined($value, $type, $path);
|
||||
} else {
|
||||
$isValid = $this->validateType($value, $type);
|
||||
}
|
||||
|
||||
if ($isValid === false) {
|
||||
$this->addError($path, gettype($value) . " value found, but a " . $type . " is required");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies that a given value is of a certain type
|
||||
*
|
||||
* @param string $type
|
||||
* @param mixed $value
|
||||
* @return boolean
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function validateType($value, $type)
|
||||
{
|
||||
//mostly the case for inline schema
|
||||
if (!$type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'integer' :
|
||||
return (integer)$value == $value ? true : is_int($value);
|
||||
case 'number' :
|
||||
return is_numeric($value);
|
||||
case 'boolean' :
|
||||
return is_bool($value);
|
||||
case 'object' :
|
||||
return is_object($value);
|
||||
//return ($this::CHECK_MODE_TYPE_CAST == $this->checkMode) ? is_array($value) : is_object($value);
|
||||
case 'array' :
|
||||
return is_array($value);
|
||||
case 'string' :
|
||||
return is_string($value);
|
||||
case 'null' :
|
||||
return is_null($value);
|
||||
case 'any' :
|
||||
return true;
|
||||
default:
|
||||
throw new \InvalidArgumentException((is_object($value) ? 'object' : $value) . ' is a invalid type for ' . $type);
|
||||
}
|
||||
}
|
||||
}
|
107
src/JsonSchema/Validator/Undefined.php
Normal file
107
src/JsonSchema/Validator/Undefined.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Undefined Validator
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
class Undefined extends Validator
|
||||
{
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
function check($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
if (!is_object($schema)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$path = $this->incrementPath($path, $i);
|
||||
|
||||
// check special properties
|
||||
$this->validateCommonProperties($value, $schema, $path);
|
||||
|
||||
// check known types
|
||||
$this->validateTypes($value, $schema, $path, $i);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* validates the value against the types
|
||||
*
|
||||
* @param $value
|
||||
* @param null $schema
|
||||
* @param null $path
|
||||
* @param null $i
|
||||
*/
|
||||
public function validateTypes($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
// check array
|
||||
if (is_array($value)) {
|
||||
$this->checkArray($value, $schema, $path, $i);
|
||||
}
|
||||
|
||||
// check object
|
||||
if (is_object($value) && isset($schema->properties)) {
|
||||
$this->checkObject($value, $schema->properties, $path, isset($schema->additionalProperties) ? $schema->additionalProperties : null);
|
||||
}
|
||||
|
||||
// check string
|
||||
if (is_string($value)) {
|
||||
$this->checkString($value, $schema, $path, $i);
|
||||
}
|
||||
|
||||
// check numeric
|
||||
if (is_numeric($value)) {
|
||||
$this->checkNumber($value, $schema, $path, $i);
|
||||
}
|
||||
|
||||
// check enum
|
||||
if (isset($schema->enum)) {
|
||||
$this->checkEnum($value, $schema, $path, $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validates common properties
|
||||
*
|
||||
* @param $value
|
||||
* @param null $schema
|
||||
* @param null $path
|
||||
* @param null $i
|
||||
*/
|
||||
protected function validateCommonProperties($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
// if it extends another schema, it must pass that schema as well
|
||||
if (isset($schema->extends)) {
|
||||
$this->checkUndefined($value, $schema->extends, $path, $i);
|
||||
}
|
||||
|
||||
// verify required values
|
||||
if (is_object($value) && $value instanceOf Undefined) {
|
||||
if (isset($schema->required) && $schema->required) {
|
||||
$this->addError($path, "is missing and it is required");
|
||||
}
|
||||
} else {
|
||||
$this->checkType($value, $schema, $path);
|
||||
}
|
||||
|
||||
//verify disallowed items
|
||||
if (isset($schema->disallow)) {
|
||||
$initErrors = $this->getErrors();
|
||||
|
||||
$this->checkUndefined($value, $schema->disallow, $path);
|
||||
|
||||
//if no new errors were raised it must be a disallowed value
|
||||
if (count($this->getErrors()) == count($initErrors)) {
|
||||
$this->addError($path, " disallowed value was matched");
|
||||
} else {
|
||||
$this->errors = $initErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
198
src/JsonSchema/Validator/Validator.php
Normal file
198
src/JsonSchema/Validator/Validator.php
Normal file
@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Base Validator, all Validators should extend this class
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
* @author Bruno Prieto Reis <bruno.p.reis@gmail.com>
|
||||
*/
|
||||
abstract class Validator implements ValidatorInterface
|
||||
{
|
||||
protected $checkMode = self::CHECK_MODE_NORMAL;
|
||||
protected $errors = array();
|
||||
protected $inlineSchemaProperty = '$schema';
|
||||
|
||||
const CHECK_MODE_NORMAL = 1;
|
||||
const CHECK_MODE_TYPE_CAST = 2;
|
||||
|
||||
/**
|
||||
* @param int $checkMode
|
||||
*/
|
||||
public function __construct($checkMode = self::CHECK_MODE_NORMAL)
|
||||
{
|
||||
$this->checkMode = $checkMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function addError($path, $message)
|
||||
{
|
||||
$this->errors[] = array(
|
||||
'property' => $path,
|
||||
'message' => $message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function addErrors(array $errors)
|
||||
{
|
||||
$this->errors = array_merge($this->errors, $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return array_unique($this->errors, SORT_REGULAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* bubble down the path
|
||||
*
|
||||
* @param string $path
|
||||
* @param mixed $i
|
||||
* @return string
|
||||
*/
|
||||
protected function incrementPath($path, $i)
|
||||
{
|
||||
if ($path !== '') {
|
||||
if (is_int($i)) {
|
||||
$path .= '[' . $i . ']';
|
||||
} else if ($i == '') {
|
||||
$path .= '';
|
||||
} else {
|
||||
$path .= '.' . $i;
|
||||
}
|
||||
} else {
|
||||
$path = $i;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* validates an array
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkArray($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new Collection($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* validates an object
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkObject($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new Object($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* validates the type of a property
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkType($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new Type($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a undefined element
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkUndefined($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new Undefined($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a string element
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkString($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new String($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a number element
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkNumber($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new Number($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a enum element
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $schema
|
||||
* @param mixed $path
|
||||
* @param mixed $i
|
||||
*/
|
||||
protected function checkEnum($value, $schema = null, $path = null, $i = null)
|
||||
{
|
||||
$validator = new Enum($this->checkMode);
|
||||
$validator->check($value, $schema, $path, $i);
|
||||
|
||||
$this->addErrors($validator->getErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* {inheritDoc}
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
return !!!$this->getErrors();
|
||||
}
|
||||
}
|
51
src/JsonSchema/Validator/ValidatorInterface.php
Normal file
51
src/JsonSchema/Validator/ValidatorInterface.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Validator;
|
||||
|
||||
/**
|
||||
* The Validator Interface
|
||||
*
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
*/
|
||||
interface ValidatorInterface
|
||||
{
|
||||
/**
|
||||
* returns all collected errors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getErrors();
|
||||
|
||||
/**
|
||||
* adds errors to this validator
|
||||
*
|
||||
* @param array $errors
|
||||
*/
|
||||
function addErrors(array $errors);
|
||||
|
||||
/**
|
||||
* adds an error
|
||||
*
|
||||
* @param $path
|
||||
* @param $message
|
||||
*/
|
||||
function addError($path, $message);
|
||||
|
||||
/**
|
||||
* checks if the validator has not raised errors
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function isValid();
|
||||
|
||||
/**
|
||||
* invokes the validation of an element
|
||||
*
|
||||
* @abstract
|
||||
* @param mixed $value
|
||||
* @param null $schema
|
||||
* @param null $path
|
||||
* @param null $i
|
||||
*/
|
||||
function check($value, $schema = null, $path = null, $i = null);
|
||||
}
|
@ -25,7 +25,7 @@ class AdditionalPropertiesTest extends BaseTestCase
|
||||
array(
|
||||
array(
|
||||
'property' => '',
|
||||
'message' => 'The property additionalProp is not defined in the objTypeDef and the objTypeDef does not allow additional properties'
|
||||
'message' => 'The property additionalProp is not defined and the definition does not allow additional properties'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -51,7 +51,22 @@ class ArraysTest extends BaseTestCase
|
||||
"array":{"type":"array"}
|
||||
}
|
||||
}'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'{
|
||||
"array":[1,2,"a"]
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"array":{
|
||||
"type":"array",
|
||||
"items":{"type":"number"},
|
||||
"additionalItems": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}'
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -9,36 +9,27 @@ abstract class BaseTestCase extends \PHPUnit_Framework_TestCase
|
||||
/**
|
||||
* @dataProvider getInvalidTests
|
||||
*/
|
||||
public function testInvalidCases($input, $schema, $checkMode = null, $errors = array())
|
||||
public function testInvalidCases($input, $schema, $checkMode = Validator::CHECK_MODE_NORMAL, $errors = array())
|
||||
{
|
||||
if (null === $checkMode) {
|
||||
$checkMode = Validator::CHECK_MODE_NORMAL;
|
||||
}
|
||||
$validator = new Validator($checkMode);
|
||||
|
||||
$validator = new Validator();
|
||||
$validator->checkMode = $checkMode;
|
||||
$validator->check(json_decode($input), json_decode($schema));
|
||||
|
||||
$result = $validator->validate(json_decode($input), json_decode($schema));
|
||||
if (array() !== $errors) {
|
||||
$this->assertEquals($errors, $result->errors, var_export($result, true));
|
||||
$this->assertEquals($errors, $validator->getErrors(), print_r($validator->getErrors(),true));
|
||||
}
|
||||
$this->assertFalse($result->valid, var_export($result, true));
|
||||
$this->assertFalse($validator->isValid(), print_r($validator->getErrors(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidTests
|
||||
*/
|
||||
public function testValidCases($input, $schema, $checkMode = null)
|
||||
public function testValidCases($input, $schema, $checkMode = Validator::CHECK_MODE_NORMAL)
|
||||
{
|
||||
if (null === $checkMode) {
|
||||
$checkMode = Validator::CHECK_MODE_NORMAL;
|
||||
}
|
||||
$validator = new Validator($checkMode);
|
||||
|
||||
$validator = new Validator();
|
||||
$validator->checkMode = $checkMode;
|
||||
|
||||
$result = $validator->validate(json_decode($input), json_decode($schema));
|
||||
$this->assertTrue($result->valid, var_export($result, true));
|
||||
$validator->check(json_decode($input), json_decode($schema));
|
||||
$this->assertTrue($validator->isValid(), print_r($validator->getErrors(), true));
|
||||
}
|
||||
|
||||
abstract public function getValidTests();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace JsonSchema\Tests;
|
||||
|
||||
class MaxDecimalTest extends BaseTestCase
|
||||
class DivisibleByTest extends BaseTestCase
|
||||
{
|
||||
public function getInvalidTests()
|
||||
{
|
||||
@ -14,7 +14,7 @@ class MaxDecimalTest extends BaseTestCase
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"value":{"type":"number","maxDecimal":3}
|
||||
"value":{"type":"number","divisibleBy":3}
|
||||
}
|
||||
}'
|
||||
)
|
||||
@ -26,12 +26,12 @@ class MaxDecimalTest extends BaseTestCase
|
||||
return array(
|
||||
array(
|
||||
'{
|
||||
"value":5.633
|
||||
"value":6
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"value":{"type":"number","maxDecimal":3}
|
||||
"value":{"type":"number","divisibleBy":3}
|
||||
}
|
||||
}'
|
||||
)
|
@ -20,7 +20,7 @@ class MinItemsMaxItemsTest extends BaseTestCase
|
||||
),
|
||||
array(
|
||||
'{
|
||||
"value":2,2,5,8,5]
|
||||
"value":[2,2,5,8,5]
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
|
@ -34,7 +34,7 @@ class PhpTypeCastModeTest extends BaseTestCase
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"a":{"type":"integer","maximum":8}
|
||||
"a":{"type":"integer","maximum":"8"}
|
||||
}
|
||||
}'
|
||||
)
|
||||
@ -46,19 +46,31 @@ class PhpTypeCastModeTest extends BaseTestCase
|
||||
return array(
|
||||
array(
|
||||
'{
|
||||
"a":"9"
|
||||
"a":"7"
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"a":{"type":"integer","maximum":8.0}
|
||||
"a":{"type":"integer","maximum":8}
|
||||
}
|
||||
}',
|
||||
Validator::CHECK_MODE_TYPE_CAST
|
||||
),
|
||||
array(
|
||||
'{
|
||||
"a":"9"
|
||||
"a":1.337
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"a":{"type":"number","maximum":8.0}
|
||||
}
|
||||
}',
|
||||
Validator::CHECK_MODE_TYPE_CAST
|
||||
),
|
||||
array(
|
||||
'{
|
||||
"a":"9e42"
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
|
39
tests/JsonSchema/Tests/ReadOnlyTest.php
Normal file
39
tests/JsonSchema/Tests/ReadOnlyTest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Tests;
|
||||
|
||||
class ReadOnlyTest extends BaseTestCase
|
||||
{
|
||||
public function getInvalidTests()
|
||||
{
|
||||
//is readonly really required?
|
||||
return array(
|
||||
array(
|
||||
'{ "number": [] }',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"number":{"type":"string","readonly":true}
|
||||
}
|
||||
}'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function getValidTests()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'{
|
||||
"number": "1.4"
|
||||
}',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"number":{"type":"string","readonly":true}
|
||||
}
|
||||
}'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -32,6 +32,15 @@ class RequiredPropertyTest extends BaseTestCase
|
||||
"number":{"type":"string","required":true}
|
||||
}
|
||||
}'
|
||||
),
|
||||
array(
|
||||
'{}',
|
||||
'{
|
||||
"type":"object",
|
||||
"properties":{
|
||||
"number":{"type":"string"}
|
||||
}
|
||||
}'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
39
tests/JsonSchema/Tests/UniqueItemsTest.php
Normal file
39
tests/JsonSchema/Tests/UniqueItemsTest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace JsonSchema\Tests;
|
||||
|
||||
class UniqueItemsTest extends BaseTestCase
|
||||
{
|
||||
public function getInvalidTests()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'[1,2,2]',
|
||||
'{
|
||||
"type":"array",
|
||||
"uniqueItems": true
|
||||
}'
|
||||
),
|
||||
/* array(
|
||||
'[{"a":"b"},{"a":"c"},{"a":"b"}]',
|
||||
'{
|
||||
"type":"array",
|
||||
"uniqueItems": true
|
||||
}'
|
||||
)*/
|
||||
);
|
||||
}
|
||||
|
||||
public function getValidTests()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'[1,2,3]',
|
||||
'{
|
||||
"type":"array",
|
||||
"uniqueItems": true
|
||||
}'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,8 +1,17 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../vendor/symfony/Component/ClassLoader/UniversalClassLoader.php';
|
||||
if(is_readable(__DIR__.'/../vendor/.composer/autoload.php')) {
|
||||
//composer
|
||||
$loader = require_once(__DIR__.'/../vendor/.composer/autoload.php');
|
||||
$loader->add('JsonSchema\Tests', __DIR__);
|
||||
$loader->register();
|
||||
|
||||
$loader = new Symfony\Component\ClassLoader\UniversalClassLoader();
|
||||
$loader->registerNamespace('JsonSchema', __DIR__.'/../src');
|
||||
$loader->registerNamespace('JsonSchema\Tests', __DIR__);
|
||||
$loader->register();
|
||||
} elseif(is_readable(__DIR__.'/../vendor/symfony/Component/ClassLoader/UniversalClassLoader.php')) {
|
||||
//submodule
|
||||
require_once __DIR__.'/../vendor/symfony/Component/ClassLoader/UniversalClassLoader.php';
|
||||
|
||||
$loader = new Symfony\Component\ClassLoader\UniversalClassLoader();
|
||||
$loader->registerNamespace('JsonSchema', __DIR__.'/../src');
|
||||
$loader->registerNamespace('JsonSchema\Tests', __DIR__);
|
||||
$loader->register();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user