From c7c8201c53fbd77d139b3947e3cdb8139c10ea2e Mon Sep 17 00:00:00 2001 From: coffeemakr <5737978+coffeemakr@users.noreply.github.com> Date: Mon, 18 May 2026 16:27:37 +0200 Subject: [PATCH 1/4] Add test for issue #23813 --- .../php/PhpNextgenClientCodegenTest.java | 60 +++++++++++++++++++ ..._php_nextgen_oneOf_discriminator_enum.yaml | 53 ++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 modules/openapi-generator/src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml 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 88ad980ac167..b8d160b9569c 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 @@ -187,6 +187,66 @@ public void testEnumUnknownDefaultCaseDeserializationDisabled() throws Exception Assert.assertListContains(modelContent, a -> a.equalsIgnoreCase("\"Invalid value '%s' for 'color', must be one of '%s'\","), ""); } + @Test + public void testOneOfDiscriminatorEnumGeneration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.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())); + + Assert.assertNotNull(files.get("PetAnimal.php")); + + List combinedModelContent = Files + .readAllLines(files.get("PetAnimal.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + int styleAllowableValuesStart = combinedModelContent.indexOf("public static function getStyleAllowableValues()"); + Assert.assertTrue(styleAllowableValuesStart >= 0, + "Expected combined oneOf wrapper to declare getStyleAllowableValues"); + int styleAllowableValuesEnd = combinedModelContent.subList(styleAllowableValuesStart, combinedModelContent.size()).indexOf("];"); + Assert.assertTrue(styleAllowableValuesEnd >= 0, + "Expected combined oneOf wrapper to close the style allowable-values array"); + List styleAllowableValuesContent = combinedModelContent.subList( + styleAllowableValuesStart, + styleAllowableValuesStart + styleAllowableValuesEnd + 1); + Assert.assertListContains(combinedModelContent, + a -> a.equals("public const STYLE_PAGE = 'page';"), + "Expected combined oneOf wrapper to declare STYLE_PAGE constant"); + Assert.assertListContains(combinedModelContent, + a -> a.equals("public const STYLE_TEXT = 'text';"), + "Expected combined oneOf wrapper to declare STYLE_TEXT constant"); + Assert.assertListContains(combinedModelContent, + a -> a.equals("public const STYLE_VIEWPORT = 'viewport';"), + "Expected combined oneOf wrapper to declare STYLE_VIEWPORT constant"); + Assert.assertListContains(styleAllowableValuesContent, + a -> a.equals("self::STYLE_PAGE,"), + "Expected combined oneOf wrapper to use style enum values"); + Assert.assertListContains(styleAllowableValuesContent, + a -> a.equals("self::STYLE_TEXT,"), + "Expected combined oneOf wrapper to use style enum values"); + Assert.assertListContains(styleAllowableValuesContent, + a -> a.equals("self::STYLE_VIEWPORT,"), + "Expected combined oneOf wrapper to use style enum values"); + Assert.assertListNotContains(styleAllowableValuesContent, + a -> a.equals("self::TYPE_PET_DOG,"), + "Combined oneOf wrapper should not use type enum values for style"); + Assert.assertListNotContains(styleAllowableValuesContent, + a -> a.equals("self::TYPE_PET_CAT,"), + "Combined oneOf wrapper should not use type enum values for style"); + } + @Test public void testDifferentResponseSchemasWithEmpty() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); diff --git a/modules/openapi-generator/src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml b/modules/openapi-generator/src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml new file mode 100644 index 000000000000..62ceb3d61984 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml @@ -0,0 +1,53 @@ +openapi: 3.0.0 +info: + title: php-nextgen oneOf discriminator enum bug + version: 1.0.0 + +components: + schemas: + Pet: + type: object + properties: + id: + type: string + minLength: 1 + animal: + oneOf: + - $ref: '#/components/schemas/Dog' + - $ref: '#/components/schemas/Cat' + discriminator: + propertyName: type + mapping: + pet-dog: '#/components/schemas/Dog' + pet-cat: '#/components/schemas/Cat' + Dog: + type: object + properties: + type: + type: string + enum: ["pet-dog"] + default: "pet-dog" + imageId: + type: string + required: + - type + - imageId + Cat: + type: object + properties: + type: + type: string + enum: ["pet-cat"] + default: "pet-cat" + imageId: + type: string + style: + type: string + enum: + - "page" + - "text" + - "viewport" + required: + - type + - imageId + - style From 404d16c8757d6aa6e80a4e565cb4bc5aa858cf61 Mon Sep 17 00:00:00 2001 From: coffeemakr <5737978+coffeemakr@users.noreply.github.com> Date: Mon, 18 May 2026 17:15:40 +0200 Subject: [PATCH 2/4] fix(php-nextgen): First iteration to fix enums --- .../php-nextgen/model_generic.mustache | 22 +++++++++---------- .../OpenAPIClient-php/src/Model/Animal.php | 2 -- .../src/Model/DiscriminatorBase.php | 1 - 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache b/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache index 6d6b6ed44138..e78755835676 100644 --- a/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache @@ -171,22 +171,22 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}}{{/parentSchema}}{{^par return self::$openAPIModelName; } -{{#discriminator}} -{{#discriminator.mappedModels}} - public const {{#lambda.uppercase}}{{discriminator.propertyName}}_{{#lambda.snakecase}}{{mappingName}}{{/lambda.snakecase}}{{/lambda.uppercase}} = '{{mappingName}}'; -{{/discriminator.mappedModels}} -{{/discriminator}} -{{^discriminator}} {{#vars}} {{#isEnum}} + {{#isDiscriminator}} + {{#discriminator.mappedModels}} + public const {{#lambda.uppercase}}{{discriminator.propertyName}}_{{#lambda.snakecase}}{{mappingName}}{{/lambda.snakecase}}{{/lambda.uppercase}} = '{{mappingName}}'; + {{/discriminator.mappedModels}} + {{/isDiscriminator}} + {{^isDiscriminator}} {{#allowableValues}} {{#enumVars}} public const {{enumName}}_{{{name}}} = {{{value}}}; {{/enumVars}} {{/allowableValues}} + {{/isDiscriminator}} {{/isEnum}} {{/vars}} -{{/discriminator}} {{#vars}} {{#isEnum}} @@ -198,15 +198,15 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}}{{/parentSchema}}{{^par public static function {{getter}}AllowableValues() { return [ -{{#discriminator}} +{{#isDiscriminator}} {{#discriminator.mappedModels}} self::{{#lambda.uppercase}}{{discriminator.propertyName}}_{{#lambda.snakecase}}{{mappingName}}{{/lambda.snakecase}}{{/lambda.uppercase}},{{^-last}} {{/-last}}{{/discriminator.mappedModels}} -{{/discriminator}} -{{^discriminator}} +{{/isDiscriminator}} +{{^isDiscriminator}} {{#allowableValues}}{{#enumVars}}self::{{enumName}}_{{{name}}},{{^-last}} {{/-last}}{{/enumVars}}{{/allowableValues}} -{{/discriminator}} +{{/isDiscriminator}} ]; } diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php index 13b677c32af7..c2d9a967eddb 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php @@ -214,8 +214,6 @@ public function getModelName(): string return self::$openAPIModelName; } - public const CLASS_NAME_CAT = 'CAT'; - public const CLASS_NAME_DOG = 'DOG'; /** * Associative array for storing property values diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php index f0c8e04614c0..25da38adb46f 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php @@ -208,7 +208,6 @@ public function getModelName(): string return self::$openAPIModelName; } - public const TYPE_DISCRIMINATOR_CHILD = 'DiscriminatorChild'; /** * Associative array for storing property values From 330c81810abb37c0e84bdc6c98c1ce03f21b1888 Mon Sep 17 00:00:00 2001 From: coffeemakr <5737978+coffeemakr@users.noreply.github.com> Date: Mon, 18 May 2026 17:18:01 +0200 Subject: [PATCH 3/4] fix(php-nextgen): Re-add discriminator static properties --- .../php-nextgen/model_generic.mustache | 10 ++--- .../php/PhpNextgenClientCodegenTest.java | 44 +++++++++++++++++++ .../OpenAPIClient-php/src/Model/Animal.php | 2 + .../src/Model/DiscriminatorBase.php | 1 + 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache b/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache index e78755835676..ddb488c503a0 100644 --- a/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/php-nextgen/model_generic.mustache @@ -171,13 +171,13 @@ class {{classname}} {{#parentSchema}}extends {{{parent}}}{{/parentSchema}}{{^par return self::$openAPIModelName; } +{{#discriminator}} +{{#discriminator.mappedModels}} + public const {{#lambda.uppercase}}{{discriminator.propertyName}}_{{#lambda.snakecase}}{{mappingName}}{{/lambda.snakecase}}{{/lambda.uppercase}} = '{{mappingName}}'; +{{/discriminator.mappedModels}} +{{/discriminator}} {{#vars}} {{#isEnum}} - {{#isDiscriminator}} - {{#discriminator.mappedModels}} - public const {{#lambda.uppercase}}{{discriminator.propertyName}}_{{#lambda.snakecase}}{{mappingName}}{{/lambda.snakecase}}{{/lambda.uppercase}} = '{{mappingName}}'; - {{/discriminator.mappedModels}} - {{/isDiscriminator}} {{^isDiscriminator}} {{#allowableValues}} {{#enumVars}} 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 b8d160b9569c..a8a85df0fd2c 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 @@ -247,6 +247,50 @@ public void testOneOfDiscriminatorEnumGeneration() throws Exception { "Combined oneOf wrapper should not use type enum values for style"); } + @Test + public void testDiscriminatorConstantsPreservedForNonEnumDiscriminatorModels() 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()); + + 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())); + + Assert.assertNotNull(files.get("Animal.php")); + Assert.assertNotNull(files.get("DiscriminatorBase.php")); + + List animalModelContent = Files + .readAllLines(files.get("Animal.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + Assert.assertListContains(animalModelContent, + a -> a.equals("public const CLASS_NAME_DOG = 'DOG';"), + "Expected Animal to preserve discriminator constant CLASS_NAME_DOG"); + Assert.assertListContains(animalModelContent, + a -> a.equals("public const CLASS_NAME_CAT = 'CAT';"), + "Expected Animal to preserve discriminator constant CLASS_NAME_CAT"); + + List discriminatorBaseModelContent = Files + .readAllLines(files.get("DiscriminatorBase.php").toPath()) + .stream() + .map(String::trim) + .collect(Collectors.toList()); + Assert.assertListContains(discriminatorBaseModelContent, + a -> a.equals("public const TYPE_DISCRIMINATOR_CHILD = 'DiscriminatorChild';"), + "Expected DiscriminatorBase to preserve inferred discriminator constants"); + } + @Test public void testDifferentResponseSchemasWithEmpty() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php index c2d9a967eddb..13b677c32af7 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/Animal.php @@ -214,6 +214,8 @@ public function getModelName(): string return self::$openAPIModelName; } + public const CLASS_NAME_CAT = 'CAT'; + public const CLASS_NAME_DOG = 'DOG'; /** * Associative array for storing property values diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php index 25da38adb46f..f0c8e04614c0 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Model/DiscriminatorBase.php @@ -208,6 +208,7 @@ public function getModelName(): string return self::$openAPIModelName; } + public const TYPE_DISCRIMINATOR_CHILD = 'DiscriminatorChild'; /** * Associative array for storing property values From 14e75a673ca406bf8e9a10aaac72acde4a621830 Mon Sep 17 00:00:00 2001 From: coffeemakr <5737978+coffeemakr@users.noreply.github.com> Date: Mon, 18 May 2026 17:26:55 +0200 Subject: [PATCH 4/4] fix(test): Rename the test file --- .../openapitools/codegen/php/PhpNextgenClientCodegenTest.java | 2 +- ...p_nextgen_oneOf_discriminator_enum.yaml => issue_23813.yaml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename modules/openapi-generator/src/test/resources/bugs/{issue_php_nextgen_oneOf_discriminator_enum.yaml => issue_23813.yaml} (100%) 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 a8a85df0fd2c..edbd3894dfa2 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 @@ -193,7 +193,7 @@ public void testOneOfDiscriminatorEnumGeneration() throws Exception { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_23813.yaml", null, new ParseOptions()).getOpenAPI(); codegen.setOutputDir(output.getAbsolutePath()); diff --git a/modules/openapi-generator/src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml b/modules/openapi-generator/src/test/resources/bugs/issue_23813.yaml similarity index 100% rename from modules/openapi-generator/src/test/resources/bugs/issue_php_nextgen_oneOf_discriminator_enum.yaml rename to modules/openapi-generator/src/test/resources/bugs/issue_23813.yaml