From 0496b54d8267e99965d0513bd3961743325b55b5 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 30 Jan 2024 12:29:54 +0200 Subject: [PATCH 01/10] [feat] Added resolving RequestBody->request based on class name --- src/Generator.php | 1 + src/Processors/AugmentRequestBody.php | 48 +++++++++++++++++++++ tests/Fixtures/Request.php | 18 ++++++++ tests/Processors/AugmentRequestBodyTest.php | 34 +++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 src/Processors/AugmentRequestBody.php create mode 100644 tests/Fixtures/Request.php create mode 100644 tests/Processors/AugmentRequestBodyTest.php diff --git a/src/Generator.php b/src/Generator.php index 8d5e3a2f..61cf7d41 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -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(), diff --git a/src/Processors/AugmentRequestBody.php b/src/Processors/AugmentRequestBody.php new file mode 100644 index 00000000..35566ec5 --- /dev/null +++ b/src/Processors/AugmentRequestBody.php @@ -0,0 +1,48 @@ +getAnnotationsOfType(OA\RequestBody::class); + + $this->augmentRequestBody($requests); + } + + /** + * @param array $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; + } + } + } + } +} diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php new file mode 100644 index 00000000..9d53d90c --- /dev/null +++ b/tests/Fixtures/Request.php @@ -0,0 +1,18 @@ +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'); + } +} From 6c46af89ed4db0b6b2bba8950cca9e163c009cc8 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 30 Jan 2024 12:32:33 +0200 Subject: [PATCH 02/10] CS --- tests/Fixtures/Request.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index 9d53d90c..171f5b87 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -5,12 +5,13 @@ */ // NOTE: this file uses "\r\n" linebreaks on purpose + namespace OpenApi\Tests\Fixtures; use OpenApi\Annotations as OA; /** - * @OA\RequestBody() + * @OA\RequestBody */ class Request { From 95d95f45ead6f6e253cd6c5f804e6822a4feba38 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 30 Jan 2024 12:33:15 +0200 Subject: [PATCH 03/10] Updated docs --- docs/reference/processors.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/reference/processors.md b/docs/reference/processors.md index 3ea46f9a..ae32253c 100644 --- a/docs/reference/processors.md +++ b/docs/reference/processors.md @@ -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. From d9bfbe6a9994e88d84e993b0189a6fa1b969a3ff Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 30 Jan 2024 16:12:25 +0200 Subject: [PATCH 04/10] Added resolving refs from components --- src/Analysis.php | 5 ++-- src/Processors/AugmentRefs.php | 3 +- tests/Fixtures/Request.php | 11 ++++++++ tests/Processors/AugmentRefsTest.php | 41 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 tests/Processors/AugmentRefsTest.php diff --git a/src/Analysis.php b/src/Analysis.php index 52c6e3ab..7251d12e 100644 --- a/src/Analysis.php +++ b/src/Analysis.php @@ -323,16 +323,17 @@ public function getAnnotationsOfType($classes, bool $strict = false): array /** * @param string $fqdn the source class/interface/trait */ - public function getSchemaForSource(string $fqdn): ?OA\Schema + public function getSchemaForSource(string $fqdn, string $class = OA\Schema::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)) { 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; } } diff --git a/src/Processors/AugmentRefs.php b/src/Processors/AugmentRefs.php index 0e532a8f..5071917b 100644 --- a/src/Processors/AugmentRefs.php +++ b/src/Processors/AugmentRefs.php @@ -60,12 +60,13 @@ protected function resolveFQCNRefs(Analysis $analysis): void { /** @var OA\AbstractAnnotation[] $annotations */ $annotations = $analysis->getAnnotationsOfType([OA\Examples::class, OA\Header::class, OA\Link::class, OA\Parameter::class, OA\PathItem::class, OA\RequestBody::class, OA\Response::class, OA\Schema::class, OA\SecurityScheme::class]); - foreach ($annotations as $annotation) { if (property_exists($annotation, 'ref') && !Generator::isDefault($annotation->ref) && is_string($annotation->ref) && !$this->isRef($annotation->ref)) { // check if we have a schema for this if ($refSchema = $analysis->getSchemaForSource($annotation->ref)) { $annotation->ref = OA\Components::ref($refSchema); + } elseif ($refSchema = $analysis->getSchemaForSource($annotation->ref, get_class($annotation))) { + $annotation->ref = OA\Components::ref($refSchema); } } } diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index 171f5b87..026bde4f 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -9,11 +9,22 @@ namespace OpenApi\Tests\Fixtures; use OpenApi\Annotations as OA; +use OpenApi\Tests\Fixtures; /** * @OA\RequestBody */ class Request { + /** + * @OA\Post( + * path="/", + * @OA\RequestBody(ref=Fixtures\Request::class), + * @OA\Response(response="200", description="An example resource") + * ) + */ + public function post() + { + } } diff --git a/tests/Processors/AugmentRefsTest.php b/tests/Processors/AugmentRefsTest.php new file mode 100644 index 00000000..bd5ace90 --- /dev/null +++ b/tests/Processors/AugmentRefsTest.php @@ -0,0 +1,41 @@ +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'); + } +} From ba7e201da7c52268276a512f4d1f55db704f4b6f Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 30 Jan 2024 16:15:32 +0200 Subject: [PATCH 05/10] CS --- src/Processors/AugmentRefs.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Processors/AugmentRefs.php b/src/Processors/AugmentRefs.php index 5071917b..1c603676 100644 --- a/src/Processors/AugmentRefs.php +++ b/src/Processors/AugmentRefs.php @@ -60,6 +60,7 @@ protected function resolveFQCNRefs(Analysis $analysis): void { /** @var OA\AbstractAnnotation[] $annotations */ $annotations = $analysis->getAnnotationsOfType([OA\Examples::class, OA\Header::class, OA\Link::class, OA\Parameter::class, OA\PathItem::class, OA\RequestBody::class, OA\Response::class, OA\Schema::class, OA\SecurityScheme::class]); + foreach ($annotations as $annotation) { if (property_exists($annotation, 'ref') && !Generator::isDefault($annotation->ref) && is_string($annotation->ref) && !$this->isRef($annotation->ref)) { // check if we have a schema for this From 4fd7a1c70b9bdaae4fcf805e75cd2bf53e53c916 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Tue, 30 Jan 2024 16:17:59 +0200 Subject: [PATCH 06/10] CS --- src/Analysis.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Analysis.php b/src/Analysis.php index 7251d12e..6ede8d90 100644 --- a/src/Analysis.php +++ b/src/Analysis.php @@ -328,7 +328,6 @@ public function getSchemaForSource(string $fqdn, string $class = OA\Schema::clas $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)) { From 85c250b5aed6a6229896a95ef8d76dccb26083e2 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Wed, 31 Jan 2024 14:10:07 +0200 Subject: [PATCH 07/10] Used full qualified class name --- tests/Fixtures/Request.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Fixtures/Request.php b/tests/Fixtures/Request.php index 026bde4f..a24a72e8 100644 --- a/tests/Fixtures/Request.php +++ b/tests/Fixtures/Request.php @@ -9,7 +9,6 @@ namespace OpenApi\Tests\Fixtures; use OpenApi\Annotations as OA; -use OpenApi\Tests\Fixtures; /** * @OA\RequestBody @@ -19,7 +18,7 @@ class Request /** * @OA\Post( * path="/", - * @OA\RequestBody(ref=Fixtures\Request::class), + * @OA\RequestBody(ref=OpenApi\Tests\Fixtures\Request::class), * @OA\Response(response="200", description="An example resource") * ) */ From 59694ac55733d8c0f9bdb0586c3551c93852ff1c Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Thu, 1 Feb 2024 00:09:43 +0200 Subject: [PATCH 08/10] Added getAnnotationForSource method(analyse) --- src/Analysis.php | 15 ++++++++++++++- src/Processors/AugmentRefs.php | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Analysis.php b/src/Analysis.php index 6ede8d90..a200e402 100644 --- a/src/Analysis.php +++ b/src/Analysis.php @@ -323,7 +323,19 @@ public function getAnnotationsOfType($classes, bool $strict = false): array /** * @param string $fqdn the source class/interface/trait */ - public function getSchemaForSource(string $fqdn, string $class = OA\Schema::class): ?OA\AbstractAnnotation + 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 $class + * @return T|null + */ + public function getAnnotationForSource(string $fqdn, string $class): ?OA\AbstractAnnotation { $fqdn = '\\' . ltrim($fqdn, '\\'); @@ -331,6 +343,7 @@ public function getSchemaForSource(string $fqdn, string $class = OA\Schema::clas 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 (is_a($annotation, $class) && $annotation->isRoot($class) && !$annotation->_context->is('generated')) { return $annotation; diff --git a/src/Processors/AugmentRefs.php b/src/Processors/AugmentRefs.php index 1c603676..b827efa1 100644 --- a/src/Processors/AugmentRefs.php +++ b/src/Processors/AugmentRefs.php @@ -66,7 +66,7 @@ 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 ($refSchema = $analysis->getSchemaForSource($annotation->ref, get_class($annotation))) { + } elseif ($refSchema = $analysis->getAnnotationForSource($annotation->ref, get_class($annotation))) { $annotation->ref = OA\Components::ref($refSchema); } } From b7237a578a61b93381dedafbc8bd1c786ecd74cf Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Fri, 16 Feb 2024 15:33:30 +0200 Subject: [PATCH 09/10] Apply suggestions from code review Co-authored-by: Martin Rademacher --- src/Processors/AugmentRefs.php | 2 +- src/Processors/AugmentRequestBody.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Processors/AugmentRefs.php b/src/Processors/AugmentRefs.php index b827efa1..64703855 100644 --- a/src/Processors/AugmentRefs.php +++ b/src/Processors/AugmentRefs.php @@ -66,7 +66,7 @@ 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 ($refSchema = $analysis->getAnnotationForSource($annotation->ref, get_class($annotation))) { + } elseif ($refAnnotation = $analysis->getAnnotationForSource($annotation->ref, get_class($annotation))) { $annotation->ref = OA\Components::ref($refSchema); } } diff --git a/src/Processors/AugmentRequestBody.php b/src/Processors/AugmentRequestBody.php index 35566ec5..77733a75 100644 --- a/src/Processors/AugmentRequestBody.php +++ b/src/Processors/AugmentRequestBody.php @@ -17,7 +17,7 @@ class AugmentRequestBody implements ProcessorInterface { public function __invoke(Analysis $analysis) { - /** @var OA\RequestBody[] $requests */ + /** @var array $requests */ $requests = $analysis->getAnnotationsOfType(OA\RequestBody::class); $this->augmentRequestBody($requests); From 53af814e158df8940964178d532716aa99d075c6 Mon Sep 17 00:00:00 2001 From: Dmytro Kulyk Date: Fri, 16 Feb 2024 23:14:46 +0200 Subject: [PATCH 10/10] Fixed name of variable --- src/Processors/AugmentRefs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Processors/AugmentRefs.php b/src/Processors/AugmentRefs.php index 64703855..b120d295 100644 --- a/src/Processors/AugmentRefs.php +++ b/src/Processors/AugmentRefs.php @@ -67,7 +67,7 @@ protected function resolveFQCNRefs(Analysis $analysis): void 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($refSchema); + $annotation->ref = OA\Components::ref($refAnnotation); } } }