diff --git a/README.md b/README.md index 86133446..1adb4817 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ if ($validator->isValid()) { ``` ###Type Coercion If you're validating data passed to your application via HTTP, you can cast strings and booleans to the expected types defined by your schema: -``` +```php use JsonSchema\SchemaStorage; use JsonSchema\Validator; use JsonSchema\Constraints\Factory; @@ -56,9 +56,7 @@ $request = (object)[ 'refundAmount'=>"17" ]; -$factory = new Factory( null, null, Constraint::CHECK_MODE_TYPE_CAST | Constraint::CHECK_MODE_COERCE ); - -$validator = new Validator($factory); +$validator = new Validator(Constraint::CHECK_MODE_TYPE_CAST | Constraint::CHECK_MODE_COERCE); $validator->check($request, (object) [ "type"=>"object", "properties"=>(object)[ @@ -85,6 +83,7 @@ Note that the ```CHECK_MODE_COERCE``` flag will only take effect when an object use JsonSchema\SchemaStorage; use JsonSchema\Validator; use JsonSchema\Constraints\Factory; +use JsonSchema\Constraints\Constraint; $jsonSchema = <<<'JSON' { @@ -122,7 +121,7 @@ $schemaStorage = new SchemaStorage(); $schemaStorage->addSchema('file://mySchema', $jsonSchemaObject); // Provide $schemaStorage to the Validator so that references can be resolved during validation -$jsonValidator = new Validator( new Factory($schemaStorage)); +$jsonValidator = new Validator( Constraint::CHECK_MODE_NORMAL, new Factory($schemaStorage)); // JSON must be decoded before it can be validated $jsonToValidateObject = json_decode('{"data":123}'); @@ -133,4 +132,4 @@ $jsonValidator->check($jsonToValidateObject, $jsonSchemaObject); ## Running the tests - $ vendor/bin/phpunit + $ vendor/bin/phpunit \ No newline at end of file diff --git a/src/JsonSchema/Constraints/CollectionConstraint.php b/src/JsonSchema/Constraints/CollectionConstraint.php index b65173de..5d77b088 100644 --- a/src/JsonSchema/Constraints/CollectionConstraint.php +++ b/src/JsonSchema/Constraints/CollectionConstraint.php @@ -106,7 +106,7 @@ protected function validateItems($value, $schema = null, JsonPointer $path = nul // Treat when we have more schema definitions than values, not for empty arrays if (count($value) > 0) { for ($k = count($value); $k < count($schema->items); $k++) { - $this->checkUndefined($this->factory->createInstanceFor('undefined'), $schema->items[$k], $path, $k); + $this->checkUndefined($this->factory->createInstanceFor($this->checkMode,'undefined'), $schema->items[$k], $path, $k); } } } diff --git a/src/JsonSchema/Constraints/Constraint.php b/src/JsonSchema/Constraints/Constraint.php index 95a63971..df01b281 100644 --- a/src/JsonSchema/Constraints/Constraint.php +++ b/src/JsonSchema/Constraints/Constraint.php @@ -29,6 +29,11 @@ abstract class Constraint implements ConstraintInterface const CHECK_MODE_TYPE_CAST = 0x00000002; const CHECK_MODE_COERCE = 0x00000004; + /** + * @var int + */ + protected $checkMode; + /** * @var Factory */ @@ -37,8 +42,9 @@ abstract class Constraint implements ConstraintInterface /** * @param Factory $factory */ - public function __construct(Factory $factory = null) + public function __construct($checkMode = Constraint::CHECK_MODE_NORMAL, Factory $factory = null) { + $this->checkMode = $checkMode; $this->factory = $factory ? : new Factory(); } @@ -127,7 +133,7 @@ protected function incrementPath(JsonPointer $path = null, $i) */ protected function checkArray($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('collection'); + $validator = $this->factory->createInstanceFor($this->checkMode,'collection'); $validator->check($value, $schema, $path, $i); $this->addErrors($validator->getErrors()); @@ -144,7 +150,7 @@ protected function checkArray($value, $schema = null, JsonPointer $path = null, */ protected function checkObject($value, $schema = null, JsonPointer $path = null, $i = null, $patternProperties = null) { - $validator = $this->factory->createInstanceFor('object'); + $validator = $this->factory->createInstanceFor($this->checkMode,'object'); $validator->check($value, $schema, $path, $i, $patternProperties); $this->addErrors($validator->getErrors()); @@ -160,7 +166,7 @@ protected function checkObject($value, $schema = null, JsonPointer $path = null, */ protected function checkType($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('type'); + $validator = $this->factory->createInstanceFor($this->checkMode, 'type'); $validator->check($value, $schema, $path, $i); $this->addErrors($validator->getErrors()); @@ -176,7 +182,7 @@ protected function checkType($value, $schema = null, JsonPointer $path = null, $ */ protected function checkUndefined($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('undefined'); + $validator = $this->factory->createInstanceFor($this->checkMode,'undefined'); $validator->check($value, $this->factory->getSchemaStorage()->resolveRefSchema($schema), $path, $i); @@ -193,7 +199,7 @@ protected function checkUndefined($value, $schema = null, JsonPointer $path = nu */ protected function checkString($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('string'); + $validator = $this->factory->createInstanceFor($this->checkMode, 'string'); $validator->check($value, $schema, $path, $i); $this->addErrors($validator->getErrors()); @@ -209,7 +215,7 @@ protected function checkString($value, $schema = null, JsonPointer $path = null, */ protected function checkNumber($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('number'); + $validator = $this->factory->createInstanceFor($this->checkMode, 'number'); $validator->check($value, $schema, $path, $i); $this->addErrors($validator->getErrors()); @@ -225,7 +231,7 @@ protected function checkNumber($value, $schema = null, JsonPointer $path = null, */ protected function checkEnum($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('enum'); + $validator = $this->factory->createInstanceFor($this->checkMode, 'enum'); $validator->check($value, $schema, $path, $i); $this->addErrors($validator->getErrors()); @@ -241,7 +247,7 @@ protected function checkEnum($value, $schema = null, JsonPointer $path = null, $ */ protected function checkFormat($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('format'); + $validator = $this->factory->createInstanceFor($this->checkMode, 'format'); $validator->check($value, $schema, $path, $i); $this->addErrors($validator->getErrors()); @@ -254,7 +260,7 @@ protected function checkFormat($value, $schema = null, JsonPointer $path = null, */ protected function getTypeCheck() { - return $this->factory->getTypeCheck(); + return $this->factory->getTypeCheck($this->checkMode); } /** diff --git a/src/JsonSchema/Constraints/EnumConstraint.php b/src/JsonSchema/Constraints/EnumConstraint.php index 376d3ee9..23adb653 100644 --- a/src/JsonSchema/Constraints/EnumConstraint.php +++ b/src/JsonSchema/Constraints/EnumConstraint.php @@ -31,7 +31,7 @@ public function check($element, $schema = null, JsonPointer $path = null, $i = n foreach ($schema->enum as $enum) { $enumType = gettype($enum); - if (($this->factory->getCheckMode() & self::CHECK_MODE_TYPE_CAST) && $type == "array" && $enumType == "object") { + if (($this->checkMode & self::CHECK_MODE_TYPE_CAST) && $type == "array" && $enumType == "object") { if ((object)$element == $enum) { return; } diff --git a/src/JsonSchema/Constraints/Factory.php b/src/JsonSchema/Constraints/Factory.php index 5eadb17e..e9b37150 100644 --- a/src/JsonSchema/Constraints/Factory.php +++ b/src/JsonSchema/Constraints/Factory.php @@ -29,11 +29,6 @@ class Factory */ protected $uriRetriever; - /** - * @var int - */ - private $checkMode; - /** * @var TypeCheck\TypeCheckInterface[] */ @@ -69,12 +64,10 @@ class Factory */ public function __construct( SchemaStorage $schemaStorage = null, - UriRetrieverInterface $uriRetriever = null, - $checkMode = Constraint::CHECK_MODE_NORMAL + UriRetrieverInterface $uriRetriever = null ) { $this->uriRetriever = $uriRetriever ?: new UriRetriever; $this->schemaStorage = $schemaStorage ?: new SchemaStorage($this->uriRetriever); - $this->checkMode = $checkMode; } /** @@ -90,15 +83,15 @@ public function getSchemaStorage() return $this->schemaStorage; } - public function getTypeCheck() + public function getTypeCheck($checkMode) { - if (!isset($this->typeCheck[$this->checkMode])) { - $this->typeCheck[$this->checkMode] = ($this->checkMode & Constraint::CHECK_MODE_TYPE_CAST) + if (!isset($this->typeCheck[$checkMode])) { + $this->typeCheck[$checkMode] = ($checkMode & Constraint::CHECK_MODE_TYPE_CAST) ? new TypeCheck\LooseTypeCheck : new TypeCheck\StrictTypeCheck; } - return $this->typeCheck[$this->checkMode]; + return $this->typeCheck[$checkMode]; } /** @@ -127,24 +120,16 @@ public function setConstraintClass($name, $class) * @return ConstraintInterface|ObjectConstraint * @throws InvalidArgumentException if is not possible create the constraint instance. */ - public function createInstanceFor($constraintName) + public function createInstanceFor($checkMode, $constraintName) { if (!isset($this->constraintMap[$constraintName])) { throw new InvalidArgumentException('Unknown constraint ' . $constraintName); } if (!isset($this->instanceCache[$constraintName])) { - $this->instanceCache[$constraintName] = new $this->constraintMap[$constraintName]($this); + $this->instanceCache[$constraintName] = new $this->constraintMap[$constraintName]($checkMode, $this); } return clone $this->instanceCache[$constraintName]; } - - /** - * @return int - */ - public function getCheckMode() - { - return $this->checkMode; - } } diff --git a/src/JsonSchema/Constraints/ObjectConstraint.php b/src/JsonSchema/Constraints/ObjectConstraint.php index ca8068fe..56cb4caf 100644 --- a/src/JsonSchema/Constraints/ObjectConstraint.php +++ b/src/JsonSchema/Constraints/ObjectConstraint.php @@ -106,7 +106,7 @@ public function validateElement($element, $matches, $objectDefinition = null, Js $this->addError($path, "The presence of the property " . $i . " requires that " . $require . " also be present", 'requires'); } - $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined')); + $property = $this->getProperty($element, $i, $this->factory->createInstanceFor($this->checkMode, 'undefined')); if (is_object($property)) { $this->validateMinMaxConstraint(!($property instanceof UndefinedConstraint) ? $property : $element, $definition, $path); } @@ -122,17 +122,17 @@ public function validateElement($element, $matches, $objectDefinition = null, Js */ public function validateDefinition($element, $objectDefinition = null, JsonPointer $path = null) { - $undefinedConstraint = $this->factory->createInstanceFor('undefined'); + $undefinedConstraint = $this->factory->createInstanceFor($this->checkMode,'undefined'); foreach ($objectDefinition as $i => $value) { $property = $this->getProperty($element, $i, $undefinedConstraint); $definition = $this->getProperty($objectDefinition, $i); - if($this->factory->getCheckMode() & Constraint::CHECK_MODE_TYPE_CAST){ + if($this->checkMode & Constraint::CHECK_MODE_TYPE_CAST){ if(!($property instanceof Constraint)) { $property = $this->coerce($property, $definition); - if($this->factory->getCheckMode() & Constraint::CHECK_MODE_COERCE) { + if($this->checkMode & Constraint::CHECK_MODE_COERCE) { if (is_object($element)) { $element->{$i} = $property; } else { diff --git a/src/JsonSchema/Constraints/TypeConstraint.php b/src/JsonSchema/Constraints/TypeConstraint.php index 1b2125e0..d215ca0d 100644 --- a/src/JsonSchema/Constraints/TypeConstraint.php +++ b/src/JsonSchema/Constraints/TypeConstraint.php @@ -82,7 +82,7 @@ protected function validateTypesArray($value, array $type, &$validTypesWording, // with a new type constraint if (is_object($tp)) { if (!$isValid) { - $validator = $this->factory->createInstanceFor('type'); + $validator = $this->factory->createInstanceFor($this->checkMode,'type'); $subSchema = new \stdClass(); $subSchema->type = $tp; $validator->check($value, $subSchema, $path, null); diff --git a/src/JsonSchema/Validator.php b/src/JsonSchema/Validator.php index 39dca096..4ad7d524 100644 --- a/src/JsonSchema/Validator.php +++ b/src/JsonSchema/Validator.php @@ -32,7 +32,7 @@ class Validator extends Constraint */ public function check($value, $schema = null, JsonPointer $path = null, $i = null) { - $validator = $this->factory->createInstanceFor('schema'); + $validator = $this->factory->createInstanceFor($this->checkMode, 'schema'); $validator->check($value, $schema); $this->addErrors(array_unique($validator->getErrors(), SORT_REGULAR)); diff --git a/tests/Constraints/BaseTestCase.php b/tests/Constraints/BaseTestCase.php index 5c6dcf18..143526d1 100644 --- a/tests/Constraints/BaseTestCase.php +++ b/tests/Constraints/BaseTestCase.php @@ -37,7 +37,7 @@ public function testInvalidCases($input, $schema, $checkMode = Constraint::CHECK $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $validator->check(json_decode($input), $schema); if (array() !== $errors) { @@ -59,7 +59,7 @@ public function testInvalidCasesUsingAssoc($input, $schema, $checkMode = Constra $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $validator->check(json_decode($input, true), $schema); if (array() !== $errors) { @@ -76,7 +76,7 @@ public function testValidCases($input, $schema, $checkMode = Constraint::CHECK_M $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $validator->check(json_decode($input), $schema); $this->assertTrue($validator->isValid(), print_r($validator->getErrors(), true)); @@ -96,7 +96,7 @@ public function testValidCasesUsingAssoc($input, $schema, $checkMode = Constrain $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); $value = json_decode($input, true); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $validator->check($value, $schema); $this->assertTrue($validator->isValid(), print_r($validator->getErrors(), true)); diff --git a/tests/Constraints/CoerciveTest.php b/tests/Constraints/CoerciveTest.php index 5115988a..ad9b0c47 100644 --- a/tests/Constraints/CoerciveTest.php +++ b/tests/Constraints/CoerciveTest.php @@ -27,7 +27,7 @@ public function testValidCoerceCasesUsingAssoc($input, $schema) $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $value = json_decode($input, true); @@ -45,7 +45,7 @@ public function testValidCoerceCases($input, $schema, $errors = array()) $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $value = json_decode($input); $this->assertTrue(gettype($value->number) == "string"); @@ -86,7 +86,7 @@ public function testInvalidCoerceCases($input, $schema, $errors = array()) $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $validator->check(json_decode($input), $schema); if (array() !== $errors) { @@ -105,7 +105,7 @@ public function testInvalidCoerceCasesUsingAssoc($input, $schema, $errors = arra $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator(new Factory($schemaStorage, null, $checkMode)); + $validator = new Validator($checkMode, new Factory($schemaStorage, null)); $validator->check(json_decode($input, true), $schema); if (array() !== $errors) { diff --git a/tests/Constraints/FactoryTest.php b/tests/Constraints/FactoryTest.php index 956db6de..ff8718ea 100644 --- a/tests/Constraints/FactoryTest.php +++ b/tests/Constraints/FactoryTest.php @@ -50,7 +50,7 @@ protected function setUp() */ public function testCreateInstanceForConstraintName($constraintName, $expectedClass) { - $constraint = $this->factory->createInstanceFor($constraintName); + $constraint = $this->factory->createInstanceFor(Constraint::CHECK_MODE_NORMAL, $constraintName); $this->assertInstanceOf($expectedClass, $constraint); $this->assertInstanceOf('JsonSchema\Constraints\ConstraintInterface', $constraint); @@ -82,7 +82,7 @@ public function constraintNameProvider() public function testExceptionWhenCreateInstanceForInvalidConstraintName($constraintName) { $this->setExpectedException('JsonSchema\Exception\InvalidArgumentException'); - $this->factory->createInstanceFor($constraintName); + $this->factory->createInstanceFor(Constraint::CHECK_MODE_NORMAL, $constraintName); } public function invalidConstraintNameProvider() { @@ -110,7 +110,7 @@ public function testSetConstraintClassImplementsCondition() public function testSetConstraintClassInstance() { $this->factory->setConstraintClass('string', 'JsonSchema\Tests\Constraints\MyStringConstraint'); - $constraint = $this->factory->createInstanceFor('string'); + $constraint = $this->factory->createInstanceFor(Constraint::CHECK_MODE_NORMAL, 'string'); $this->assertInstanceOf('JsonSchema\Tests\Constraints\MyStringConstraint', $constraint); $this->assertInstanceOf('JsonSchema\Constraints\ConstraintInterface', $constraint); }