diff --git a/README.md b/README.md index ed88c0e7..c0c9feb2 100644 --- a/README.md +++ b/README.md @@ -26,17 +26,11 @@ See [json-schema](http://json-schema.org/) for more details. ```php resolve('file://' . realpath('schema.json')); - $data = json_decode(file_get_contents('data.json')); // Validate -$validator = new JsonSchema\Validator(); -$validator->check($data, $schema); +$validator = new JsonSchema\Validator; +$validator->check($data, (object)['$ref' => 'file://' . realpath('schema.json')]); if ($validator->isValid()) { echo "The supplied JSON validates against the schema.\n"; diff --git a/src/JsonSchema/Constraints/Constraint.php b/src/JsonSchema/Constraints/Constraint.php index a56acbb4..521a0e06 100644 --- a/src/JsonSchema/Constraints/Constraint.php +++ b/src/JsonSchema/Constraints/Constraint.php @@ -9,8 +9,9 @@ namespace JsonSchema\Constraints; +use JsonSchema\SchemaStorage; use JsonSchema\Uri\UriRetriever; -use JsonSchema\Validator; +use JsonSchema\UriRetrieverInterface; use JsonSchema\Entity\JsonPointer; /** @@ -21,6 +22,7 @@ */ abstract class Constraint implements ConstraintInterface { + protected $schemaStorage; protected $checkMode = self::CHECK_MODE_NORMAL; protected $uriRetriever; protected $errors = array(); @@ -35,19 +37,25 @@ abstract class Constraint implements ConstraintInterface private $factory; /** - * @param int $checkMode - * @param UriRetriever $uriRetriever - * @param Factory $factory + * @param int $checkMode + * @param SchemaStorage $schemaStorage + * @param UriRetrieverInterface $uriRetriever + * @param Factory $factory */ - public function __construct($checkMode = self::CHECK_MODE_NORMAL, UriRetriever $uriRetriever = null, Factory $factory = null) - { - $this->checkMode = $checkMode; - $this->uriRetriever = $uriRetriever; - $this->factory = $factory; + public function __construct( + $checkMode = self::CHECK_MODE_NORMAL, + SchemaStorage $schemaStorage = null, + UriRetrieverInterface $uriRetriever = null, + Factory $factory = null + ) { + $this->checkMode = $checkMode; + $this->uriRetriever = $uriRetriever; + $this->factory = $factory; + $this->schemaStorage = $schemaStorage; } /** - * @return UriRetriever $uriRetriever + * @return UriRetrieverInterface $uriRetriever */ public function getUriRetriever() { @@ -64,16 +72,28 @@ public function getUriRetriever() public function getFactory() { if (!$this->factory) { - $this->factory = new Factory($this->getUriRetriever(), $this->checkMode); + $this->factory = new Factory($this->getSchemaStorage(), $this->getUriRetriever(), $this->checkMode); } return $this->factory; } /** - * @param UriRetriever $uriRetriever + * @return SchemaStorage + */ + public function getSchemaStorage() + { + if (is_null($this->schemaStorage)) { + $this->schemaStorage = new SchemaStorage($this->getUriRetriever()); + } + + return $this->schemaStorage; + } + + /** + * @param UriRetrieverInterface $uriRetriever */ - public function setUriRetriever(UriRetriever $uriRetriever) + public function setUriRetriever(UriRetrieverInterface $uriRetriever) { $this->uriRetriever = $uriRetriever; } @@ -211,7 +231,7 @@ protected function checkType($value, $schema = null, JsonPointer $path = null, $ protected function checkUndefined($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('undefined'); - $validator->check($value, $schema, $path, $i); + $validator->check($value, $this->schemaStorage->resolveRefSchema($schema), $path, $i); $this->addErrors($validator->getErrors()); } @@ -280,20 +300,6 @@ protected function checkFormat($value, $schema = null, JsonPointer $path = null, $this->addErrors($validator->getErrors()); } - /** - * @param string $uri JSON Schema URI - * @return string JSON Schema contents - */ - protected function retrieveUri($uri) - { - if (null === $this->uriRetriever) { - $this->setUriRetriever(new UriRetriever); - } - $jsonSchema = $this->uriRetriever->retrieve($uri); - // TODO validate using schema - return $jsonSchema; - } - /** * Get the type check based on the set check mode. * diff --git a/src/JsonSchema/Constraints/Factory.php b/src/JsonSchema/Constraints/Factory.php index 7defbd68..bb12ecec 100644 --- a/src/JsonSchema/Constraints/Factory.php +++ b/src/JsonSchema/Constraints/Factory.php @@ -10,13 +10,20 @@ namespace JsonSchema\Constraints; use JsonSchema\Exception\InvalidArgumentException; +use JsonSchema\SchemaStorage; use JsonSchema\Uri\UriRetriever; +use JsonSchema\UriRetrieverInterface; /** * Factory for centralize constraint initialization. */ class Factory { + /** + * @var SchemaStorage + */ + protected $schemaStorage; + /** * @var UriRetriever $uriRetriever */ @@ -50,34 +57,39 @@ class Factory ); /** - * @param UriRetriever $uriRetriever + * @param SchemaStorage $schemaStorage + * @param UriRetrieverInterface $uriRetriever + * @param int $checkMode */ - public function __construct(UriRetriever $uriRetriever = null, $checkMode = Constraint::CHECK_MODE_NORMAL) - { - if (!$uriRetriever) { - $uriRetriever = new UriRetriever(); - } - - $this->uriRetriever = $uriRetriever; + public function __construct( + SchemaStorage $schemaStorage = null, + UriRetrieverInterface $uriRetriever = null, + $checkMode = Constraint::CHECK_MODE_NORMAL + ) { + $this->uriRetriever = $uriRetriever ?: new UriRetriever; + $this->schemaStorage = $schemaStorage ?: new SchemaStorage($this->uriRetriever); $this->checkMode = $checkMode; } /** - * @return UriRetriever + * @return UriRetrieverInterface */ public function getUriRetriever() { return $this->uriRetriever; } + + public function getSchemaStorage() + { + return $this->schemaStorage; + } public function getTypeCheck() { if (!isset($this->typeCheck[$this->checkMode])) { - if ($this->checkMode === Constraint::CHECK_MODE_TYPE_CAST) { - $this->typeCheck[Constraint::CHECK_MODE_TYPE_CAST] = new TypeCheck\LooseTypeCheck(); - } else { - $this->typeCheck[$this->checkMode] = new TypeCheck\StrictTypeCheck(); - } + $this->typeCheck[$this->checkMode] = $this->checkMode === Constraint::CHECK_MODE_TYPE_CAST + ? new TypeCheck\LooseTypeCheck + : new TypeCheck\StrictTypeCheck; } return $this->typeCheck[$this->checkMode]; @@ -112,7 +124,12 @@ public function setConstraintClass($name, $class) public function createInstanceFor($constraintName) { if (array_key_exists($constraintName, $this->constraintMap)) { - return new $this->constraintMap[$constraintName]($this->checkMode, $this->uriRetriever, $this); + return new $this->constraintMap[$constraintName]( + $this->checkMode, + $this->schemaStorage, + $this->uriRetriever, + $this + ); } throw new InvalidArgumentException('Unknown constraint ' . $constraintName); } diff --git a/src/JsonSchema/Constraints/ObjectConstraint.php b/src/JsonSchema/Constraints/ObjectConstraint.php index f9733971..5a12b87f 100644 --- a/src/JsonSchema/Constraints/ObjectConstraint.php +++ b/src/JsonSchema/Constraints/ObjectConstraint.php @@ -127,7 +127,7 @@ public function validateElement($element, $matches, $objectDefinition = null, Js public function validateDefinition($element, $objectDefinition = null, JsonPointer $path = null) { foreach ($objectDefinition as $i => $value) { - $property = $this->getProperty($element, $i, new UndefinedConstraint()); + $property = $this->getProperty($element, $i, $this->getFactory()->createInstanceFor('undefined')); $definition = $this->getProperty($objectDefinition, $i); $this->checkUndefined($property, $definition, $path, $i); } diff --git a/src/JsonSchema/Constraints/TypeConstraint.php b/src/JsonSchema/Constraints/TypeConstraint.php index 85e695a2..d082f6a4 100644 --- a/src/JsonSchema/Constraints/TypeConstraint.php +++ b/src/JsonSchema/Constraints/TypeConstraint.php @@ -81,7 +81,7 @@ protected function validateTypesArray($value, array $type, &$validTypesWording, // with a new type constraint if (is_object($tp)) { if (!$isValid) { - $validator = new static($this->checkMode); + $validator = $this->getFactory()->createInstanceFor('type'); $subSchema = new \stdClass(); $subSchema->type = $tp; $validator->check($value, $subSchema, $path, null); diff --git a/src/JsonSchema/RefResolver.php b/src/JsonSchema/RefResolver.php deleted file mode 100644 index 00c7a671..00000000 --- a/src/JsonSchema/RefResolver.php +++ /dev/null @@ -1,175 +0,0 @@ - - * @author Rik Jansen - */ -class RefResolver -{ - /** @var UriRetrieverInterface */ - private $uriRetriever; - - /** @var UriResolverInterface */ - private $uriResolver; - - private $paths = array(); - - /** - * @param UriRetrieverInterface $retriever - * @param UriResolverInterface $uriResolver - */ - public function __construct(UriRetrieverInterface $retriever, UriResolverInterface $uriResolver) - { - $this->uriRetriever = $retriever; - $this->uriResolver = $uriResolver; - } - - /** - * Resolves all schema and all $ref references for the give $sourceUri. Recurse through the object to resolve - * references of any child schemas and return the schema. - * - * @param string $sourceUri URI where this schema was located - * @return object - */ - public function resolve($sourceUri) - { - $jsonPointer = new JsonPointer($sourceUri); - - $fileName = $jsonPointer->getFilename(); - if (!array_key_exists($fileName, $this->paths)) { - $schema = $this->uriRetriever->retrieve($jsonPointer->getFilename()); - $this->paths[$jsonPointer->getFilename()] = $schema; - $this->resolveSchemas($schema, $jsonPointer->getFilename()); - } - $schema = $this->paths[$fileName]; - - return $this->getRefSchema($jsonPointer, $schema); - } - - /** - * Recursive resolve schema by traversing through al nodes - * - * @param object $unresolvedSchema - * @param string $fileName - */ - private function resolveSchemas($unresolvedSchema, $fileName) - { - $objectIterator = new ObjectIterator($unresolvedSchema); - foreach ($objectIterator as $toResolveSchema) { - if (property_exists($toResolveSchema, '$ref') && is_string($toResolveSchema->{'$ref'})) { - $jsonPointer = new JsonPointer($this->uriResolver->resolve($toResolveSchema->{'$ref'}, $fileName)); - $refSchema = $this->resolve((string) $jsonPointer); - $this->unionSchemas($refSchema, $toResolveSchema, $fileName); - } - } - } - - /** - * @param JsonPointer $jsonPointer - * @param object $refSchema - * @throws UnresolvableJsonPointerException when json schema file is found but reference can not be resolved - * @return object - */ - private function getRefSchema(JsonPointer $jsonPointer, $refSchema) - { - foreach ($jsonPointer->getPropertyPaths() as $path) { - if (is_object($refSchema) && property_exists($refSchema, $path)) { - $refSchema = $refSchema->{$path}; - } elseif (is_array($refSchema) && array_key_exists($path, $refSchema)) { - $refSchema = $refSchema[$path]; - } else { - throw new UnresolvableJsonPointerException(sprintf( - 'File: %s is found, but could not resolve fragment: %s', - $jsonPointer->getFilename(), - $jsonPointer->getPropertyPathAsString() - )); - } - } - - return $refSchema; - } - - /** - * @param object $refSchema - * @param object $schema - * @param string $fileName - */ - private function unionSchemas($refSchema, $schema, $fileName) - { - if (property_exists($refSchema, '$ref')) { - $jsonPointer = new JsonPointer($this->uriResolver->resolve($refSchema->{'$ref'}, $fileName)); - $newSchema = $this->resolve((string) $jsonPointer); - $this->unionSchemas($newSchema, $refSchema, $fileName); - } - - unset($schema->{'$ref'}); - if (!$this->hasSubSchemas($schema)) { - foreach (get_object_vars($refSchema) as $prop => $value) { - $schema->$prop = $value; - } - } else { - $newSchema = new \stdClass(); - foreach (get_object_vars($schema) as $prop => $value) { - $newSchema->$prop = $value; - unset($schema->$prop); - } - $schema->allOf = array($newSchema, $refSchema); - } - } - - /** - * @param object $schema - * @return bool - */ - private function hasSubSchemas($schema) - { - foreach (array_keys(get_object_vars($schema)) as $propertyName) { - if (in_array($propertyName, $this->getReservedKeysWhichAreInFactSubSchemas())) { - return true; - } - } - - return false; - } - - /** - * @return string[] - */ - private function getReservedKeysWhichAreInFactSubSchemas() - { - return array( - 'additionalItems', - 'additionalProperties', - 'extends', - 'items', - 'disallow', - 'extends', - 'items', - 'type', - 'allOf', - 'anyOf', - 'oneOf', - 'dependencies', - 'patternProperties', - 'properties' - ); - } -} diff --git a/src/JsonSchema/SchemaStorage.php b/src/JsonSchema/SchemaStorage.php new file mode 100644 index 00000000..97f88eb9 --- /dev/null +++ b/src/JsonSchema/SchemaStorage.php @@ -0,0 +1,109 @@ +uriRetriever = $uriRetriever ?: new UriRetriever; + $this->uriResolver = $uriResolver ?: new UriResolver; + } + + /** + * @return UriRetrieverInterface + */ + public function getUriRetriever() + { + return $this->uriRetriever; + } + + /** + * @return UriResolverInterface + */ + public function getUriResolver() + { + return $this->uriResolver; + } + + /** + * @param string $id + * @param object $schema + */ + public function addSchema($id, $schema = null) + { + if (is_null($schema)) { + $schema = $this->uriRetriever->retrieve($id); + } + $objectIterator = new ObjectIterator($schema); + foreach ($objectIterator as $toResolveSchema) { + if (property_exists($toResolveSchema, '$ref') && is_string($toResolveSchema->{'$ref'})) { + $jsonPointer = new JsonPointer($this->uriResolver->resolve($toResolveSchema->{'$ref'}, $id)); + $toResolveSchema->{'$ref'} = (string)$jsonPointer; + } + } + $this->schemas[$id] = $schema; + } + + /** + * @param string $id + * @return object + */ + public function getSchema($id) + { + if (!array_key_exists($id, $this->schemas)) { + $this->addSchema($id); + } + + return $this->schemas[$id]; + } + + public function resolveRef($ref) + { + $jsonPointer = new JsonPointer($ref); + $refSchema = $this->getSchema($jsonPointer->getFilename()); + + foreach ($jsonPointer->getPropertyPaths() as $path) { + if (is_object($refSchema) && property_exists($refSchema, $path)) { + $refSchema = $this->resolveRefSchema($refSchema->{$path}); + } elseif (is_array($refSchema) && array_key_exists($path, $refSchema)) { + $refSchema = $this->resolveRefSchema($refSchema[$path]); + } else { + throw new UnresolvableJsonPointerException(sprintf( + 'File: %s is found, but could not resolve fragment: %s', + $jsonPointer->getFilename(), + $jsonPointer->getPropertyPathAsString() + )); + } + } + + return $refSchema; + } + + /** + * @param $refSchema + * @return object + */ + public function resolveRefSchema($refSchema) + { + if (is_object($refSchema) && property_exists($refSchema, '$ref')) { + $newSchema = $this->resolveRef($refSchema->{'$ref'}); + $refSchema = (object) (get_object_vars($refSchema) + get_object_vars($newSchema)); + unset($refSchema->{'$ref'}); + } + + return $refSchema; + } +} diff --git a/tests/Constraints/BaseTestCase.php b/tests/Constraints/BaseTestCase.php index 52bcd456..fe6c6951 100644 --- a/tests/Constraints/BaseTestCase.php +++ b/tests/Constraints/BaseTestCase.php @@ -10,7 +10,7 @@ namespace JsonSchema\Tests\Constraints; use JsonSchema\Constraints\Constraint; -use JsonSchema\RefResolver; +use JsonSchema\SchemaStorage; use JsonSchema\Uri\UriResolver; use JsonSchema\Validator; use Prophecy\Argument; @@ -29,19 +29,15 @@ abstract class BaseTestCase extends \PHPUnit_Framework_TestCase /** * @dataProvider getInvalidTests */ - public function testInvalidCases($input, $jsonSchema, $checkMode = Constraint::CHECK_MODE_NORMAL, $errors = array()) + public function testInvalidCases($input, $schema, $checkMode = Constraint::CHECK_MODE_NORMAL, $errors = array()) { $checkMode = $checkMode === null ? Constraint::CHECK_MODE_NORMAL : $checkMode; - $schema = json_decode($jsonSchema); - if (is_object($schema)) { - $schema = $this->resolveSchema($schema); - } - - $value = json_decode($input); + $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); + $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator($checkMode); - $validator->check($value, $schema); + $validator = new Validator($checkMode, $schemaStorage); + $validator->check(json_decode($input), $schema); if (array() !== $errors) { $this->assertEquals($errors, $validator->getErrors(), print_r($validator->getErrors(),true)); @@ -52,22 +48,18 @@ public function testInvalidCases($input, $jsonSchema, $checkMode = Constraint::C /** * @dataProvider getInvalidForAssocTests */ - public function testInvalidCasesUsingAssoc($input, $jsonSchema, $checkMode = Constraint::CHECK_MODE_TYPE_CAST, $errors = array()) + public function testInvalidCasesUsingAssoc($input, $schema, $checkMode = Constraint::CHECK_MODE_TYPE_CAST, $errors = array()) { $checkMode = $checkMode === null ? Constraint::CHECK_MODE_TYPE_CAST : $checkMode; if ($checkMode !== Constraint::CHECK_MODE_TYPE_CAST) { $this->markTestSkipped('Test indicates that it is not for "CHECK_MODE_TYPE_CAST"'); } - $schema = json_decode($jsonSchema); - if (is_object($schema)) { - $schema = $this->resolveSchema($schema); - } - - $value = json_decode($input, true); + $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); + $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $validator = new Validator($checkMode); - $validator->check($value, $schema); + $validator = new Validator($checkMode, $schemaStorage); + $validator->check(json_decode($input, true), $schema); if (array() !== $errors) { $this->assertEquals($errors, $validator->getErrors(), print_r($validator->getErrors(), true)); @@ -80,15 +72,12 @@ public function testInvalidCasesUsingAssoc($input, $jsonSchema, $checkMode = Con */ public function testValidCases($input, $schema, $checkMode = Constraint::CHECK_MODE_NORMAL) { - $schema = json_decode($schema); - if (is_object($schema)) { - $schema = $this->resolveSchema($schema); - } + $schemaStorage = new SchemaStorage($this->getUriRetrieverMock(json_decode($schema))); + $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); - $value = json_decode($input); - $validator = new Validator($checkMode); + $validator = new Validator($checkMode, $schemaStorage); + $validator->check(json_decode($input), $schema); - $validator->check($value, $schema); $this->assertTrue($validator->isValid(), print_r($validator->getErrors(), true)); } @@ -102,12 +91,11 @@ public function testValidCasesUsingAssoc($input, $schema, $checkMode = Constrain } $schema = json_decode($schema); - if (is_object($schema)) { - $schema = $this->resolveSchema($schema); - } + $schemaStorage = new SchemaStorage($this->getUriRetrieverMock($schema), new UriResolver); + $schema = $schemaStorage->getSchema('http://www.my-domain.com/schema.json'); $value = json_decode($input, true); - $validator = new Validator($checkMode); + $validator = new Validator($checkMode, $schemaStorage); $validator->check($value, $schema); $this->assertTrue($validator->isValid(), print_r($validator->getErrors(), true)); @@ -143,7 +131,7 @@ public function getInvalidForAssocTests() * @param object $schema * @return object */ - private function resolveSchema($schema) + private function getUriRetrieverMock($schema) { $relativeTestsRoot = realpath(__DIR__ . '/../../vendor/json-schema/JSON-Schema-Test-Suite/remotes'); @@ -168,9 +156,7 @@ private function resolveSchema($schema) return json_decode(file_get_contents($relativeTestsRoot . '/folder' . $urlParts['path'])); } }); - $refResolver = new RefResolver($uriRetriever->reveal(), new UriResolver()); - - return $refResolver->resolve('http://www.my-domain.com/schema.json'); + return $uriRetriever->reveal(); } /** diff --git a/tests/RefResolverTest.php b/tests/SchemaStorageTest.php similarity index 57% rename from tests/RefResolverTest.php rename to tests/SchemaStorageTest.php index 408f56c8..ebd96781 100644 --- a/tests/RefResolverTest.php +++ b/tests/SchemaStorageTest.php @@ -9,92 +9,81 @@ namespace JsonSchema\Tests; -use JsonSchema\RefResolver; -use JsonSchema\Uri\UriResolver; +use JsonSchema\SchemaStorage; use JsonSchema\Uri\UriRetriever; use Prophecy\Argument; -/** - * @package JsonSchema\Tests - * @author Joost Nijhuis - * @author Rik Jansen - * @group RefResolver - */ -class RefResolverTest extends \PHPUnit_Framework_TestCase +class SchemaStorageTest extends \PHPUnit_Framework_TestCase { - /** @var RefResolver */ - private $refResolver; - - /** - * {@inheritdoc} - */ - public function setUp() + public function testResolveRef() { - parent::setUp(); + $mainSchema = $this->getMainSchema(); + $mainSchemaPath = 'http://www.example.com/schema.json'; + + $uriRetriever = $this->prophesize('JsonSchema\UriRetrieverInterface'); + $uriRetriever->retrieve($mainSchemaPath)->willReturn($mainSchema)->shouldBeCalled(); + + $schemaStorage = new SchemaStorage($uriRetriever->reveal()); - $this->refResolver = new RefResolver(new UriRetriever(), new UriResolver()); + $this->assertEquals( + (object) array('type' => 'string'), + $schemaStorage->resolveRef("$mainSchemaPath#/definitions/house/properties/door") + ); } + /** + * @depends testResolveRef + */ public function testSchemaWithLocalAndExternalReferencesWithCircularReference() { $mainSchema = $this->getMainSchema(); $schema2 = $this->getSchema2(); $schema3 = $this->getSchema3(); + $mainSchemaPath = 'http://www.example.com/schema.json'; + $schema2Path = 'http://www.my-domain.com/schema2.json'; + $schema3Path = 'http://www.my-domain.com/schema3.json'; + /** @var UriRetriever $uriRetriever */ $uriRetriever = $this->prophesize('JsonSchema\UriRetrieverInterface'); - $uriRetriever->retrieve('http://www.example.com/schema.json') - ->willReturn($mainSchema) - ->shouldBeCalled($mainSchema); - $uriRetriever->retrieve('http://www.my-domain.com/schema2.json') - ->willReturn($schema2) - ->shouldBeCalled(); - $uriRetriever->retrieve('http://www.my-domain.com/schema3.json') - ->willReturn($schema3) - ->shouldBeCalled(); + $uriRetriever->retrieve($mainSchemaPath)->willReturn($mainSchema)->shouldBeCalled(); + $uriRetriever->retrieve($schema2Path)->willReturn($schema2)->shouldBeCalled(); + $uriRetriever->retrieve($schema3Path)->willReturn($schema3)->shouldBeCalled(); - $refResolver = new RefResolver($uriRetriever->reveal(), new UriResolver()); - $refResolver->resolve('http://www.example.com/schema.json'); + $schemaStorage = new SchemaStorage($uriRetriever->reveal()); - // ref schema merged into schema - $this->assertSame($schema2->definitions->car->type, $mainSchema->properties->car->type); - $this->assertSame( - $schema2->definitions->car->additionalProperties, - $mainSchema->properties->car->additionalProperties + // remote ref + $this->assertEquals( + $schemaStorage->resolveRef("$schema2Path#/definitions/car"), + $schemaStorage->resolveRef("$mainSchemaPath#/properties/car") ); - $this->assertSame($schema2->definitions->car->properties, $mainSchema->properties->car->properties); - $this->assertFalse(property_exists($mainSchema->properties->car, '$ref')); - - // ref schema combined with current schema - $this->assertFalse(property_exists($mainSchema->properties->house, '$ref')); - $this->assertSame(true, $mainSchema->properties->house->allOf[0]->additionalProperties); - $this->assertSame($mainSchema->definitions->house, $mainSchema->properties->house->allOf[1]); - - $this->assertNotSame($mainSchema->definitions->house, $mainSchema->definitions->house->properties->house); - $this->assertNotSame( - $mainSchema->definitions->house, - $mainSchema->definitions->house->properties->house->properties->house + $this->assertEquals( + $schemaStorage->resolveRef("$schema3Path#/wheel"), + $schemaStorage->resolveRef("$mainSchemaPath#/properties/car/properties/wheel") ); - $this->assertSame( - $mainSchema->definitions->house->properties->house, - $mainSchema->definitions->house->properties->house->properties->house->properties->house + + // local ref with overriding + $this->assertNotEquals( + $schemaStorage->resolveRef("$mainSchemaPath#/definitions/house/additionalProperties"), + $schemaStorage->resolveRef("$mainSchemaPath#/properties/house/additionalProperties") ); - $this->assertSame( - $mainSchema->definitions->house->properties->house, - $mainSchema->definitions->house->properties->house->properties->house->properties->house->properties->house + $this->assertEquals( + $schemaStorage->resolveRef("$mainSchemaPath#/definitions/house/properties"), + $schemaStorage->resolveRef("$mainSchemaPath#/properties/house/properties") ); - $this->assertNotSame($schema3->wheel, $mainSchema->properties->car->properties->wheel); - $this->assertSame( - $schema3->wheel->properties->spokes, - $mainSchema->properties->car->properties->wheel->properties->spokes + // recursive ref + $this->assertEquals( + $schemaStorage->resolveRef("$mainSchemaPath#/definitions/house"), + $schemaStorage->resolveRef("$mainSchemaPath#/properties/house/properties/house") + ); + $this->assertEquals( + $schemaStorage->resolveRef("$mainSchemaPath#/definitions/house"), + $schemaStorage->resolveRef("$mainSchemaPath#/properties/house/properties/house/properties/house") ); - - $this->assertNotSame($schema3->wheel->properties->car, $mainSchema->properties->car); - $this->assertSame($schema3->wheel->properties->car->properties, $mainSchema->properties->car->properties); } - function testUnresolvableJsonPointExceptionShouldBeThrown() + public function testUnresolvableJsonPointExceptionShouldBeThrown() { $this->setExpectedException( 'JsonSchema\Exception\UnresolvableJsonPointerException', @@ -102,37 +91,15 @@ function testUnresolvableJsonPointExceptionShouldBeThrown() ); $mainSchema = $this->getInvalidSchema(); + $mainSchemaPath = 'http://www.example.com/schema.json'; $uriRetriever = $this->prophesize('JsonSchema\UriRetrieverInterface'); - $uriRetriever->retrieve('http://www.example.com/schema.json') + $uriRetriever->retrieve($mainSchemaPath) ->willReturn($mainSchema) ->shouldBeCalled($mainSchema); - $refResolver = new RefResolver($uriRetriever->reveal(), new UriResolver()); - $refResolver->resolve('http://www.example.com/schema.json'); - } - - public function testExternalReferencesLoadedOnlyOnce() - { - $mainSchema = $this->getMainSchema(); - $schema2 = $this->getSchema2(); - $schema3 = $this->getSchema3(); - - /** @var UriRetriever $uriRetriever */ - $uriRetriever = $this->prophesize('JsonSchema\UriRetrieverInterface'); - $uriRetriever->retrieve('http://www.example.com/schema.json') - ->willReturn($mainSchema) - ->shouldBeCalledTimes(1); - $uriRetriever->retrieve('http://www.my-domain.com/schema2.json') - ->willReturn($schema2) - ->shouldBeCalledTimes(1); - $uriRetriever->retrieve('http://www.my-domain.com/schema3.json') - ->willReturn($schema3) - ->shouldBeCalledTimes(1); - - $refResolver = new RefResolver($uriRetriever->reveal(), new UriResolver()); - $refResolver->resolve('http://www.example.com/schema.json'); - $refResolver->resolve('http://www.example.com/schema.json'); + $schemaStorage = new SchemaStorage($uriRetriever->reveal()); + $schemaStorage->resolveRef("$mainSchemaPath#/definitions/car"); } /**