From ea8c7c71376330a603c6af4d3008da91ae54581a Mon Sep 17 00:00:00 2001 From: "martin.reinfandt" Date: Fri, 27 Jun 2025 12:27:13 +0200 Subject: [PATCH 1/3] resolve a reference schema --- src/Generator/ClassGenerator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index 7347a44..a7386e3 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -58,6 +58,10 @@ private function addSchemas(Configuration $configuration, OpenApi $openApi): arr $models = []; foreach ($schemas as $name => $schema) { + if ($schema instanceof Reference) { + $schema = $schema->resolve(); + } + if ($schema instanceof Schema) { $classModel = $this->classTransformer->transform( $configuration, From 3b7361734849dfa87efebb489ef72d3f65ad9957 Mon Sep 17 00:00:00 2001 From: "martin.reinfandt" Date: Fri, 27 Jun 2025 13:57:33 +0200 Subject: [PATCH 2/3] resolve a reference schema --- src/Generator/ClassTransformer.php | 6 ++++++ src/Generator/PropertyResolver.php | 3 ++- src/Generator/ReferenceResolver.php | 16 +++++++++++++++- src/Generator/TypeResolver.php | 9 +++++++-- src/Model/InlineSchemaReference.php | 15 +++++++++++++++ test/Generator/ClassGeneratorTest.php | 21 ++++++++++++++++++--- test/Generator/ReferenceResolverTest.php | 14 +++++++++++--- 7 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/Model/InlineSchemaReference.php diff --git a/src/Generator/ClassTransformer.php b/src/Generator/ClassTransformer.php index a27a37d..a5da35e 100644 --- a/src/Generator/ClassTransformer.php +++ b/src/Generator/ClassTransformer.php @@ -23,6 +23,7 @@ use Reinfi\OpenApiModels\Model\ArrayType; use Reinfi\OpenApiModels\Model\ClassModel; use Reinfi\OpenApiModels\Model\Imports; +use Reinfi\OpenApiModels\Model\InlineSchemaReference; use Reinfi\OpenApiModels\Model\OneOfReference; use Reinfi\OpenApiModels\Model\OneOfType; use Reinfi\OpenApiModels\Model\ScalarType; @@ -504,6 +505,11 @@ private function resolveArrayType( $arrayType = Types::OneOf; } + if ($arrayType instanceof InlineSchemaReference) { + $itemsSchema = $arrayType->schema; + $arrayType = Types::Object; + } + if ($arrayType === Types::Object) { $inlineObject = $this->transformInlineObject( $configuration, diff --git a/src/Generator/PropertyResolver.php b/src/Generator/PropertyResolver.php index ddceb30..e9b0724 100644 --- a/src/Generator/PropertyResolver.php +++ b/src/Generator/PropertyResolver.php @@ -8,6 +8,7 @@ use Nette\PhpGenerator\PromotedParameter; use openapiphp\openapi\spec\Reference; use openapiphp\openapi\spec\Schema; +use Reinfi\OpenApiModels\Model\InlineSchemaReference; use Reinfi\OpenApiModels\Model\OneOfReference; use Reinfi\OpenApiModels\Model\ScalarType; @@ -18,7 +19,7 @@ public function resolve( string $name, Schema|Reference $schema, bool $required, - ScalarType|ClassReference|OneOfReference|Types|string $type, + ScalarType|ClassReference|InlineSchemaReference|OneOfReference|Types|string $type, ): PromotedParameter { $property = $constructor->addPromotedParameter($name); diff --git a/src/Generator/ReferenceResolver.php b/src/Generator/ReferenceResolver.php index e405225..10eba9c 100644 --- a/src/Generator/ReferenceResolver.php +++ b/src/Generator/ReferenceResolver.php @@ -10,6 +10,7 @@ use openapiphp\openapi\spec\Schema; use Reinfi\OpenApiModels\Exception\InvalidReferenceException; use Reinfi\OpenApiModels\Model\SchemaWithName; +use Throwable; readonly class ReferenceResolver { @@ -20,8 +21,21 @@ public function resolve(OpenApi $openApi, Reference $reference): SchemaWithName $reference->getReference(), $matches ) !== 1) { + try { + $resolvedSchema = $reference->resolve(); + + if ($resolvedSchema instanceof Schema) { + return new SchemaWithName(OpenApiType::Schemas, '', $resolvedSchema); + } + } catch (Throwable $throwable) { + throw new InvalidArgumentException( + sprintf('Invalid reference "%s" given, does not match pattern', $reference->getReference()), + previous: $throwable, + ); + } + throw new InvalidArgumentException( - sprintf('Invalid reference "%s" given, does not match pattern', $reference->getReference()) + sprintf('Invalid reference "%s" given, does not match pattern', $reference->getReference()), ); } diff --git a/src/Generator/TypeResolver.php b/src/Generator/TypeResolver.php index d858cdf..9af0f6d 100644 --- a/src/Generator/TypeResolver.php +++ b/src/Generator/TypeResolver.php @@ -9,6 +9,7 @@ use openapiphp\openapi\spec\OpenApi; use openapiphp\openapi\spec\Reference; use openapiphp\openapi\spec\Schema; +use Reinfi\OpenApiModels\Model\InlineSchemaReference; use Reinfi\OpenApiModels\Model\OneOfReference; use Reinfi\OpenApiModels\Model\ScalarType; @@ -22,13 +23,13 @@ public function __construct( /** * @phpstan-assert Schema $schema when return type is string|Types|null - * @return ($schema is Reference ? ClassReference|OneOfReference|ScalarType : ($throwException is true ? string|Types : string|Types|null)) + * @return ($schema is Reference ? ClassReference|InlineSchemaReference|OneOfReference|ScalarType : ($throwException is true ? string|Types : string|Types|null)) */ public function resolve( OpenApi $openApi, Schema|Reference $schema, bool $throwException = true - ): ScalarType|ClassReference|OneOfReference|string|Types|null { + ): ScalarType|ClassReference|InlineSchemaReference|OneOfReference|string|Types|null { if ($schema instanceof Reference) { $schemaWithName = $this->referenceResolver->resolve($openApi, $schema); @@ -46,6 +47,10 @@ public function resolve( return new ScalarType($referenceType, $schemaWithName->schema); } + if ($schemaWithName->name === '') { + return new InlineSchemaReference($schemaWithName->schema); + } + return new ClassReference( $schemaWithName->openApiType, $this->namespaceResolver->resolveNamespace($schemaWithName->openApiType, $schemaWithName->schema) diff --git a/src/Model/InlineSchemaReference.php b/src/Model/InlineSchemaReference.php new file mode 100644 index 0000000..3cd7b05 --- /dev/null +++ b/src/Model/InlineSchemaReference.php @@ -0,0 +1,15 @@ + [ 'type' => 'object', ], - 'Test3' => [ - '$ref' => '#/components/schemas/Test4', - ], ], ], ]); @@ -77,6 +74,9 @@ public function testItGeneratesRequestBodies(): void $configuration = new Configuration([], '', ''); $openApi = new OpenApi([ + 'openapi' => '3.0.0', + 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'paths' => [], 'components' => [ 'requestBodies' => [ 'Test1' => [ @@ -123,6 +123,9 @@ public function testItGeneratesResponses(): void $configuration = new Configuration([], '', ''); $openApi = new OpenApi([ + 'openapi' => '3.0.0', + 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'paths' => [], 'components' => [ 'responses' => [ 'Test1' => [ @@ -169,6 +172,9 @@ public function testItGeneratesReferenceClasses(): void $configuration = new Configuration([], '', ''); $openApi = new OpenApi([ + 'openapi' => '3.0.0', + 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'paths' => [], 'components' => [ 'responses' => [ 'Test1' => [ @@ -215,6 +221,9 @@ public function testItGeneratesOnlyJsonSchema(): void $configuration = new Configuration([], '', ''); $openApi = new OpenApi([ + 'openapi' => '3.0.0', + 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'paths' => [], 'components' => [ 'responses' => [ 'Test1' => [ @@ -270,6 +279,9 @@ public function testItThrowsExceptionIfJsonContentTypeNotFound(): void $configuration = new Configuration([], '', ''); $openApi = new OpenApi([ + 'openapi' => '3.0.0', + 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'paths' => [], 'components' => [ 'responses' => [ 'Test1' => [ @@ -304,6 +316,9 @@ public function testItSetsCommentIfTopLevelHasDescription(): void $configuration = new Configuration([], '', ''); $openApi = new OpenApi([ + 'openapi' => '3.0.0', + 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'paths' => [], 'components' => [ 'responses' => [ 'Test1' => [ diff --git a/test/Generator/ReferenceResolverTest.php b/test/Generator/ReferenceResolverTest.php index a8b4325..28bcbe2 100644 --- a/test/Generator/ReferenceResolverTest.php +++ b/test/Generator/ReferenceResolverTest.php @@ -57,11 +57,19 @@ public function testItThrowsExceptionIfNotValidReference(): void self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('Invalid reference "no-valid-reference" given, does not match pattern'); - $openApi = new OpenApi([]); - $reference = new Reference([ - '$ref' => 'no-valid-reference', + $openApi = new OpenApi([ + 'components' => [ + 'schemas' => [ + 'InvalidReference' => [ + '$ref' => 'no-valid-reference', + ], + ], + ], ]); + $reference = $openApi->components?->schemas['InvalidReference']; + self::assertInstanceOf(Reference::class, $reference); + $resolver = new ReferenceResolver(); $resolver->resolve($openApi, $reference); } From 9d4dd2539f8d152c5a3e126ca87d84a91e602436 Mon Sep 17 00:00:00 2001 From: "martin.reinfandt" Date: Fri, 27 Jun 2025 13:59:24 +0200 Subject: [PATCH 3/3] fix codestyle --- test/Generator/ClassGeneratorTest.php | 30 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/test/Generator/ClassGeneratorTest.php b/test/Generator/ClassGeneratorTest.php index 1314abc..d56ee92 100644 --- a/test/Generator/ClassGeneratorTest.php +++ b/test/Generator/ClassGeneratorTest.php @@ -75,7 +75,10 @@ public function testItGeneratesRequestBodies(): void $openApi = new OpenApi([ 'openapi' => '3.0.0', - 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'info' => [ + 'title' => 'Test API', + 'version' => '1.0.0', + ], 'paths' => [], 'components' => [ 'requestBodies' => [ @@ -124,7 +127,10 @@ public function testItGeneratesResponses(): void $openApi = new OpenApi([ 'openapi' => '3.0.0', - 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'info' => [ + 'title' => 'Test API', + 'version' => '1.0.0', + ], 'paths' => [], 'components' => [ 'responses' => [ @@ -173,7 +179,10 @@ public function testItGeneratesReferenceClasses(): void $openApi = new OpenApi([ 'openapi' => '3.0.0', - 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'info' => [ + 'title' => 'Test API', + 'version' => '1.0.0', + ], 'paths' => [], 'components' => [ 'responses' => [ @@ -222,7 +231,10 @@ public function testItGeneratesOnlyJsonSchema(): void $openApi = new OpenApi([ 'openapi' => '3.0.0', - 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'info' => [ + 'title' => 'Test API', + 'version' => '1.0.0', + ], 'paths' => [], 'components' => [ 'responses' => [ @@ -280,7 +292,10 @@ public function testItThrowsExceptionIfJsonContentTypeNotFound(): void $openApi = new OpenApi([ 'openapi' => '3.0.0', - 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'info' => [ + 'title' => 'Test API', + 'version' => '1.0.0', + ], 'paths' => [], 'components' => [ 'responses' => [ @@ -317,7 +332,10 @@ public function testItSetsCommentIfTopLevelHasDescription(): void $openApi = new OpenApi([ 'openapi' => '3.0.0', - 'info' => ['title' => 'Test API', 'version' => '1.0.0'], + 'info' => [ + 'title' => 'Test API', + 'version' => '1.0.0', + ], 'paths' => [], 'components' => [ 'responses' => [