Skip to content

Commit 497683f

Browse files
committed
Fix recursion issue with reading references which are included multiple times
fixes #44
1 parent 0158fec commit 497683f

File tree

3 files changed

+79
-18
lines changed

3 files changed

+79
-18
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
TESTCASE=
2-
PHPARGS=
3-
#PHPARGS=-dzend_extension=xdebug.so -dxdebug.remote_enable=1
2+
PHPARGS=-dmemory_limit=64M
3+
#PHPARGS=-dmemory_limit=64M -dzend_extension=xdebug.so -dxdebug.remote_enable=1
44

55
all:
66

@@ -18,10 +18,13 @@ install:
1818

1919
test:
2020
php $(PHPARGS) vendor/bin/phpunit $(TESTCASE)
21+
php $(PHPARGS) bin/php-openapi validate tests/spec/data/recursion.json
22+
php $(PHPARGS) bin/php-openapi validate tests/spec/data/recursion2.yaml
2123

2224
lint:
2325
php $(PHPARGS) bin/php-openapi validate tests/spec/data/reference/playlist.json
2426
php $(PHPARGS) bin/php-openapi validate tests/spec/data/recursion.json
27+
php $(PHPARGS) bin/php-openapi validate tests/spec/data/recursion2.yaml
2528
node_modules/.bin/speccy lint tests/spec/data/reference/playlist.json
2629
node_modules/.bin/speccy lint tests/spec/data/recursion.json
2730

src/SpecBaseObject.php

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ abstract class SpecBaseObject implements SpecObjectInterface, DocumentContextInt
2424
{
2525
private $_properties = [];
2626
private $_errors = [];
27-
private $_recursing = false;
27+
28+
private $_recursingSerializableData = false;
29+
private $_recursingValidate = false;
30+
private $_recursingErrors = false;
31+
private $_recursingReferences = false;
32+
private $_recursingReferenceContext = false;
33+
private $_recursingDocumentContext = false;
2834

2935
private $_baseDocument;
3036
private $_jsonPointer;
@@ -168,11 +174,11 @@ protected function instantiate($type, $data)
168174
*/
169175
public function getSerializableData()
170176
{
171-
if ($this->_recursing) {
177+
if ($this->_recursingSerializableData) {
172178
// return a reference
173179
return (object) ['$ref' => JsonReference::createFromUri('', $this->getDocumentPosition())->getReference()];
174180
}
175-
$this->_recursing = true;
181+
$this->_recursingSerializableData = true;
176182

177183
$data = $this->_properties;
178184
foreach ($data as $k => $v) {
@@ -195,7 +201,7 @@ public function getSerializableData()
195201
}
196202
}
197203

198-
$this->_recursing = false;
204+
$this->_recursingSerializableData = false;
199205

200206
return (object) $data;
201207
}
@@ -208,10 +214,10 @@ public function getSerializableData()
208214
public function validate(): bool
209215
{
210216
// avoid recursion to get stuck in a loop
211-
if ($this->_recursing) {
217+
if ($this->_recursingValidate) {
212218
return true;
213219
}
214-
$this->_recursing = true;
220+
$this->_recursingValidate = true;
215221
$valid = true;
216222
foreach ($this->_properties as $v) {
217223
if ($v instanceof SpecObjectInterface) {
@@ -228,7 +234,7 @@ public function validate(): bool
228234
}
229235
}
230236
}
231-
$this->_recursing = false;
237+
$this->_recursingValidate = false;
232238

233239
$this->performValidation();
234240

@@ -246,10 +252,10 @@ public function validate(): bool
246252
public function getErrors(): array
247253
{
248254
// avoid recursion to get stuck in a loop
249-
if ($this->_recursing) {
255+
if ($this->_recursingErrors) {
250256
return [];
251257
}
252-
$this->_recursing = true;
258+
$this->_recursingErrors = true;
253259

254260
if (($pos = $this->getDocumentPosition()) !== null) {
255261
$errors = [
@@ -272,7 +278,7 @@ public function getErrors(): array
272278
}
273279
}
274280

275-
$this->_recursing = false;
281+
$this->_recursingErrors = false;
276282

277283
return array_merge(...$errors);
278284
}
@@ -360,10 +366,10 @@ public function __unset($name)
360366
public function resolveReferences(ReferenceContext $context = null)
361367
{
362368
// avoid recursion to get stuck in a loop
363-
if ($this->_recursing) {
369+
if ($this->_recursingReferences) {
364370
return;
365371
}
366-
$this->_recursing = true;
372+
$this->_recursingReferences = true;
367373

368374
foreach ($this->_properties as $property => $value) {
369375
if ($value instanceof Reference) {
@@ -389,14 +395,20 @@ public function resolveReferences(ReferenceContext $context = null)
389395
}
390396
}
391397

392-
$this->_recursing = false;
398+
$this->_recursingReferences = false;
393399
}
394400

395401
/**
396402
* Set context for all Reference Objects in this object.
397403
*/
398404
public function setReferenceContext(ReferenceContext $context)
399405
{
406+
// avoid recursion to get stuck in a loop
407+
if ($this->_recursingReferenceContext) {
408+
return;
409+
}
410+
$this->_recursingReferenceContext = true;
411+
400412
foreach ($this->_properties as $property => $value) {
401413
if ($value instanceof Reference) {
402414
$value->setContext($context);
@@ -412,6 +424,8 @@ public function setReferenceContext(ReferenceContext $context)
412424
}
413425
}
414426
}
427+
428+
$this->_recursingReferenceContext = false;
415429
}
416430

417431
/**
@@ -428,10 +442,10 @@ public function setDocumentContext(SpecObjectInterface $baseDocument, JsonPointe
428442
$this->_jsonPointer = $jsonPointer;
429443

430444
// avoid recursion to get stuck in a loop
431-
if ($this->_recursing) {
445+
if ($this->_recursingDocumentContext) {
432446
return;
433447
}
434-
$this->_recursing = true;
448+
$this->_recursingDocumentContext = true;
435449

436450
foreach ($this->_properties as $property => $value) {
437451
if ($value instanceof DocumentContextInterface) {
@@ -445,7 +459,7 @@ public function setDocumentContext(SpecObjectInterface $baseDocument, JsonPointe
445459
}
446460
}
447461

448-
$this->_recursing = false;
462+
$this->_recursingDocumentContext = false;
449463
}
450464

451465
/**

tests/spec/data/recursion2.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
openapi: 3.0.2
2+
info:
3+
title: My API
4+
version: "123"
5+
components:
6+
schemas:
7+
SomeResponse:
8+
type: object
9+
properties:
10+
name:
11+
type: string
12+
description: Name of SomeResponse
13+
recursive:
14+
$ref: '#/components/schemas/RecursiveItem'
15+
16+
AnotherResponse:
17+
type: object
18+
properties:
19+
uuid:
20+
type: string
21+
format: uuid
22+
description: UUID of AnotherResponse
23+
recursive:
24+
$ref: '#/components/schemas/RecursiveItem'
25+
26+
27+
RecursiveItem:
28+
type: object
29+
properties:
30+
children:
31+
type: array
32+
items:
33+
oneOf:
34+
- $ref: '#/components/schemas/RecursiveItem'
35+
- $ref: '#/components/schemas/SomeResponse'
36+
37+
38+
paths:
39+
'/':
40+
get:
41+
description: default
42+
responses:
43+
200:
44+
description: ok

0 commit comments

Comments
 (0)