diff --git a/src/JsonSchema/RefResolver.php b/src/JsonSchema/RefResolver.php index cd96beb7..232c4ade 100644 --- a/src/JsonSchema/RefResolver.php +++ b/src/JsonSchema/RefResolver.php @@ -41,6 +41,11 @@ class RefResolver */ protected $uriRetriever = null; + /** + * @var object + */ + protected $rootSchema = null; + /** * @param UriRetriever $retriever */ @@ -110,6 +115,10 @@ public function resolve($schema, $sourceUri = null) $sourceUri = $schema->id; } + if (null === $this->rootSchema) { + $this->rootSchema = $schema; + } + // Resolve $ref first $this->resolveRef($schema, $sourceUri); @@ -205,7 +214,30 @@ public function resolveRef($schema, $sourceUri) return; } - $refSchema = $this->fetchRef($schema->$ref, $sourceUri); + $splitRef = explode('#', $schema->$ref, 2); + + $refDoc = $splitRef[0]; + $refPath = null; + if (count($splitRef) === 2) { + $refPath = explode('/', $splitRef[1]); + array_shift($refPath); + } + + if (empty($refDoc) && empty($refPath)) { + // TODO: Not yet implemented - root pointer ref, causes recursion issues + return; + } + + if (!empty($refDoc)) { + $refSchema = $this->fetchRef($refDoc, $sourceUri); + } else { + $refSchema = $this->rootSchema; + } + + if (null !== $refPath) { + $refSchema = $this->resolveRefSegment($refSchema, $refPath); + } + unset($schema->$ref); // Augment the current $schema object with properties fetched @@ -226,4 +258,19 @@ public function setUriRetriever(UriRetriever $retriever) return $this; } + + protected function resolveRefSegment($data, $pathParts) + { + foreach ($pathParts as $path) { + $path = strtr($path, array('~1' => '/', '~0' => '~', '%25' => '%')); + + if (is_array($data)) { + $data = $data[$path]; + } else { + $data = $data->{$path}; + } + } + + return $data; + } } diff --git a/tests/JsonSchema/Tests/Constraints/BaseTestCase.php b/tests/JsonSchema/Tests/Constraints/BaseTestCase.php index fe351781..903df42b 100644 --- a/tests/JsonSchema/Tests/Constraints/BaseTestCase.php +++ b/tests/JsonSchema/Tests/Constraints/BaseTestCase.php @@ -9,6 +9,8 @@ namespace JsonSchema\Tests\Constraints; +use JsonSchema\RefResolver; +use JsonSchema\Uri\UriRetriever; use JsonSchema\Validator; abstract class BaseTestCase extends \PHPUnit_Framework_TestCase @@ -18,9 +20,14 @@ abstract class BaseTestCase extends \PHPUnit_Framework_TestCase */ public function testInvalidCases($input, $schema, $checkMode = Validator::CHECK_MODE_NORMAL, $errors = array()) { + $schema = json_decode($schema); + + $refResolver = new RefResolver(new UriRetriever); + $refResolver->resolve($schema); + $validator = new Validator($checkMode); - $validator->check(json_decode($input), json_decode($schema)); + $validator->check(json_decode($input), $schema); if (array() !== $errors) { $this->assertEquals($errors, $validator->getErrors(), print_r($validator->getErrors(),true)); @@ -33,13 +40,18 @@ public function testInvalidCases($input, $schema, $checkMode = Validator::CHECK_ */ public function testValidCases($input, $schema, $checkMode = Validator::CHECK_MODE_NORMAL) { + $schema = json_decode($schema); + + $refResolver = new RefResolver(new UriRetriever); + $refResolver->resolve($schema); + $validator = new Validator($checkMode); - $validator->check(json_decode($input), json_decode($schema)); + $validator->check(json_decode($input), $schema); $this->assertTrue($validator->isValid(), print_r($validator->getErrors(), true)); } abstract public function getValidTests(); abstract public function getInvalidTests(); -} \ No newline at end of file +} diff --git a/tests/JsonSchema/Tests/Drafts/Draft4Test.php b/tests/JsonSchema/Tests/Drafts/Draft4Test.php index 3f1d566c..26d2d1c6 100644 --- a/tests/JsonSchema/Tests/Drafts/Draft4Test.php +++ b/tests/JsonSchema/Tests/Drafts/Draft4Test.php @@ -26,4 +26,4 @@ protected function getSkippedTests() ); } -} \ No newline at end of file +}