diff --git a/src/spec/Reference.php b/src/spec/Reference.php index f1df189..279fbe9 100644 --- a/src/spec/Reference.php +++ b/src/spec/Reference.php @@ -289,7 +289,9 @@ private function resolveTransitiveReference(Reference $referencedObject, Referen return $transitiveRefResult; } - // adjust relative refernces inside of the file to match the context of the base file + /** + * Adjust relative references inside of the file to match the context of the base file + */ private function adjustRelativeReferences($referencedDocument, $basePath, $baseDocument = null, $oContext = null) { $context = new ReferenceContext(null, $basePath); @@ -298,6 +300,7 @@ private function adjustRelativeReferences($referencedDocument, $basePath, $baseD } foreach ($referencedDocument as $key => $value) { + // adjust reference URLs if ($key === '$ref' && is_string($value)) { if (isset($value[0]) && $value[0] === '#') { // direcly inline references in the same document, @@ -309,9 +312,17 @@ private function adjustRelativeReferences($referencedDocument, $basePath, $baseD $parts = explode('#', $referencedDocument[$key], 2); if ($parts[0] === $oContext->getUri()) { $referencedDocument[$key] = '#' . ($parts[1] ?? ''); + } else { + $referencedDocument[$key] = $this->makeRelativePath($oContext->getUri(), $referencedDocument[$key]); } continue; } + // adjust URLs for 'externalValue' references in Example Objects + // https://spec.openapis.org/oas/v3.0.3#example-object + if ($key === 'externalValue' && is_string($value)) { + $referencedDocument[$key] = $this->makeRelativePath($oContext->getUri(), $context->resolveRelativeUri($value)); + continue; + } if (is_array($value)) { $referencedDocument[$key] = $this->adjustRelativeReferences($value, $basePath, $baseDocument, $oContext); } @@ -319,6 +330,20 @@ private function adjustRelativeReferences($referencedDocument, $basePath, $baseD return $referencedDocument; } + /** + * If $path can be expressed relative to $base, make it a relative path, otherwise $path is returned. + * @param string $base + * @param string $path + */ + private function makeRelativePath($base, $path) + { + if (strpos($path, dirname($base)) === 0) { + return '.' . DIRECTORY_SEPARATOR . substr($path, strlen(dirname($base) . DIRECTORY_SEPARATOR)); + } + + return $path; + } + /** * Resolves all Reference Objects in this object and replaces them with their resolution. * @throws UnresolvableReferenceException diff --git a/tests/spec/ReferenceTest.php b/tests/spec/ReferenceTest.php index 124a1e4..4448da3 100644 --- a/tests/spec/ReferenceTest.php +++ b/tests/spec/ReferenceTest.php @@ -484,6 +484,16 @@ public function testReferencedCommonParamsInReferencedPath() responses: '200': description: 'OK if common params can be references' + request: + content: + application/json: + examples: + user: + summary: 'User Example' + externalValue: ./paths/examples/user-example.json + userex: + summary: 'External User Example' + externalValue: 'https://api.example.com/examples/user-example.json' parameters: - name: test diff --git a/tests/spec/data/reference/paths/ReferencesCommonParams.yml b/tests/spec/data/reference/paths/ReferencesCommonParams.yml index 514d9a9..5513a53 100644 --- a/tests/spec/data/reference/paths/ReferencesCommonParams.yml +++ b/tests/spec/data/reference/paths/ReferencesCommonParams.yml @@ -5,3 +5,13 @@ get: responses: 200: description: OK if common params can be references + request: + content: + application/json: + examples: + "user": + "summary": "User Example" + "externalValue": "./examples/user-example.json" + "userex": + "summary": "External User Example" + "externalValue": "https://api.example.com/examples/user-example.json" diff --git a/tests/spec/data/reference/paths/examples/user-example.json b/tests/spec/data/reference/paths/examples/user-example.json new file mode 100644 index 0000000..c6f2c4b --- /dev/null +++ b/tests/spec/data/reference/paths/examples/user-example.json @@ -0,0 +1,6 @@ +{ + "type": "user", + "properties": { + "name": "John" + } +}