Add resolving references of components (#1544)

This commit is contained in:
Dmytro Kulyk 2024-02-19 00:00:16 +02:00 committed by GitHub
parent e1fb191ae0
commit a6d8a93e5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 172 additions and 1 deletions

View File

@ -43,6 +43,9 @@ Determines `schema`, `enum` and `type`.
Use the Schema context to extract useful information and inject that into the annotation.
Merges properties.
## [AugmentRequestBody](https://github.com/zircote/swagger-php/tree/master/src/Processors/AugmentRequestBody.php)
Use the RequestBody context to extract useful information and inject that into the annotation.
## [AugmentProperties](https://github.com/zircote/swagger-php/tree/master/src/Processors/AugmentProperties.php)
Use the property context to extract useful information and inject that into the annotation.

View File

@ -324,6 +324,18 @@ class Analysis
* @param string $fqdn the source class/interface/trait
*/
public function getSchemaForSource(string $fqdn): ?OA\Schema
{
return $this->getAnnotationForSource($fqdn, OA\Schema::class);
}
/**
* @template T of OA\AbstractAnnotation
*
* @param string $fqdn the source class/interface/trait
* @param class-string<T> $class
* @return T|null
*/
public function getAnnotationForSource(string $fqdn, string $class): ?OA\AbstractAnnotation
{
$fqdn = '\\' . ltrim($fqdn, '\\');
@ -331,8 +343,9 @@ class Analysis
if (array_key_exists($fqdn, $definitions)) {
$definition = $definitions[$fqdn];
if (is_iterable($definition['context']->annotations)) {
/** @var OA\AbstractAnnotation $annotation */
foreach (array_reverse($definition['context']->annotations) as $annotation) {
if ($annotation instanceof OA\Schema && $annotation->isRoot(OA\Schema::class) && !$annotation->_context->is('generated')) {
if (is_a($annotation, $class) && $annotation->isRoot($class) && !$annotation->_context->is('generated')) {
return $annotation;
}
}

View File

@ -261,6 +261,7 @@ class Generator
new Processors\ExpandTraits(),
new Processors\ExpandEnums(),
new Processors\AugmentSchemas(),
new Processors\AugmentRequestBody(),
new Processors\AugmentProperties(),
new Processors\BuildPaths(),
new Processors\AugmentParameters(),

View File

@ -66,6 +66,8 @@ class AugmentRefs implements ProcessorInterface
// check if we have a schema for this
if ($refSchema = $analysis->getSchemaForSource($annotation->ref)) {
$annotation->ref = OA\Components::ref($refSchema);
} elseif ($refAnnotation = $analysis->getAnnotationForSource($annotation->ref, get_class($annotation))) {
$annotation->ref = OA\Components::ref($refAnnotation);
}
}
}

View File

@ -0,0 +1,48 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Processors;
use OpenApi\Analysis;
use OpenApi\Annotations as OA;
use OpenApi\Generator;
/**
* Use the RequestBody context to extract useful information and inject that into the annotation.
*/
class AugmentRequestBody implements ProcessorInterface
{
public function __invoke(Analysis $analysis)
{
/** @var array<OA\RequestBody> $requests */
$requests = $analysis->getAnnotationsOfType(OA\RequestBody::class);
$this->augmentRequestBody($requests);
}
/**
* @param array<OA\RequestBody> $requests
*/
protected function augmentRequestBody(array $requests): void
{
foreach ($requests as $request) {
if (!$request->isRoot(OA\RequestBody::class)) {
continue;
}
if (Generator::isDefault($request->request)) {
if ($request->_context->is('class')) {
$request->request = $request->_context->class;
} elseif ($request->_context->is('interface')) {
$request->request = $request->_context->interface;
} elseif ($request->_context->is('trait')) {
$request->request = $request->_context->trait;
} elseif ($request->_context->is('enum')) {
$request->request = $request->_context->enum;
}
}
}
}
}

View File

@ -0,0 +1,29 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
// NOTE: this file uses "\r\n" linebreaks on purpose
namespace OpenApi\Tests\Fixtures;
use OpenApi\Annotations as OA;
/**
* @OA\RequestBody
*/
class Request
{
/**
* @OA\Post(
* path="/",
* @OA\RequestBody(ref=OpenApi\Tests\Fixtures\Request::class),
* @OA\Response(response="200", description="An example resource")
* )
*/
public function post()
{
}
}

View File

@ -0,0 +1,41 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Tests\Processors;
use OpenApi\Processors\AugmentRefs;
use OpenApi\Processors\AugmentRequestBody;
use OpenApi\Processors\BuildPaths;
use OpenApi\Processors\Concerns\DocblockTrait;
use OpenApi\Processors\MergeIntoComponents;
use OpenApi\Processors\MergeIntoOpenApi;
use OpenApi\Tests\OpenApiTestCase;
class AugmentRefsTest extends OpenApiTestCase
{
use DocblockTrait;
public function testAugmentRefsForRequestBody(): void
{
$analysis = $this->analysisFromFixtures(['Request.php']);
$analysis->process([
// create openapi->components
new MergeIntoOpenApi(),
// Merge standalone Scheme's into openapi->components
new MergeIntoComponents(),
new BuildPaths(),
new AugmentRequestBody(),
]);
$this->assertSame($analysis->openapi->paths[0]->post->requestBody->ref, 'OpenApi\Tests\Fixtures\Request');
$analysis->process([
new AugmentRefs(),
]);
$this->assertSame($analysis->openapi->paths[0]->post->requestBody->ref, '#/components/requestBodies/Request');
}
}

View File

@ -0,0 +1,34 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Tests\Processors;
use OpenApi\Generator;
use OpenApi\Processors\AugmentRequestBody;
use OpenApi\Processors\MergeIntoComponents;
use OpenApi\Processors\MergeIntoOpenApi;
use OpenApi\Tests\OpenApiTestCase;
class AugmentRequestBodyTest extends OpenApiTestCase
{
public function testAugmentSchemas(): void
{
$analysis = $this->analysisFromFixtures(['Request.php']);
$analysis->process([
// create openapi->components
new MergeIntoOpenApi(),
// Merge standalone Scheme's into openapi->components
new MergeIntoComponents(),
]);
$this->assertCount(1, $analysis->openapi->components->requestBodies);
$request = $analysis->openapi->components->requestBodies[0];
$this->assertSame(Generator::UNDEFINED, $request->request, 'Sanity check. No request was defined');
$analysis->process([new AugmentRequestBody()]);
$this->assertSame('Request', $request->request, '@OA\RequestBody()->request based on classname');
}
}