Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ class ObjectSerializer
// If a discriminator is defined and points to a valid subclass, use it.
$discriminator = $class::DISCRIMINATOR;
if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) {
$subclass = '\{{invokerPackage}}\Model\\' . $data->{$discriminator};
$subclass = '\{{modelPackage}}\\' . $data->{$discriminator};
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Resolve discriminator values through the generated mapping before building the subclass name. Custom discriminator mappings will otherwise deserialize to the base model instead of the mapped subtype.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/php-nextgen/ObjectSerializer.mustache, line 502:

<comment>Resolve discriminator values through the generated mapping before building the subclass name. Custom discriminator mappings will otherwise deserialize to the base model instead of the mapped subtype.</comment>

<file context>
@@ -499,7 +499,7 @@ class ObjectSerializer
             $discriminator = $class::DISCRIMINATOR;
             if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) {
-                $subclass = '\{{invokerPackage}}\Model\\' . $data->{$discriminator};
+                $subclass = '\{{modelPackage}}\\' . $data->{$discriminator};
                 if (is_subclass_of($subclass, $class)) {
                     $class = $subclass;
</file context>
Fix with Cubic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this scenario (where discriminator is limited to existing class), the use case is valid.

if (is_subclass_of($subclass, $class)) {
$class = $subclass;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,45 @@ public void testEnumUnknownDefaultCaseDeserializationEnabled() throws Exception
Assert.assertListNotContains(modelContent, a -> a.equals("\"Invalid value '%s' for 'color', must be one of '%s'\","), "");
}

@Test
public void testDiscriminatorUsesModelPackageNamespace() throws Exception {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

OpenAPI openAPI = new OpenAPIParser()
.readLocation("src/test/resources/3_0/php-nextgen/petstore-with-fake-endpoints-models-for-testing.yaml", null, new ParseOptions()).getOpenAPI();

codegen.setOutputDir(output.getAbsolutePath());
// Set invokerPackage="MyApp" and modelPackage="Entities" (relative suffix).
// AbstractPhpCodegen.processOpts() will produce final modelPackage = "MyApp\Entities".
// The old bug would have emitted '\MyApp\Model\' (invokerPackage + \Model\).
codegen.additionalProperties().put(CodegenConstants.INVOKER_PACKAGE, "MyApp");
codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "Entities");

ClientOptInput input = new ClientOptInput()
.openAPI(openAPI)
.config(codegen);

DefaultGenerator generator = new DefaultGenerator();
Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));

List<String> objectSerializerContent = Files
.readAllLines(files.get("ObjectSerializer.php").toPath())
.stream()
.map(String::trim)
.collect(Collectors.toList());

// The discriminator subclass lookup must use modelPackage (\MyApp\Entities\),
// NOT invokerPackage + '\Model' (\MyApp\Model\).
Assert.assertListContains(objectSerializerContent,
a -> a.contains("'\\MyApp\\Entities\\\\'"),
"ObjectSerializer discriminator subclass lookup must use modelPackage namespace");
Assert.assertListNotContains(objectSerializerContent,
a -> a.contains("'\\MyApp\\Model\\\\'"),
"ObjectSerializer discriminator must NOT use invokerPackage\\Model namespace");
}

@Test
public void testEnumUnknownDefaultCaseDeserializationDisabled() throws Exception {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2291,3 +2291,22 @@ components:
description: "Optional array of multiple errors encountered during processing"
required:
- error

DiscriminatorBase:
type: object
discriminator:
propertyName: type
required:
- type
properties:
type:
type: string

DiscriminatorChild:
allOf:
- $ref: '#/components/schemas/DiscriminatorBase'
- type: object
properties:
childProperty:
type: string

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ docs/Model/ChildWithNullable.md
docs/Model/ClassModel.md
docs/Model/Client.md
docs/Model/DeprecatedObject.md
docs/Model/DiscriminatorBase.md
docs/Model/DiscriminatorChild.md
docs/Model/Dog.md
docs/Model/EnumArrays.md
docs/Model/EnumClass.md
Expand Down Expand Up @@ -91,6 +93,8 @@ src/Model/ChildWithNullable.php
src/Model/ClassModel.php
src/Model/Client.php
src/Model/DeprecatedObject.php
src/Model/DiscriminatorBase.php
src/Model/DiscriminatorChild.php
src/Model/Dog.php
src/Model/EnumArrays.php
src/Model/EnumClass.php
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ Class | Method | HTTP request | Description
- [ClassModel](docs/Model/ClassModel.md)
- [Client](docs/Model/Client.md)
- [DeprecatedObject](docs/Model/DeprecatedObject.md)
- [DiscriminatorBase](docs/Model/DiscriminatorBase.md)
- [DiscriminatorChild](docs/Model/DiscriminatorChild.md)
- [Dog](docs/Model/Dog.md)
- [EnumArrays](docs/Model/EnumArrays.md)
- [EnumClass](docs/Model/EnumClass.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# # DiscriminatorBase

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**type** | **string** | |

[[Back to Model list]](../../README.md#models) [[Back to API list]](../../README.md#endpoints) [[Back to README]](../../README.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# # DiscriminatorChild
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Use a single Markdown heading marker for the model title.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/php-nextgen/OpenAPIClient-php/docs/Model/DiscriminatorChild.md, line 1:

<comment>Use a single Markdown heading marker for the model title.</comment>

<file context>
@@ -0,0 +1,9 @@
+# # DiscriminatorChild
+
+## Properties
</file context>
Suggested change
# # DiscriminatorChild
# DiscriminatorChild
Fix with Cubic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the line in template modules/openapi-generator/src/main/resources/php-nextgen/model_doc.mustache

is currently written as:

# {{#models}}{{#model}}# {{classname}}

should be only

# {{classname}}


## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**child_property** | **string** | | [optional]

[[Back to Model list]](../../README.md#models) [[Back to API list]](../../README.md#endpoints) [[Back to README]](../../README.md)
Loading
Loading