Skip to content

Commit 6e93f83

Browse files
committed
spec compliance almost there
Tests: 275, Assertions: 275, Failures: 1.
1 parent 4387a72 commit 6e93f83

File tree

5 files changed

+132
-27
lines changed

5 files changed

+132
-27
lines changed

src/RemoteRef/BasicFetcher.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Yaoi\Schema\RemoteRef;
4+
5+
use Yaoi\Schema\RemoteRefProvider;
6+
7+
class BasicFetcher implements RemoteRefProvider
8+
{
9+
public function getSchemaData($url)
10+
{
11+
return json_decode(file_get_contents($url));
12+
}
13+
}

src/RemoteRef/Preloaded.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Yaoi\Schema\RemoteRef;
4+
5+
use Yaoi\Schema\RemoteRefProvider;
6+
7+
class Preloaded implements RemoteRefProvider
8+
{
9+
private $storage;
10+
11+
public function __construct()
12+
{
13+
$this->setSchemaData('http://json-schema.org/draft-04/schema',
14+
json_decode(file_get_contents(__DIR__ . '/../../spec/json-schema.json')));
15+
}
16+
17+
public function getSchemaData($url)
18+
{
19+
if (isset($this->storage[$url])) {
20+
return $this->storage[$url];
21+
}
22+
return false;
23+
}
24+
25+
public function setSchemaData($url, $schemaData)
26+
{
27+
$this->storage[$url] = $schemaData;
28+
return $this;
29+
}
30+
31+
32+
}

src/RemoteRefProvider.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Yaoi\Schema;
4+
5+
6+
interface RemoteRefProvider
7+
{
8+
/**
9+
* @param string $url
10+
* @return \stdClass|false json_decode of $url resource content
11+
*/
12+
public function getSchemaData($url);
13+
}

src/SchemaLoader.php

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Yaoi\Schema\Constraint\Properties;
66
use Yaoi\Schema\Constraint\Ref;
77
use Yaoi\Schema\Constraint\Type;
8+
use Yaoi\Schema\RemoteRef\BasicFetcher;
89

910
class SchemaLoader extends Base
1011
{
@@ -51,6 +52,25 @@ class SchemaLoader extends Base
5152
/** @var Ref[] */
5253
private $refs = array();
5354

55+
/** @var SchemaLoader[] */
56+
private $remoteSchemaLoaders = array();
57+
58+
/** @var RemoteRefProvider */
59+
private $refProvider;
60+
61+
public function setRemoteRefProvider(RemoteRefProvider $provider)
62+
{
63+
$this->refProvider = $provider;
64+
return $this;
65+
}
66+
67+
private function getRefProvider()
68+
{
69+
if (null === $this->refProvider) {
70+
$this->refProvider = new BasicFetcher();
71+
}
72+
return $this->refProvider;
73+
}
5474

5575
public function readSchema($schemaData)
5676
{
@@ -230,35 +250,41 @@ private function resolveReference($referencePath)
230250
{
231251
$ref = &$this->refs[$referencePath];
232252
if (null === $ref) {
233-
if ($referencePath === 'http://json-schema.org/draft-04/schema#') {
234-
$ref = new Ref(
235-
$referencePath,
236-
SchemaLoader::create()->readSchema(json_decode(file_get_contents(__DIR__ . '/../spec/json-schema.json')))
237-
);
238-
} elseif ($referencePath === '#') {
239-
$ref = new Ref($referencePath, $this->rootSchema);
240-
} elseif ($referencePath[0] === '#') {
241-
$path = explode('/', trim($referencePath, '#/'));
242-
$branch = &$this->rootData;
243-
while ($path) {
244-
$folder = array_shift($path);
245-
246-
// unescaping special characters
247-
// https://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07#section-4
248-
// https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/130
249-
$folder = str_replace(array('~0','~1', '%25'), array('~', '/', '%'), $folder);
250-
251-
if ($branch instanceof \stdClass && isset($branch->$folder)) {
252-
$branch = &$branch->$folder;
253-
} elseif (is_array($branch) && isset($branch[$folder])) {
254-
$branch = &$branch[$folder];
255-
} else {
256-
throw new \Exception('Could not resolve ' . $referencePath . ': ' . $folder);
253+
if ($referencePath[0] === '#') {
254+
if ($referencePath === '#') {
255+
$ref = new Ref($referencePath, $this->rootSchema);
256+
} else {
257+
$path = explode('/', trim($referencePath, '#/'));
258+
$branch = &$this->rootData;
259+
while ($path) {
260+
$folder = array_shift($path);
261+
262+
// unescaping special characters
263+
// https://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07#section-4
264+
// https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/130
265+
$folder = str_replace(array('~0', '~1', '%25'), array('~', '/', '%'), $folder);
266+
267+
if ($branch instanceof \stdClass && isset($branch->$folder)) {
268+
$branch = &$branch->$folder;
269+
} elseif (is_array($branch) && isset($branch[$folder])) {
270+
$branch = &$branch[$folder];
271+
} else {
272+
throw new \Exception('Could not resolve ' . $referencePath . ': ' . $folder);
273+
}
257274
}
275+
$ref = new Ref($referencePath, $this->readSchema($branch));
258276
}
259-
$ref = new Ref($referencePath, $this->readSchema($branch));
260277
} else {
261-
throw new \Exception('Could not resolve ' . $referencePath);
278+
$refParts = explode('#', $referencePath);
279+
$url = $refParts[0];
280+
$refLocalPath = isset($refParts[1]) ? '#' . $refParts[1] : '#';
281+
$schemaLoader = &$this->remoteSchemaLoaders[$url];
282+
if (null === $schemaLoader) {
283+
$schemaLoader = SchemaLoader::create();
284+
$schemaLoader->readSchema($this->getRefProvider()->getSchemaData($url));
285+
}
286+
287+
$ref = $schemaLoader->resolveReference($refLocalPath);
262288
}
263289
}
264290

tests/src/PHPUnit/Spec/SpecTest.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Yaoi\Schema\Tests\PHPUnit\Spec;
44

55
use Yaoi\Schema\Exception;
6+
use Yaoi\Schema\RemoteRef\Preloaded;
67
use Yaoi\Schema\SchemaLoader;
78

89
class SpecTest extends \PHPUnit_Framework_TestCase
@@ -16,10 +17,30 @@ class SpecTest extends \PHPUnit_Framework_TestCase
1617
*/
1718
public function testSpecDraft4($schemaData, $data, $isValid)
1819
{
20+
static $refProvider = null;
21+
22+
if (null === $refProvider) {
23+
$refProvider = new Preloaded();
24+
$refProvider
25+
->setSchemaData(
26+
'http://localhost:1234/integer.json',
27+
json_decode(file_get_contents(__DIR__
28+
. '/../../../../spec/JSON-Schema-Test-Suite/remotes/integer.json')))
29+
->setSchemaData(
30+
'http://localhost:1234/subSchemas.json',
31+
json_decode(file_get_contents(__DIR__
32+
. '/../../../../spec/JSON-Schema-Test-Suite/remotes/subSchemas.json')))
33+
->setSchemaData(
34+
'http://localhost:1234/folder/folderInteger.json',
35+
json_decode(file_get_contents(__DIR__
36+
. '/../../../../spec/JSON-Schema-Test-Suite/remotes/folder/folderInteger.json')))
37+
;
38+
}
39+
1940
$actualValid = true;
2041
$error = '';
2142
try {
22-
$schema = SchemaLoader::create()->readSchema($schemaData);
43+
$schema = SchemaLoader::create()->setRemoteRefProvider($refProvider)->readSchema($schemaData);
2344
$res = $schema->import($data);
2445
//$res = $schema->export($res);
2546
} catch (Exception $exception) {

0 commit comments

Comments
 (0)