Skip to content
Browse files

Validation errors are no longer thrown as exceptions. The validate me…

…thod now returns a boolean and the validation errors can be retrieved using getValidationErrors.
  • Loading branch information...
1 parent 555d719 commit 6c6a276204c7f47608327aa36bdab6eff8aa4b92 @maikg committed Feb 29, 2012
View
12 README.md
@@ -56,11 +56,8 @@ $schema = new Schema(Schema::TYPE_OBJECT, function($obj) {
});
});
-try {
- $schema->validate($json);
-}
-catch (\JSON\Schema\ValidationException $e) {
- // Handle the exception.
+if (!$schema->validate($json)) {
+ var_dump($schema->getValidationErrors());
}
@@ -70,6 +67,8 @@ $schema = new Schema(Schema::TYPE_OBJECT, function($obj) {
// When specifying a custom validation when using this syntax, it is called always
// whenever the actual type matches one of the expected types, except when the actual
// type is NULL.
+ //
+ // This currently only works for "flat" types: string, number, boolean and NULL.
$obj->includes('name', Schema::TYPE_STRING | Schema::TYPE_NULL, function($str) {
// Only called when $root['name'] is a string.
});
@@ -85,4 +84,5 @@ $schema = new Schema(Schema::TYPE_OBJECT, function($obj) {
* Add more validation methods for the array type:
* Specify the expected amount of items in the array (either exact or through a minimum and/or maximum).
* Specify the expected type/value at a certain index.
-* Better error messages.
+* Better error messages.
+* Extend multiple type support to aggregate types as well.
View
11 lib/JSON/Schema.php
@@ -35,6 +35,15 @@ public function validate($data) {
$data = json_decode($data, true);
}
- $this->root_desc->validate($data);
+ $this->root_desc->clearValidationErrors();
+
+ $this->root_desc->validate('root', $data);
+
+ return (count($this->getValidationErrors()) == 0);
+ }
+
+
+ public function getValidationErrors() {
+ return $this->root_desc->getValidationErrors();
}
}
View
27 lib/JSON/Schema/ArrayDesc.php
@@ -10,14 +10,15 @@ public function all($type, \Closure $describe = NULL) {
}
- public function validate($data) {
+ public function validate($node, $data) {
if (!$this->validateType($data)) {
- throw new ValidationException("Expected an array.");
+ $this->addValidationError(new ValidationError($node, "Expected an array."));
+ return;
}
if ($this->all_desc !== NULL) {
foreach ($data as $value) {
- $this->all_desc->validate($value);
+ $this->all_desc->validate($node, $value);
}
}
}
@@ -26,4 +27,24 @@ public function validate($data) {
private function validateType($data) {
return (is_array($data) && (count($data) == 0 || array_keys($data) === range(0, count($data) - 1)));
}
+
+
+ public function getValidationErrors() {
+ $validation_errors = parent::getValidationErrors();
+
+ if ($this->all_desc !== NULL) {
+ $validation_errors = array_merge($validation_errors, $this->all_desc->getValidationErrors());
+ }
+
+ return $validation_errors;
+ }
+
+
+ public function clearValidationErrors() {
+ parent::clearValidationErrors();
+
+ if ($this->all_desc !== NULL) {
+ $this->all_desc->clearValidationErrors();
+ }
+ }
}
View
20 lib/JSON/Schema/Desc.php
@@ -2,5 +2,23 @@
namespace JSON\Schema;
abstract class Desc {
- abstract public function validate($data);
+ private $validation_errors = array();
+
+
+ abstract public function validate($node, $data);
+
+
+ public function getValidationErrors() {
+ return $this->validation_errors;
+ }
+
+
+ protected function addValidationError(ValidationError $error) {
+ $this->validation_errors[] = $error;
+ }
+
+
+ public function clearValidationErrors() {
+ $this->validation_errors = array();
+ }
}
View
48 lib/JSON/Schema/ObjectDesc.php
@@ -22,46 +22,76 @@ public function optional($key_name, $child_type, \Closure $describe = NULL) {
}
- public function validate($data) {
+ public function validate($node, $data) {
if (!$this->validateType($data)) {
- throw new ValidationException("Expected an object.");
+ $this->addValidationError(new ValidationError($node, "Expected an object."));
+ return;
}
foreach ($this->excludes as $key_name) {
if (array_key_exists($key_name, $data)) {
- throw new ValidationException(sprintf("Expected '%s' to not be present.", $key_name));
+ $this->addValidationError(new ValidationError($node, sprintf("Expected '%s' to not be present.", $key_name)));
}
}
foreach ($this->includes as $key_name => $desc) {
if (!array_key_exists($key_name, $data)) {
- throw new ValidationException(sprintf("Expected '%s' to be present.", $key_name));
+ $this->addValidationError(new ValidationError($node, sprintf("Expected '%s' to be present.", $key_name)));
+ continue;
}
- $this->validateValueForKey($desc, $data, $key_name);
+ $this->validateValueForKey($desc, sprintf("%s.%s", $node, $key_name), $data, $key_name);
}
foreach ($this->optional as $key_name => $desc) {
if (!array_key_exists($key_name, $data)) {
continue;
}
- $this->validateValueForKey($desc, $data, $key_name);
+ $this->validateValueForKey($desc, sprintf("%s.%s", $node, $key_name), $data, $key_name);
}
}
- private function validateValueForKey(Desc $desc, $data, $key_name) {
+ private function validateValueForKey(Desc $desc, $node, $data, $key_name) {
if (is_object($data)) {
- $desc->validate($data->$key_name);
+ $desc->validate($node, $data->$key_name);
}
else {
- $desc->validate($data[$key_name]);
+ $desc->validate($node, $data[$key_name]);
}
}
private function validateType($data) {
return (is_object($data) || is_array($data));
}
+
+
+ public function getValidationErrors() {
+ $validation_errors = parent::getValidationErrors();
+
+ foreach ($this->includes as $desc) {
+ $validation_errors = array_merge($validation_errors, $desc->getValidationErrors());
+ }
+
+ foreach ($this->optional as $desc) {
+ $validation_errors = array_merge($validation_errors, $desc->getValidationErrors());
+ }
+
+ return $validation_errors;
+ }
+
+
+ public function clearValidationErrors() {
+ parent::clearValidationErrors();
+
+ foreach ($this->includes as $desc) {
+ $desc->clearValidationErrors();
+ }
+
+ foreach ($this->optional as $desc) {
+ $desc->clearValidationErrors();
+ }
+ }
}
View
7 lib/JSON/Schema/PrimitiveDesc.php
@@ -22,15 +22,16 @@ public function setValueDescription(\Closure $describe) {
}
- public function validate($data) {
+ public function validate($node, $data) {
if (!$this->validateType($data)) {
- throw new ValidationException("Got unexpected type.");
+ $this->addValidationError(new ValidationError($node, "Got unexpected type."));
+ return;
}
if ($this->describe !== NULL && $this->getType($data) != Schema::TYPE_NULL) {
$describe = $this->describe;
if (!$describe($data)) {
- throw new ValidationException("Value doesn't match description.");
+ $this->addValidationError(new ValidationError($node, "Value doesn't match description."));
}
}
}
View
19 lib/JSON/Schema/ValidationError.php
@@ -0,0 +1,19 @@
+<?PHP
+namespace JSON\Schema;
+
+class ValidationError {
+ public function __construct($node, $message) {
+ $this->node = $node;
+ $this->message = $message;
+ }
+
+
+ public function getNode() {
+ return $this->node;
+ }
+
+
+ public function getMessage() {
+ return $this->message;
+ }
+}
View
4 lib/JSON/Schema/ValidationException.php
@@ -1,4 +0,0 @@
-<?PHP
-namespace JSON\Schema;
-
-class ValidationException extends \Exception {}
View
267 test/testsuite/JSON/Schema/Tests/SchemaTest.php
@@ -5,16 +5,28 @@
use JSON\Schema\ValidationException;
class SchemaTest extends \PHPUnit_Framework_TestCase {
+ private function assertValid(Schema $schema, $data) {
+ $this->assertTrue($schema->validate($data));
+ $this->assertCount(0, $schema->getValidationErrors());
+ }
+
+
+ private function assertNotValid(Schema $schema, $data, $validation_error_count) {
+ $this->assertFalse($schema->validate($data));
+ $this->assertCount($validation_error_count, $schema->getValidationErrors());
+ }
+
+
public function testEmptyArray() {
$schema = new Schema(Schema::TYPE_ARRAY);
- $schema->validate(array());
+ $this->assertValid($schema, array());
}
public function testEmptyObject() {
$schema = new Schema(Schema::TYPE_OBJECT);
- $schema->validate(array());
- $schema->validate(new \stdClass);
+ $this->assertValid($schema, array());
+ $this->assertValid($schema, new \stdClass);
}
@@ -43,28 +55,16 @@ public function testStrings() {
});
$data = array('string', 'value', '');
- $schema->validate($data);
-
- try {
- $data = array('string', 14);
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array('string', NULL);
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array('string', false);
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array('string', 14);
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array('string', NULL);
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array('string', false);
+ $this->assertNotValid($schema, $data, 1);
}
@@ -76,14 +76,10 @@ public function testStringsWithCustomValidation() {
});
$data = array('asdf', 'jkl;');
- $schema->validate($data);
-
- try {
- $data = array('asdf', 'jkl');
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array('asdf', 'jkl');
+ $this->assertNotValid($schema, $data, 1);
}
@@ -93,14 +89,10 @@ public function testNumbers() {
});
$data = array(15, 15.4);
- $schema->validate($data);
-
- try {
- $data = array(15.4, '15');
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(15.4, '15');
+ $this->assertNotValid($schema, $data, 1);
}
@@ -112,14 +104,10 @@ public function testNumbersWithCustomValidation() {
});
$data = array(10.1, 11);
- $schema->validate($data);
-
- try {
- $data = array(10.1, 10);
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(10.1, 10);
+ $this->assertNotValid($schema, $data, 1);
}
@@ -129,21 +117,13 @@ public function testBooleans() {
});
$data = array(true, false);
- $schema->validate($data);
-
- try {
- $data = array(true, 1);
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array(true, 'true');
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(true, 1);
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array(true, 'true');
+ $this->assertNotValid($schema, $data, 1);
}
@@ -153,21 +133,13 @@ public function testNull() {
});
$data = array(NULL);
- $schema->validate($data);
-
- try {
- $data = array(NULL, false);
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array(NULL, 'NULL');
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(NULL, false);
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array(NULL, 'NULL');
+ $this->assertNotValid($schema, $data, 1);
}
@@ -185,34 +157,26 @@ public function testSimpleObject() {
'first_name' => 'Maik',
'last_name' => 'Gosenshuis'
);
- $schema->validate($data);
+ $this->assertValid($schema, $data);
$data = array(
'first_name' => 'Maik',
'last_name' => 'Gosenshuis',
'date_of_birth' => '1986-09-02'
);
- $schema->validate($data);
-
- try {
- $data = array(
- 'first_name' => 'Maik',
- 'last_name' => 'Gosenshuis',
- 'name' => 'Maik Gosenshuis'
- );
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array(
- 'first_name' => 'Maik'
- );
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(
+ 'first_name' => 'Maik',
+ 'last_name' => 'Gosenshuis',
+ 'name' => 'Maik Gosenshuis'
+ );
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array(
+ 'first_name' => 'Maik'
+ );
+ $this->assertNotValid($schema, $data, 1);
}
@@ -234,41 +198,29 @@ public function testNestedAggregates() {
),
'nicknames' => array()
);
- $schema->validate($data);
-
- try {
- $data = array(
- 'name' => 'Maik Gosenshuis',
- 'nicknames' => array()
- );
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array(
+ $this->assertValid($schema, $data);
+
+ $data = array(
+ 'name' => 'Maik Gosenshuis',
+ 'nicknames' => array()
+ );
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array(
+ 'first' => 'Maik',
+ 'last' => 'Gosenshuis',
+ 'nicknames' => array()
+ );
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array(
+ 'name' => array(
'first' => 'Maik',
- 'last' => 'Gosenshuis',
- 'nicknames' => array()
- );
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
-
- try {
- $data = array(
- 'name' => array(
- 'first' => 'Maik',
- 'last' => 'Gosenshuis'
- ),
- 'nicknames' => ''
- );
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ 'last' => 'Gosenshuis'
+ ),
+ 'nicknames' => ''
+ );
+ $this->assertNotValid($schema, $data, 1);
}
@@ -280,24 +232,25 @@ public function testMultipleTypes() {
$data = array(
'name' => 'Maik Gosenshuis'
);
- $schema->validate($data);
+ $this->assertValid($schema, $data);
$data = array(
'name' => 15
);
- $schema->validate($data);
+ $this->assertValid($schema, $data);
$data = array(
'name' => NULL
);
- $schema->validate($data);
-
- try {
- $data = array();
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(
+ 'name' => true
+ );
+ $this->assertNotValid($schema, $data, 1);
+
+ $data = array();
+ $this->assertNotValid($schema, $data, 1);
}
@@ -311,21 +264,17 @@ public function testMultipleTypesWithCustomValidation() {
$data = array(
'name' => 'Maik'
);
- $schema->validate($data);
+ $this->assertValid($schema, $data);
$data = array(
'name' => NULL
);
- $schema->validate($data);
-
- try {
- $data = array(
- 'name' => ''
- );
- $schema->validate($data);
- $this->fail("Expected ValidationException to be thrown.");
- }
- catch (ValidationException $e) {}
+ $this->assertValid($schema, $data);
+
+ $data = array(
+ 'name' => ''
+ );
+ $this->assertNotValid($schema, $data, 1);
}
@@ -345,7 +294,7 @@ public function testConvertsJSONStrings() {
$schema = new Schema(Schema::TYPE_OBJECT);
$json_string = "{}";
- $schema->validate($json_string);
+ $this->assertValid($schema, $json_string);
}
@@ -357,7 +306,7 @@ public function testSupportsPHPObjects() {
$json = new \stdClass;
$json->name = 'Maik';
- $schema->validate($json);
+ $this->assertValid($schema, $json);
$schema = new Schema(Schema::TYPE_ARRAY, function($arr) {
$arr->all(Schema::TYPE_OBJECT, function($obj) {
@@ -373,6 +322,6 @@ public function testSupportsPHPObjects() {
$json = array($user1, $user2);
- $schema->validate($json);
+ $this->assertValid($schema, $json);
}
}

0 comments on commit 6c6a276

Please sign in to comment.
Something went wrong with that request. Please try again.