Skip to content

Commit 23b6709

Browse files
authored
Merge pull request #80 from swaggest/fault-tolerant-dereferencing
Do not fail validation of dereferenced value if original data is valid
2 parents 914d076 + d310a1f commit 23b6709

File tree

5 files changed

+109
-3
lines changed

5 files changed

+109
-3
lines changed

src/Schema.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Swaggest\JsonSchema\Structure\Egg;
2626
use Swaggest\JsonSchema\Structure\ObjectItem;
2727
use Swaggest\JsonSchema\Structure\ObjectItemContract;
28+
use Swaggest\JsonSchema\Structure\WithResolvedValue;
2829

2930
/**
3031
* Class Schema
@@ -702,6 +703,7 @@ private function processObject($data, Context $options, $path, $result = null)
702703
});
703704

704705
$ref = $refResolver->resolveReference($refString);
706+
$unresolvedData = $data;
705707
$data = self::unboolSchemaData($ref->getData());
706708
if (!$options->validateOnly) {
707709
if ($ref->isImported()) {
@@ -710,6 +712,7 @@ private function processObject($data, Context $options, $path, $result = null)
710712
}
711713
$ref->setImported($result);
712714
try {
715+
// Best effort dereference delivery.
713716
$refResult = $this->process($data, $options, $path . '->$ref:' . $refString, $result);
714717
if ($refResult instanceof ObjectItemContract) {
715718
if ($refResult->getFromRefs()) {
@@ -718,11 +721,28 @@ private function processObject($data, Context $options, $path, $result = null)
718721
$refResult->setFromRef($refString);
719722
}
720723
$ref->setImported($refResult);
724+
return $refResult;
721725
} catch (InvalidValue $exception) {
722726
$ref->unsetImported();
723-
throw $exception;
727+
$skipValidation = $options->skipValidation;
728+
$options->skipValidation = true;
729+
$refResult = $this->process($data, $options, $path . '->$ref:' . $refString);
730+
if ($refResult instanceof ObjectItemContract) {
731+
if ($refResult->getFromRefs()) {
732+
$refResult = clone $refResult; // @todo check performance, consider option
733+
}
734+
$refResult->setFromRef($refString);
735+
}
736+
$ref->setImported($refResult);
737+
$options->skipValidation = $skipValidation;
738+
739+
if ($result instanceof WithResolvedValue) {
740+
$result->setResolvedValue($refResult);
741+
}
742+
743+
// Proceeding with unresolved data.
744+
$data = $unresolvedData;
724745
}
725-
return $refResult;
726746
} else {
727747
$this->process($data, $options, $path . '->$ref:' . $refString);
728748
}

src/Structure/ObjectItem.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* @method string|null getFromRef();
1212
* @method string[]|null getFromRefs();
1313
*/
14-
class ObjectItem implements ObjectItemContract
14+
class ObjectItem implements ObjectItemContract, WithResolvedValue
1515
{
1616
use ObjectItemTrait;
1717
}

src/Structure/ObjectItemTrait.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@ trait ObjectItemTrait
1919
/** @var null|string[] */
2020
protected $__fromRef;
2121

22+
protected $__hasResolvedValue = false;
23+
protected $__resolvedValue;
24+
25+
public function setResolvedValue($value)
26+
{
27+
$this->__hasResolvedValue = true;
28+
$this->__resolvedValue = $value;
29+
return $this;
30+
}
31+
32+
public function getResolvedValue()
33+
{
34+
return $this->__resolvedValue;
35+
}
36+
37+
public function hasResolvedValue()
38+
{
39+
return $this->__hasResolvedValue;
40+
}
41+
2242
public function getNestedObject($className)
2343
{
2444
if (isset($this->__nestedObjects[$className])) {

src/Structure/WithResolvedValue.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
4+
namespace Swaggest\JsonSchema\Structure;
5+
6+
7+
interface WithResolvedValue
8+
{
9+
public function setResolvedValue($value);
10+
11+
public function getResolvedValue();
12+
13+
public function hasResolvedValue();
14+
15+
}

tests/resources/suite/oneOfRef.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
[
2+
{
3+
"description": "oneOfRef",
4+
"schema": {
5+
"oneOf": [
6+
{
7+
"type": "object",
8+
"required": [
9+
"$ref"
10+
],
11+
"properties": {
12+
"$ref": {
13+
"type": "string",
14+
"format": "uri-reference"
15+
}
16+
}
17+
},
18+
{
19+
"type": "object",
20+
"required": [
21+
"dataKey"
22+
]
23+
}
24+
]
25+
},
26+
"tests": [
27+
{
28+
"description": "valid against data",
29+
"data": {
30+
"dataKey": true
31+
},
32+
"valid": true
33+
},
34+
{
35+
"description": "valid against reference",
36+
"data": {
37+
"$ref": "#/container",
38+
"container": {
39+
"dataKey": true
40+
}
41+
},
42+
"valid": true
43+
},
44+
{
45+
"description": "invalid against not an object",
46+
"data": 123,
47+
"valid": false
48+
}
49+
]
50+
}
51+
]

0 commit comments

Comments
 (0)