From 40257ec864e2438e1a77a7a5aa013dda6d78f265 Mon Sep 17 00:00:00 2001 From: Ben Yarwood Date: Wed, 21 Oct 2026 22:57:54 +0100 Subject: [PATCH 1/4] [php] Keep the model namespace for allOf-wrapped array items and parameters toAllOfName() returned the fully qualified declaration of a single allOf member, which getSchemaType() then ran through toModelName(), stripping the namespace separators: an array item or parameter declared as `allOf: [$ref]` came out as \AcmeClientModelError instead of \Acme\Client\Model\Error. Resolve a single-member allOf to its member, as fromProperty() already does for properties, and let the $ref branch qualify it. Fixes #25354 Co-Authored-By: Claude Fable 5.1 --- .../codegen/languages/AbstractPhpCodegen.java | 10 ++++++++++ .../codegen/php/PhpModelTest.java | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java index 04c784f975c1..eebf74b42d3e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java @@ -458,6 +458,10 @@ public String getTypeDeclaration(Schema p) { String type = super.getTypeDeclaration(p); return (!languageSpecificPrimitives.contains(type)) ? "\\" + modelPackage + "\\" + toModelName(type) : type; + } else if (ModelUtils.isAllOf(p) && p.getAllOf().size() == 1 && p.getAllOf().get(0) instanceof Schema) { + // allOf with a single member (e.g. a $ref wrapped to add a description) is the + // member's type; resolving it here keeps the model namespace intact. + return getTypeDeclaration((Schema) p.getAllOf().get(0)); } return super.getTypeDeclaration(p); } @@ -1090,6 +1094,12 @@ public String toOneOfName(List names, Schema composedSchema) { public String toAllOfName(List names, Schema composedSchema) { List schemas = ModelUtils.getInterfaces(composedSchema); + if (schemas.size() == 1) { + // a single member is a plain schema name; getSchemaType() turns it into a model + // name and getTypeDeclaration() qualifies it, like any other $ref + return super.toAllOfName(names, composedSchema); + } + List types = new ArrayList<>(); for (Schema s : schemas) { types.add(getTypeDeclaration(s)); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpModelTest.java index c133c9c325b7..4f158fb8f2f7 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpModelTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpModelTest.java @@ -202,6 +202,26 @@ public void complexListProperty() { Assert.assertTrue(property1.isContainer); } + @Test(description = "convert a model with a list property whose items are a single-member allOf") + public void complexListPropertyWithAllOfItems() { + final Schema model = new Schema() + .description("a sample model") + .addProperties("children", new ArraySchema() + .items(new ComposedSchema() + .addAllOfItem(new Schema().$ref("#/components/schemas/Children")))); + final DefaultCodegen codegen = new PhpClientCodegen(); + OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model); + codegen.setOpenAPI(openAPI); + final CodegenModel cm = codegen.fromModel("sample", model); + + final CodegenProperty property1 = cm.vars.get(0); + Assert.assertEquals(property1.baseName, "children"); + Assert.assertEquals(property1.dataType, "\\OpenAPI\\Client\\Model\\Children[]"); + Assert.assertEquals(property1.items.dataType, "\\OpenAPI\\Client\\Model\\Children"); + Assert.assertEquals(property1.items.baseType, "Children"); + Assert.assertEquals(property1.complexType, "Children"); + } + @Test(description = "convert a model with complex map property") public void complexMapSchema() { final Schema model = new Schema() From 998364e3c9bac90e58a136f0ff0451d901524caa Mon Sep 17 00:00:00 2001 From: Ben Yarwood Date: Wed, 21 Oct 2026 23:04:00 +0100 Subject: [PATCH 2/4] [php] Cover allOf-wrapped items with a fixture test and a sample model Generate the issue's spec through php and php-nextgen and assert the model type map and the API parameter carry the qualified model class. The php-nextgen petstore sample gains AllOfRefArray so the regenerated sample shows the fix and its phpstan job exercises it. Co-Authored-By: Claude Fable 5.1 --- .../codegen/php/PhpClientCodegenTest.java | 47 ++- .../php/PhpNextgenClientCodegenTest.java | 44 ++ ...ith-fake-endpoints-models-for-testing.yaml | 10 + .../src/test/resources/bugs/issue_25354.yaml | 47 +++ .../.openapi-generator/FILES | 3 + .../php-nextgen/OpenAPIClient-php/README.md | 1 + .../docs/Model/AllOfRefArray.md | 9 + .../src/Model/AllOfRefArray.php | 383 ++++++++++++++++++ .../tests/Model/AllOfRefArrayTest.php | 88 ++++ 9 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 modules/openapi-generator/src/test/resources/bugs/issue_25354.yaml create mode 100644 samples/client/petstore/php-nextgen/OpenAPIClient-php/docs/Model/AllOfRefArray.md create mode 100644 samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/AllOfRefArray.php create mode 100644 samples/client/petstore/php-nextgen/OpenAPIClient-php/tests/Model/AllOfRefArrayTest.php diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpClientCodegenTest.java index 803a460aea0a..92757a14d022 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpClientCodegenTest.java @@ -209,4 +209,49 @@ public void testDateTimeLengthValidationIsNotGenerated() throws Exception { Assert.assertTrue(modelPhp.contains("mb_strlen($this->container['title']) > 10"), modelPhp); Assert.assertTrue(modelPhp.contains("mb_strlen($title) > 10"), modelPhp); } -} \ No newline at end of file + + @Test(description = "Issue #25354: allOf-wrapped array items and parameters keep the model namespace") + public void testAllOfWrappedArrayItemsAndParametersKeepModelNamespace() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_25354.yaml", null, new ParseOptions()).getOpenAPI(); + + codegen.setOutputDir(output.getAbsolutePath()); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + Map files = generator.opts(input).generate().stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + List modelContent = Files + .readAllLines(files.get("ThingList.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + + Assert.assertListContains(modelContent, + a -> a.equals("'errors_wrapped' => '\\OpenAPI\\Client\\Model\\Error[]',"), + "an allOf-wrapped array item must be typed with its qualified model class"); + Assert.assertListContains(modelContent, + a -> a.equals("'errors_plain' => '\\OpenAPI\\Client\\Model\\Error[]',"), + "a plain $ref array item keeps its qualified model class"); + Assert.assertListNotContains(modelContent, a -> a.contains("OpenAPIClientModel"), ""); + + List apiContent = Files + .readAllLines(files.get("DefaultApi.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + + // the php generator leaves parameters untyped in the signature; the docblock carries the type + Assert.assertListContains(apiContent, + a -> a.contains("\\OpenAPI\\Client\\Model\\SortDir|null $sort"), + "an allOf-wrapped parameter must be documented with its qualified model class"); + Assert.assertListNotContains(apiContent, a -> a.contains("OpenAPIClientModel"), ""); + } +} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpNextgenClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpNextgenClientCodegenTest.java index ba5e167bd42d..89c9222223f2 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpNextgenClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/php/PhpNextgenClientCodegenTest.java @@ -754,4 +754,48 @@ public void testDateTimeLengthValidationIsNotGenerated() throws Exception { Assert.assertTrue(modelPhp.contains("mb_strlen($this->container['title']) > 10"), modelPhp); Assert.assertTrue(modelPhp.contains("mb_strlen($title) > 10"), modelPhp); } + + @Test(description = "Issue #25354: allOf-wrapped array items and parameters keep the model namespace") + public void testAllOfWrappedArrayItemsAndParametersKeepModelNamespace() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_25354.yaml", null, new ParseOptions()).getOpenAPI(); + + codegen.setOutputDir(output.getAbsolutePath()); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + Map files = generator.opts(input).generate().stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + List modelContent = Files + .readAllLines(files.get("ThingList.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + + Assert.assertListContains(modelContent, + a -> a.equals("'errors_wrapped' => '\\OpenAPI\\Client\\Model\\Error[]',"), + "an allOf-wrapped array item must be typed with its qualified model class"); + Assert.assertListContains(modelContent, + a -> a.equals("'errors_plain' => '\\OpenAPI\\Client\\Model\\Error[]',"), + "a plain $ref array item keeps its qualified model class"); + Assert.assertListNotContains(modelContent, a -> a.contains("OpenAPIClientModel"), ""); + + List apiContent = Files + .readAllLines(files.get("DefaultApi.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + + Assert.assertListContains(apiContent, + a -> a.contains("?\\OpenAPI\\Client\\Model\\SortDir $sort = null"), + "an allOf-wrapped parameter must be typed with its qualified model class"); + Assert.assertListNotContains(apiContent, a -> a.contains("OpenAPIClientModel"), ""); + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/php-nextgen/petstore-with-fake-endpoints-models-for-testing.yaml b/modules/openapi-generator/src/test/resources/3_0/php-nextgen/petstore-with-fake-endpoints-models-for-testing.yaml index 8de20de092c1..59d33c7f8ef4 100644 --- a/modules/openapi-generator/src/test/resources/3_0/php-nextgen/petstore-with-fake-endpoints-models-for-testing.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/php-nextgen/petstore-with-fake-endpoints-models-for-testing.yaml @@ -2460,3 +2460,13 @@ components: - $ref: '#/components/schemas/Mammal' - $ref: '#/components/schemas/Reptile' + AllOfRefArray: + # issue 25354: array items wrapped in a single-member allOf must keep the + # model's namespace (\OpenAPI\Client\Model\Tag[], not \OpenAPIClientModelTag[]) + type: object + properties: + tags: + type: array + items: + allOf: + - $ref: '#/components/schemas/Tag' diff --git a/modules/openapi-generator/src/test/resources/bugs/issue_25354.yaml b/modules/openapi-generator/src/test/resources/bugs/issue_25354.yaml new file mode 100644 index 000000000000..d28219bc30ae --- /dev/null +++ b/modules/openapi-generator/src/test/resources/bugs/issue_25354.yaml @@ -0,0 +1,47 @@ +openapi: 3.0.3 +info: + title: allOf item repro + version: 1.0.0 +paths: + /things: + get: + operationId: listThings + parameters: + - name: sort + in: query + schema: + allOf: + - $ref: '#/components/schemas/sort_dir' + responses: + '200': + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/thing_list' +components: + schemas: + sort_dir: + type: string + enum: [asc, desc] + default: desc + error: + type: object + properties: + message: + type: string + thing_list: + type: object + properties: + errors_wrapped: + type: array + items: + allOf: + - $ref: '#/components/schemas/error' + errors_plain: + type: array + items: + $ref: '#/components/schemas/error' + single_wrapped: + allOf: + - $ref: '#/components/schemas/error' diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES b/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES index 581e0684b053..db8dc02cd6e7 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES @@ -12,6 +12,7 @@ docs/Api/PetApi.md docs/Api/StoreApi.md docs/Api/UserApi.md docs/Model/AdditionalPropertiesClass.md +docs/Model/AllOfRefArray.md docs/Model/AllOfWithSingleRef.md docs/Model/Animal.md docs/Model/ApiResponse.md @@ -92,6 +93,7 @@ src/Configuration.php src/FormDataProcessor.php src/HeaderSelector.php src/Model/AdditionalPropertiesClass.php +src/Model/AllOfRefArray.php src/Model/AllOfWithSingleRef.php src/Model/Animal.php src/Model/AnyOfInterface.php @@ -162,3 +164,4 @@ src/Model/Whale.php src/Model/Zebra.php src/Model/Zoo.php src/ObjectSerializer.php +tests/Model/AllOfRefArrayTest.php diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/README.md b/samples/client/petstore/php-nextgen/OpenAPIClient-php/README.md index 2c8d783a6321..7d050d8e1eba 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/README.md +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/README.md @@ -130,6 +130,7 @@ Class | Method | HTTP request | Description ## Models - [AdditionalPropertiesClass](docs/Model/AdditionalPropertiesClass.md) +- [AllOfRefArray](docs/Model/AllOfRefArray.md) - [AllOfWithSingleRef](docs/Model/AllOfWithSingleRef.md) - [Animal](docs/Model/Animal.md) - [ApiResponse](docs/Model/ApiResponse.md) diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/docs/Model/AllOfRefArray.md b/samples/client/petstore/php-nextgen/OpenAPIClient-php/docs/Model/AllOfRefArray.md new file mode 100644 index 000000000000..1769025e970f --- /dev/null +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/docs/Model/AllOfRefArray.md @@ -0,0 +1,9 @@ +# AllOfRefArray + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**tags** | [**\OpenAPI\Client\Model\Tag[]**](Tag.md) | | [optional] + +[[Back to Model list]](../../README.md#models) [[Back to API list]](../../README.md#endpoints) [[Back to README]](../../README.md) diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/AllOfRefArray.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/AllOfRefArray.php new file mode 100644 index 000000000000..698a2ea31d55 --- /dev/null +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/AllOfRefArray.php @@ -0,0 +1,383 @@ + + */ +class AllOfRefArray implements ModelInterface, ArrayAccess, JsonSerializable +{ + public const DISCRIMINATOR = null; + + /** + * The original name of the model. + * + * @var string + */ + protected static string $openAPIModelName = 'AllOfRefArray'; + + /** + * Array of property to type mappings. Used for (de)serialization + * + * @var array + */ + protected static array $openAPITypes = [ + 'tags' => '\OpenAPI\Client\Model\Tag[]' + ]; + + /** + * Array of property to format mappings. Used for (de)serialization + * + * @var array + */ + protected static array $openAPIFormats = [ + 'tags' => null + ]; + + /** + * Array of nullable properties. Used for (de)serialization + * + * @var array + */ + protected static array $openAPINullables = [ + 'tags' => false + ]; + + /** + * If a nullable field gets set to null, insert it here + * + * @var array + */ + protected array $openAPINullablesSetToNull = []; + + /** + * {@inheritdoc} + */ + public static function openAPITypes(): array + { + return self::$openAPITypes; + } + + /** + * {@inheritdoc} + */ + public static function openAPIFormats(): array + { + return self::$openAPIFormats; + } + + /** + * Array of nullable properties + * + * @return array + */ + protected static function openAPINullables(): array + { + return self::$openAPINullables; + } + + /** + * Array of nullable field names deliberately set to null + * + * @return array + */ + private function getOpenAPINullablesSetToNull(): array + { + return $this->openAPINullablesSetToNull; + } + + /** + * Setter - Array of nullable field names deliberately set to null + * + * @param array $openAPINullablesSetToNull + */ + private function setOpenAPINullablesSetToNull(array $openAPINullablesSetToNull): void + { + $this->openAPINullablesSetToNull = $openAPINullablesSetToNull; + } + + /** + * {@inheritdoc} + */ + public static function isNullable(string $property): bool + { + return self::openAPINullables()[$property] ?? false; + } + + /** + * {@inheritdoc} + */ + public function isNullableSetToNull(string $property): bool + { + return in_array($property, $this->getOpenAPINullablesSetToNull(), true); + } + + /** + * Array of attributes where the key is the local name, + * and the value is the original name + * + * @var array + */ + protected static array $attributeMap = [ + 'tags' => 'tags' + ]; + + /** + * Array of attributes to setter functions (for deserialization of responses) + * + * @var array + */ + protected static array $setters = [ + 'tags' => 'setTags' + ]; + + /** + * Array of attributes to getter functions (for serialization of requests) + * + * @var array + */ + protected static array $getters = [ + 'tags' => 'getTags' + ]; + + /** + * {@inheritdoc} + */ + public static function attributeMap(): array + { + return self::$attributeMap; + } + + /** + * {@inheritdoc} + */ + public static function setters(): array + { + return self::$setters; + } + + /** + * {@inheritdoc} + */ + public static function getters(): array + { + return self::$getters; + } + + /** + * {@inheritdoc} + */ + public function getModelName(): string + { + return self::$openAPIModelName; + } + + + /** + * Associative array for storing property values + * + * @var array + */ + protected array $container = []; + + /** + * Constructor + * + * @param array $data Associated array of property values initializing the model + */ + public function __construct(?array $data = null) + { + $this->setIfExists('tags', $data ?? [], null); + } + + /** + * Sets $this->container[$variableName] to the given data or to the given default Value; if $variableName + * is nullable and its value is set to null in the $fields array, then mark it as "set to null" in the + * $this->openAPINullablesSetToNull array + * + * @param string $variableName + * @param array $fields + * @param mixed $defaultValue + */ + private function setIfExists(string $variableName, array $fields, mixed $defaultValue): void + { + if (self::isNullable($variableName) && array_key_exists($variableName, $fields) && is_null($fields[$variableName])) { + $this->openAPINullablesSetToNull[] = $variableName; + } + + $this->container[$variableName] = $fields[$variableName] ?? $defaultValue; + } + + /** + * {@inheritdoc} + */ + public function listInvalidProperties(): array + { + $invalidProperties = []; + + return $invalidProperties; + } + + /** + * {@inheritdoc} + */ + public function valid(): bool + { + return count($this->listInvalidProperties()) === 0; + } + + + /** + * Gets tags + * + * @return \OpenAPI\Client\Model\Tag[]|null + */ + public function getTags(): ?array + { + return $this->container['tags']; + } + + /** + * Sets tags + * + * @param \OpenAPI\Client\Model\Tag[]|null $tags tags + * + * @return $this + */ + public function setTags(?array $tags): static + { + if (is_null($tags)) { + throw new InvalidArgumentException('non-nullable tags cannot be null'); + } + $this->container['tags'] = $tags; + + return $this; + } + /** + * Returns true if offset exists. False otherwise. + * + * @param int|string $offset Offset + * + * @return boolean + */ + public function offsetExists(mixed $offset): bool + { + return isset($this->container[$offset]); + } + + /** + * Gets offset. + * + * @param int|string $offset Offset + * + * @return mixed|null + */ + #[ReturnTypeWillChange] + public function offsetGet(mixed $offset): mixed + { + return $this->container[$offset] ?? null; + } + + /** + * Sets value based on offset. + * + * @param int|string|null $offset Offset + * @param mixed $value Value to be set + * + * @return void + */ + public function offsetSet(mixed $offset, mixed $value): void + { + if (is_null($offset)) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + + /** + * Unsets offset. + * + * @param int|string $offset Offset + * + * @return void + */ + public function offsetUnset(mixed $offset): void + { + unset($this->container[$offset]); + } + + /** + * Serializes the object to a value that can be serialized natively by json_encode(). + * @link https://www.php.net/manual/en/jsonserializable.jsonserialize.php + * + * @return mixed Returns data which can be serialized by json_encode(), which is a value + * of any type other than a resource. + */ + #[ReturnTypeWillChange] + public function jsonSerialize(): mixed + { + return ObjectSerializer::sanitizeForSerialization($this); + } + + /** + * Gets the string presentation of the object + * + * @return string + */ + public function __toString(): string + { + return json_encode( + ObjectSerializer::sanitizeForSerialization($this), + JSON_PRETTY_PRINT + ); + } + + /** + * Gets a header-safe presentation of the object + * + * @return string + */ + public function toHeaderValue(): string + { + return json_encode(ObjectSerializer::sanitizeForSerialization($this)); + } +} + + diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/tests/Model/AllOfRefArrayTest.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/tests/Model/AllOfRefArrayTest.php new file mode 100644 index 000000000000..0646ae90f80d --- /dev/null +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/tests/Model/AllOfRefArrayTest.php @@ -0,0 +1,88 @@ + Date: Wed, 21 Oct 2026 23:11:33 +0100 Subject: [PATCH 3/4] [php] Treat a single-member allOf as an alias in toAllOfName too Return the member's plain schema name instead of deferring to the default, so x-all-of-name is ignored consistently by both baseType and dataType: a single-member allOf never produces a model of its own. Co-Authored-By: Claude Fable 5.1 --- .../codegen/languages/AbstractPhpCodegen.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java index eebf74b42d3e..7d0d2c1b8657 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java @@ -1095,9 +1095,11 @@ public String toAllOfName(List names, Schema composedSchema) { List schemas = ModelUtils.getInterfaces(composedSchema); if (schemas.size() == 1) { - // a single member is a plain schema name; getSchemaType() turns it into a model - // name and getTypeDeclaration() qualifies it, like any other $ref - return super.toAllOfName(names, composedSchema); + // a single member is an alias of that member, not a new model: return its plain + // schema name so getSchemaType() turns it into a model name and getTypeDeclaration() + // qualifies it like any other $ref. x-all-of-name is deliberately ignored here, as it + // is in getTypeDeclaration(), because no class would be generated under that name. + return names.get(0); } List types = new ArrayList<>(); From 4baba277c79415c0b39b5db426450ddab702548e Mon Sep 17 00:00:00 2001 From: Ben Yarwood Date: Thu, 22 Oct 2026 08:51:47 +0100 Subject: [PATCH 4/4] [php-nextgen] Drop the once-only test file from the sample FILES manifest Test files are generated once and skipped when they exist, so CI's regeneration against the merge commit does not list tests/Model/AllOfRefArrayTest.php in FILES. Co-Authored-By: Claude Fable 5.1 --- .../php-nextgen/OpenAPIClient-php/.openapi-generator/FILES | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES b/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES index db8dc02cd6e7..79442c1ea60b 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/.openapi-generator/FILES @@ -164,4 +164,3 @@ src/Model/Whale.php src/Model/Zebra.php src/Model/Zoo.php src/ObjectSerializer.php -tests/Model/AllOfRefArrayTest.php