Skip to content

Commit

Permalink
Merge pull request #41 from cebe/more-reference-issues
Browse files Browse the repository at this point in the history
Fix issue with loading reference that points to a reference
  • Loading branch information
cebe authored Oct 29, 2019
2 parents 3d86fa6 + cc41b57 commit 1316f57
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 11 deletions.
8 changes: 8 additions & 0 deletions src/SpecBaseObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,12 @@ public function setDocumentContext(SpecObjectInterface $baseDocument, JsonPointe
$this->_baseDocument = $baseDocument;
$this->_jsonPointer = $jsonPointer;

// avoid recursion to get stuck in a loop
if ($this->_recursing) {
return;
}
$this->_recursing = true;

foreach ($this->_properties as $property => $value) {
if ($value instanceof DocumentContextInterface) {
$value->setDocumentContext($baseDocument, $jsonPointer->append($property));
Expand All @@ -422,6 +428,8 @@ public function setDocumentContext(SpecObjectInterface $baseDocument, JsonPointe
}
}
}

$this->_recursing = false;
}

/**
Expand Down
16 changes: 10 additions & 6 deletions src/spec/Reference.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,16 @@ public function resolve(ReferenceContext $context = null)
if ($referencedData === null) {
return null;
}
/** @var $referencedObject SpecObjectInterface */
$referencedObject = new $this->_to($referencedData);

// transitive reference
if (isset($referencedData['$ref'])) {
return (new Reference($referencedData, $this->_to))->resolve(new ReferenceContext(null, $file));
} else {
/** @var $referencedObject SpecObjectInterface */
$referencedObject = new $this->_to($referencedData);
}
if ($jsonReference->getJsonPointer()->getPointer() === '') {
$newContext = new ReferenceContext($referencedObject, $file);
$newContext->throwException = $context->throwException;
$referencedObject->setReferenceContext($newContext);
if ($referencedObject instanceof DocumentContextInterface) {
$referencedObject->setDocumentContext($referencedObject, $jsonReference->getJsonPointer());
}
Expand All @@ -206,9 +210,9 @@ public function resolve(ReferenceContext $context = null)
// the whole document. We do not know the base type of the file at this point,
// so base document must be null.
$newContext = new ReferenceContext(null, $file);
$newContext->throwException = $context->throwException;
$referencedObject->setReferenceContext($newContext);
}
$newContext->throwException = $context->throwException;
$referencedObject->setReferenceContext($newContext);

return $referencedObject;
} catch (NonexistentJsonPointerReferenceException $e) {
Expand Down
23 changes: 18 additions & 5 deletions tests/spec/ReferenceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use cebe\openapi\Reader;
use cebe\openapi\spec\OpenApi;
use cebe\openapi\spec\Parameter;
use cebe\openapi\spec\Reference;
use cebe\openapi\spec\RequestBody;
use cebe\openapi\spec\Response;
Expand Down Expand Up @@ -178,17 +179,22 @@ public function testResolveFileInSubdir()
$this->assertEquals([], $openapi->getErrors());
$this->assertTrue($result);

$this->assertInstanceOf(Reference::class, $petItems = $openapi->components->schemas['Pet']);
$this->assertInstanceOf(Reference::class, $petItems = $openapi->components->schemas['Dog']);
$this->assertInstanceOf(Reference::class, $openapi->components->schemas['Pet']);
$this->assertInstanceOf(Reference::class, $openapi->components->schemas['Dog']);
$this->assertInstanceOf(Reference::class, $openapi->components->parameters['Parameter.PetId']);

$openapi->resolveReferences(new \cebe\openapi\ReferenceContext($openapi, $file));

$this->assertInstanceOf(Schema::class, $petItems = $openapi->components->schemas['Pet']);
$this->assertInstanceOf(Schema::class, $petItems = $openapi->components->schemas['Dog']);
$this->assertInstanceOf(Schema::class, $openapi->components->schemas['Pet']);
$this->assertInstanceOf(Schema::class, $openapi->components->schemas['Dog']);
$this->assertInstanceOf(Parameter::class, $openapi->components->parameters['Parameter.PetId']);
$this->assertArrayHasKey('id', $openapi->components->schemas['Pet']->properties);
$this->assertArrayHasKey('name', $openapi->components->schemas['Dog']->properties);
$this->assertEquals('petId', $openapi->components->parameters['Parameter.PetId']->name);
$this->assertInstanceOf(Schema::class, $openapi->components->parameters['Parameter.PetId']->schema);
$this->assertEquals('integer', $openapi->components->parameters['Parameter.PetId']->schema->type);

// second level reference inside of definitions.yaml
// second level references
$this->assertArrayHasKey('food', $openapi->components->schemas['Dog']->properties);
$this->assertInstanceOf(Schema::class, $openapi->components->schemas['Dog']->properties['food']);
$this->assertArrayHasKey('id', $openapi->components->schemas['Dog']->properties['food']->properties);
Expand All @@ -199,6 +205,13 @@ public function testResolveFileInSubdir()
$responseContent = $openapi->paths->getPath('/pets')->get->responses[200]->content['application/json'];
$this->assertInstanceOf(Schema::class, $responseContent->schema);
$this->assertEquals('A Pet', $responseContent->schema->description);

// third level reference back to original file
$this->assertCount(1, $parameters = $openapi->paths->getPath('/pets')->get->parameters);
$parameter = reset($parameters);
$this->assertEquals('petId', $parameter->name);
$this->assertInstanceOf(Schema::class, $parameter->schema);
$this->assertEquals('integer', $parameter->schema->type);
}

public function testResolveFileHttp()
Expand Down
3 changes: 3 additions & 0 deletions tests/spec/data/reference/paths/pets.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"get": {
"parameters": [
{"$ref": "../subdir.yaml#/components/parameters/Parameter.PetId"}
],
"responses": {
"200": {
"description": "return a pet",
Expand Down
3 changes: 3 additions & 0 deletions tests/spec/data/reference/subdir.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ components:
$ref: 'subdir/Pet.yaml'
Dog:
$ref: 'subdir/Dog.yaml'
parameters:
"Parameter.PetId":
"$ref": "./subdir/Parameter.PetId.json"
paths:
'/pet':
get:
Expand Down
10 changes: 10 additions & 0 deletions tests/spec/data/reference/subdir/Parameter.PetId.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "petId",
"description": "Represents the id of a pet",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"style": "simple"
}

0 comments on commit 1316f57

Please sign in to comment.