Skip to content

Commit 4ac7f41

Browse files
committed
keep intermediate references in path
1 parent dfe67fc commit 4ac7f41

File tree

7 files changed

+177
-13
lines changed

7 files changed

+177
-13
lines changed

src/Schema.php

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,25 +1025,35 @@ public function process($data, Context $options, $path = '#', $result = null)
10251025
if ('#' === $path) {
10261026
$injectDefinitions = new ScopeExit(function () use ($result, $options) {
10271027
foreach ($options->exportedDefinitions as $ref => $data) {
1028-
JsonPointer::add($result, JsonPointer::splitPath($ref), $data,
1029-
JsonPointer::SKIP_IF_ISSET + JsonPointer::RECURSIVE_KEY_CREATION);
1028+
if ($data !== null) {
1029+
JsonPointer::add($result, JsonPointer::splitPath($ref), $data,
1030+
/*JsonPointer::SKIP_IF_ISSET + */
1031+
JsonPointer::RECURSIVE_KEY_CREATION);
1032+
}
10301033
}
10311034
});
10321035
}
10331036

1034-
if ('#' !== $path && $ref = $data->getFromRef()) {
1035-
if ($ref[0] === '#') {
1036-
if (isset($options->exportedDefinitions[$ref])) {
1037-
$result->{self::PROP_REF} = $ref;
1038-
return $result;
1039-
} elseif (!array_key_exists($ref, $options->exportedDefinitions)) {
1040-
$exported = null;
1041-
$options->exportedDefinitions[$ref] = &$exported;
1042-
$exported = $this->process($data, $options, $ref);
1043-
$result->{self::PROP_REF} = $ref;
1044-
return $result;
1037+
if ('#' !== $path && $refs = $data->getFromRefs()) {
1038+
$ref = $refs[0];
1039+
if (!array_key_exists($ref, $options->exportedDefinitions)) {
1040+
$exported = null;
1041+
$options->exportedDefinitions[$ref] = &$exported;
1042+
$exported = $this->process($data, $options /*, $ref*/);
1043+
unset($exported);
1044+
}
1045+
1046+
for ($i = 1; $i < count($refs); $i++) {
1047+
$ref = $refs[$i];
1048+
if (!array_key_exists($ref, $options->exportedDefinitions)) {
1049+
$exported = new \stdClass();
1050+
$exported->{self::PROP_REF} = $refs[$i-1];
1051+
$options->exportedDefinitions[$ref] = $exported;
10451052
}
10461053
}
1054+
1055+
$result->{self::PROP_REF} = $refs[count($refs) - 1];
1056+
return $result;
10471057
}
10481058

10491059
if ($options->circularReferences->contains($data)) {

src/Structure/ObjectItem.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
namespace Swaggest\JsonSchema\Structure;
44

5+
/**
6+
* @method getNestedObject($className);
7+
* @method setNestedProperty($propertyName, $value, Egg $nestedEgg);
8+
* @method addAdditionalPropertyName($name);
9+
* @method setDocumentPath($path);
10+
* @method setFromRef($ref);
11+
* @method string|null getFromRef();
12+
* @method string[]|null getFromRefs();
13+
*/
514
class ObjectItem implements ObjectItemContract
615
{
716
use ObjectItemTrait;

src/Structure/ObjectItemContract.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,15 @@ public function setNestedProperty($propertyName, $value, Egg $nestedEgg);
1010
public function addAdditionalPropertyName($name);
1111
public function setDocumentPath($path);
1212
public function setFromRef($ref);
13+
14+
/**
15+
* @return string
16+
* @deprecated
17+
*/
1318
public function getFromRef();
19+
20+
/**
21+
* @return string[]|null
22+
*/
23+
public function getFromRefs();
1424
}

src/Structure/ObjectItemTrait.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,31 @@ public function setDocumentPath($path)
104104
}
105105

106106
/**
107+
* @see ObjectItemContract::getFromRef
108+
* @deprecated use ObjectItemContract::getFromRefs
109+
* @see ObjectItemContract::getFromRefs
110+
* @todo remove
107111
* @return string
108112
*/
109113
public function getFromRef()
110114
{
111115
return null === $this->__fromRef ? null : $this->__fromRef[0];
112116
}
113117

118+
/**
119+
* @see ObjectItemContract::getFromRef
120+
* @return string
121+
*/
122+
public function getFromRefs()
123+
{
124+
return $this->__fromRef;
125+
}
126+
127+
/**
128+
* @see ObjectItemContract::setFromRef
129+
* @param string $ref
130+
* @return $this
131+
*/
114132
public function setFromRef($ref)
115133
{
116134
if (null === $this->__fromRef) {

tests/src/Helper/DeepRefProperty.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema\Tests\Helper;
4+
5+
use Swaggest\JsonSchema\Constraint\Properties;
6+
use Swaggest\JsonSchema\Schema;
7+
use Swaggest\JsonSchema\Structure\ClassStructure;
8+
9+
class DeepRefProperty extends ClassStructure
10+
{
11+
/**
12+
* @param Properties|static $properties
13+
* @param Schema $ownerSchema
14+
*/
15+
public static function setUpProperties($properties, Schema $ownerSchema)
16+
{
17+
$ownerSchema->type = Schema::OBJECT;
18+
$ownerSchema->setFromRef('#/definitions/lvlA');
19+
$ownerSchema->setFromRef('#/definitions/lvlB');
20+
$ownerSchema->setFromRef('#/definitions/lvlC');
21+
$ownerSchema->setFromRef('#/definitions/lvlD');
22+
}
23+
24+
25+
}

tests/src/Helper/DeepRefRoot.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema\Tests\Helper;
4+
5+
6+
use Swaggest\JsonSchema\Constraint\Properties;
7+
use Swaggest\JsonSchema\Schema;
8+
use Swaggest\JsonSchema\Structure\ClassStructure;
9+
10+
class DeepRefRoot extends ClassStructure
11+
{
12+
public $prop;
13+
14+
/**
15+
* @param Properties|static $properties
16+
* @param Schema $ownerSchema
17+
*/
18+
public static function setUpProperties($properties, Schema $ownerSchema)
19+
{
20+
$properties->prop = DeepRefProperty::schema();
21+
$ownerSchema->type = Schema::STRING;
22+
}
23+
}

tests/src/PHPUnit/ClassStructure/ExportSchemaTest.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use Swaggest\JsonSchema\Schema;
77
use Swaggest\JsonSchema\Tests\Helper\DbId;
8+
use Swaggest\JsonSchema\Tests\Helper\DeepRefRoot;
89

910
class ExportSchemaTest extends \PHPUnit_Framework_TestCase
1011
{
@@ -34,4 +35,72 @@ public function testSchemaExport()
3435
$this->assertSame($expected, json_encode($schemaData, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES));
3536
}
3637

38+
public function testDeepRef()
39+
{
40+
$schema = DeepRefRoot::schema();
41+
$schemaData = Schema::export($schema);
42+
43+
$expected = <<<'JSON'
44+
{
45+
"properties": {
46+
"prop": {
47+
"$ref": "#/definitions/lvlD"
48+
}
49+
},
50+
"type": "string",
51+
"definitions": {
52+
"lvlA": {
53+
"type": "object"
54+
},
55+
"lvlB": {
56+
"$ref": "#/definitions/lvlA"
57+
},
58+
"lvlC": {
59+
"$ref": "#/definitions/lvlB"
60+
},
61+
"lvlD": {
62+
"$ref": "#/definitions/lvlC"
63+
}
64+
}
65+
}
66+
JSON;
67+
68+
$this->assertSame($expected, json_encode($schemaData, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES));
69+
70+
71+
}
72+
73+
public function testDeepRefSchema()
74+
{
75+
$schemaJson = <<<'JSON'
76+
{
77+
"definitions": {
78+
"lvl1": {
79+
"$ref": "#/definitions/lvl2"
80+
},
81+
"lvl2": {
82+
"$ref": "#/definitions/lvl3"
83+
},
84+
"lvl3": {
85+
"$ref": "#/definitions/lvl4"
86+
},
87+
"lvl4": {
88+
"type": "integer"
89+
}
90+
},
91+
"properties": {
92+
"prop": {
93+
"$ref": "#/definitions/lvl1"
94+
}
95+
},
96+
"type": "object"
97+
}
98+
JSON;
99+
$schemaData = json_decode($schemaJson);
100+
101+
$schema = Schema::import($schemaData);
102+
$exported = Schema::export($schema);
103+
$this->assertSame($schemaJson, json_encode($exported, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES));
104+
}
105+
37106
}

0 commit comments

Comments
 (0)