Skip to content

Commit

Permalink
Add resolving references of components (#1544)
Browse files Browse the repository at this point in the history
  • Loading branch information
dkulyk committed Feb 18, 2024
1 parent e1fb191 commit a6d8a93
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 1 deletion.
3 changes: 3 additions & 0 deletions docs/reference/processors.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 14 additions & 1 deletion src/Analysis.php
Original file line number Diff line number Diff line change
Expand Up @@ -324,15 +324,28 @@ public function getAnnotationsOfType($classes, bool $strict = false): array
* @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, '\\');

foreach ([$this->classes, $this->interfaces, $this->traits, $this->enums] as $definitions) {
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;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ public function getProcessors(): array
new Processors\ExpandTraits(),
new Processors\ExpandEnums(),
new Processors\AugmentSchemas(),
new Processors\AugmentRequestBody(),
new Processors\AugmentProperties(),
new Processors\BuildPaths(),
new Processors\AugmentParameters(),
Expand Down
2 changes: 2 additions & 0 deletions src/Processors/AugmentRefs.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ protected function resolveFQCNRefs(Analysis $analysis): void
// 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);
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions src/Processors/AugmentRequestBody.php
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
}
}
29 changes: 29 additions & 0 deletions tests/Fixtures/Request.php
Original file line number Diff line number Diff line change
@@ -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()
{

}
}
41 changes: 41 additions & 0 deletions tests/Processors/AugmentRefsTest.php
Original file line number Diff line number Diff line change
@@ -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');
}
}
34 changes: 34 additions & 0 deletions tests/Processors/AugmentRequestBodyTest.php
Original file line number Diff line number Diff line change
@@ -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');
}
}

0 comments on commit a6d8a93

Please sign in to comment.