@@ -58,6 +58,8 @@ class Reference implements SpecObjectInterface, DocumentContextInterface
58
58
*/
59
59
private $ _errors = [];
60
60
61
+ private $ _recursingInsideFile = false ;
62
+
61
63
/**
62
64
* Create an object from spec data.
63
65
* @param array $data spec data read from YAML or JSON
@@ -330,50 +332,83 @@ private function resolveTransitiveReference(Reference $referencedObject, Referen
330
332
private $ _recursingInsideFile = false ;
331
333
332
334
/**
333
- * Adjust relative references inside of the file to match the context of the base file
334
- */
335
- private function adjustRelativeReferences ($ referencedDocument , $ basePath , $ baseDocument = null , $ oContext = null )
335
+ * Adjust relative references inside the file to match the context of the base file
336
+ *
337
+ * @noinspection PhpConditionAlreadyCheckedInspection*/
338
+ private function adjustRelativeReferences ($ referencedDocument , $ basePath , $ baseDocument = null , ?ReferenceContext $ oContext = null )
336
339
{
340
+
337
341
$ context = new ReferenceContext (null , $ basePath );
342
+
338
343
if ($ baseDocument === null ) {
339
344
$ baseDocument = $ referencedDocument ;
340
345
}
341
346
342
347
foreach ($ referencedDocument as $ key => $ value ) {
343
- // adjust reference URLs
344
- if ($ key === '$ref ' && is_string ($ value )) {
345
- if (isset ($ value [0 ]) && $ value [0 ] === '# ' ) {
346
- // direcly inline references in the same document,
347
- // these are not going to be valid in the new context anymore
348
- $ inlineDocument = (new JsonPointer (substr ($ value , 1 )))->evaluate ($ baseDocument );
349
- if ($ this ->_recursingInsideFile ) {
350
- // keep reference when it is a recursive reference
351
- return ['$ref ' => $ basePath . $ value ];
352
- }
353
- $ this ->_recursingInsideFile = true ;
354
- $ return = $ this ->adjustRelativeReferences ($ inlineDocument , $ basePath , $ baseDocument , $ oContext );
355
- $ this ->_recursingInsideFile = false ;
356
- return $ return ;
357
- }
358
- $ referencedDocument [$ key ] = $ context ->resolveRelativeUri ($ value );
359
- $ parts = explode ('# ' , $ referencedDocument [$ key ], 2 );
360
- if ($ parts [0 ] === $ oContext ->getUri ()) {
361
- $ referencedDocument [$ key ] = '# ' . ($ parts [1 ] ?? '' );
362
- } else {
363
- $ referencedDocument [$ key ] = $ this ->makeRelativePath ($ oContext ->getUri (), $ referencedDocument [$ key ]);
364
- }
348
+
349
+ if (is_array ($ value ) === true ) {
350
+ $ referencedDocument [$ key ] = $ this ->adjustRelativeReferences ($ value , $ basePath , $ baseDocument , $ oContext );
365
351
continue ;
366
352
}
367
- // adjust URLs for 'externalValue' references in Example Objects
368
- // https://spec.openapis.org/oas/v3.0.3#example-object
369
- if ($ key === 'externalValue ' && is_string ($ value )) {
370
- $ referencedDocument [$ key ] = $ this ->makeRelativePath ($ oContext ->getUri (), $ context ->resolveRelativeUri ($ value ));
353
+
354
+ // non strings can't be references
355
+ if (is_string ($ value ) === false ) {
371
356
continue ;
372
357
}
373
- if (is_array ($ value )) {
374
- $ referencedDocument [$ key ] = $ this ->adjustRelativeReferences ($ value , $ basePath , $ baseDocument , $ oContext );
358
+
359
+ // $this->_to does not apply here
360
+ $ fullPath = $ basePath . $ value ;
361
+ $ cachePointer = $ fullPath ;
362
+ $ cacheType = 'relativeReference ' ;
363
+
364
+ if ($ context ->getCache ()->has ($ cachePointer , $ cacheType )) {
365
+ return $ context ->getCache ()->get ($ cachePointer , $ cacheType );
366
+ }
367
+
368
+ // directly inline references in the same document,
369
+ // these are not going to be valid in the new context anymore
370
+ if ($ key === '$ref ' && str_starts_with ($ value , '# ' )) {
371
+
372
+ $ inlineDocument = (new JsonPointer (substr ($ value , 1 )))->evaluate ($ baseDocument );
373
+
374
+ // keep reference when it is a recursive reference
375
+ if ($ this ->_recursingInsideFile ) {
376
+ return ['$ref ' => $ fullPath ];
377
+ }
378
+
379
+ $ this ->_recursingInsideFile = true ;
380
+ $ return = $ this ->adjustRelativeReferences ($ inlineDocument , $ basePath , $ baseDocument , $ oContext );
381
+ $ this ->_recursingInsideFile = false ;
382
+
383
+ $ context ->getCache ()->set ($ cachePointer , $ cacheType , $ return );
384
+
385
+ return $ return ;
375
386
}
387
+
388
+ $ oContextUri = $ oContext ->getUri ();
389
+ $ resolvedUri = $ context ->resolveRelativeUri ($ value );
390
+
391
+ // adjust reference URLs
392
+ if ($ key === '$ref ' ) {
393
+
394
+ if (str_starts_with ($ resolvedUri , $ oContextUri )) {
395
+ $ fragment = str_replace ($ oContextUri , '' , $ resolvedUri );
396
+ $ referencedDocument [$ key ] = $ fragment ?: '# ' ;
397
+ } else {
398
+ $ referencedDocument [$ key ] = $ this ->makeRelativePath ($ oContextUri , $ resolvedUri );
399
+ }
400
+ }
401
+
402
+ // adjust externalValue fields https://spec.openapis.org/oas/v3.0.3#example-object
403
+ if ($ key === 'externalValue ' ) {
404
+ $ referencedDocument [$ key ] = $ this ->makeRelativePath ($ oContextUri , $ resolvedUri );
405
+ }
406
+
407
+ $ oContext ->getCache ()->set ($ cachePointer , $ cacheType , $ referencedDocument );
408
+
376
409
}
410
+
411
+
377
412
return $ referencedDocument ;
378
413
}
379
414
0 commit comments