Skip to content

Commit 5b89a81

Browse files
committed
Fix transitive reference resolving in the current document context
fixes #57
1 parent 497683f commit 5b89a81

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

src/spec/Reference.php

+18
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,24 @@ public function resolve(ReferenceContext $context = null)
174174
// TODO type error if resolved object does not match $this->_to ?
175175
/** @var $referencedObject SpecObjectInterface */
176176
$referencedObject = $jsonReference->getJsonPointer()->evaluate($baseSpec);
177+
// transitive reference
178+
if ($referencedObject instanceof Reference) {
179+
if ($referencedObject->_to === null) {
180+
$referencedObject->_to = $this->_to;
181+
}
182+
$referencedObject->setContext($context);
183+
184+
if ($referencedObject === $this) { // catch recursion
185+
throw new UnresolvableReferenceException('Cyclic reference detected on a Reference Object.');
186+
}
187+
188+
$transitiveRefResult = $referencedObject->resolve();
189+
190+
if ($transitiveRefResult === $this) { // catch recursion
191+
throw new UnresolvableReferenceException('Cyclic reference detected on a Reference Object.');
192+
}
193+
return $transitiveRefResult;
194+
}
177195
if ($referencedObject instanceof SpecObjectInterface) {
178196
$referencedObject->setReferenceContext($context);
179197
}

tests/spec/ReferenceTest.php

+74
Original file line numberDiff line numberDiff line change
@@ -304,4 +304,78 @@ enum:
304304
$this->assertEquals(['Four', 'Five'], $openapi->components->schemas['Pet']->properties['typeD']->enum);
305305
$this->assertEquals(['Five', 'Six'], $openapi->components->schemas['Pet']->properties['typeE']->enum);
306306
}
307+
308+
/**
309+
* References to references fail as "cyclic reference"
310+
* @see https://github.com/cebe/php-openapi/issues/57
311+
*/
312+
public function testTransitiveReference()
313+
{
314+
$schema = <<<'YAML'
315+
openapi: 3.0.2
316+
info:
317+
title: 'City API'
318+
version: dev
319+
paths:
320+
'/city':
321+
get:
322+
description: 'Get City'
323+
responses:
324+
'200':
325+
description: 'success'
326+
content:
327+
application/json:
328+
schema:
329+
$ref: '#/components/schemas/City'
330+
components:
331+
schemas:
332+
City:
333+
$ref: '#/components/schemas/Named'
334+
Named:
335+
type: string
336+
337+
YAML;
338+
339+
$openapi = Reader::readFromYaml($schema);
340+
$openapi->resolveReferences(new \cebe\openapi\ReferenceContext($openapi, 'file:///tmp/openapi.yaml'));
341+
342+
$this->assertTrue(isset($openapi->components->schemas['City']));
343+
$this->assertTrue(isset($openapi->components->schemas['Named']));
344+
$this->assertEquals('string', $openapi->components->schemas['Named']->type);
345+
$this->assertEquals('string', $openapi->components->schemas['City']->type);
346+
$this->assertEquals('string', $openapi->paths['/city']->get->responses[200]->content['application/json']->schema->type);
347+
}
348+
349+
public function testTransitiveReferenceCyclic()
350+
{
351+
$schema = <<<'YAML'
352+
openapi: 3.0.2
353+
info:
354+
title: 'City API'
355+
version: dev
356+
paths:
357+
'/city':
358+
get:
359+
description: 'Get City'
360+
responses:
361+
'200':
362+
description: 'success'
363+
content:
364+
application/json:
365+
schema:
366+
$ref: '#/components/schemas/City'
367+
components:
368+
schemas:
369+
City:
370+
$ref: '#/components/schemas/City'
371+
372+
YAML;
373+
374+
$openapi = Reader::readFromYaml($schema);
375+
376+
$this->expectException(\cebe\openapi\exceptions\UnresolvableReferenceException::class);
377+
$this->expectExceptionMessage('Cyclic reference detected on a Reference Object.');
378+
379+
$openapi->resolveReferences(new \cebe\openapi\ReferenceContext($openapi, 'file:///tmp/openapi.yaml'));
380+
}
307381
}

0 commit comments

Comments
 (0)