Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -781,9 +781,25 @@ public String toEnumValue(String value, String datatype) {
}
}

/**
* Builds the PHP expression for a backed enum case default (PHP 8.1+ {@code enum}).
* <p>
* The legacy {@code self::}{@code <datatype>_<CASE>} form came from class-constant style enums (#10273) and is
* invalid when {@code datatype} is a namespaced class: {@code self::} only resolves constants on the current
* class. Native enums must use {@code EnumType::CASE}.
* <p>
* Execution: {@code datatype} is produced upstream (e.g. {@link DefaultCodegen#updateCodegenPropertyEnum}) via
* {@link #getTypeDeclaration(Schema)} for the referenced enum schema; {@code value} is the sanitized case name
* from {@link #toEnumVarName}. We concatenate with {@code ::} so templates emit valid PHP (e.g.
* {@code \Vendor\Model\Status::AVAILABLE}).
*
* @param value enum case name (e.g. {@code AVAILABLE})
* @param datatype enum class as in generated PHP (often leading {@code \} + FQCN)
* @return PHP default expression for that case
*/
@Override
public String toEnumDefaultValue(String value, String datatype) {
return "self::" + datatype + "_" + value;
return datatype + "::" + value;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

package org.openapitools.codegen.php;

import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
Expand Down Expand Up @@ -328,6 +331,44 @@ public void testOptionalEnumRefQueryParameterWithDefaultAppliesOpenApiSemantics(
output.deleteOnExit();
}

/**
* Model property: string enum {@code $ref} with sibling {@code default} must produce a valid PHP 8.1 backed-enum
* default expression ({@code Type::CASE}), not {@code self::} + FQCN + {@code _CASE} from
* {@link AbstractPhpCodegen#toEnumDefaultValue}.
* <p>
* Spec: {@code src/test/resources/3_1/php-symfony/optional-enum-query-ref-default.yaml} ({@code Pet.HTTP.CreatePetRequest.status}).
*/
@Test
public void testModelPropertyEnumRefWithDefaultUsesNativeEnumCaseInCodegen() {
final var openAPI = TestUtils.parseFlattenSpec(
"src/test/resources/3_1/php-symfony/optional-enum-query-ref-default.yaml");
final PhpSymfonyServerCodegen codegen = new PhpSymfonyServerCodegen();
codegen.setOpenAPI(openAPI);
codegen.processOpts();

Schema createPet = openAPI.getComponents().getSchemas().get("Pet.HTTP.CreatePetRequest");
Assert.assertNotNull(createPet, "Fixture must define Pet.HTTP.CreatePetRequest");

CodegenModel cm = codegen.fromModel("Pet.HTTP.CreatePetRequest", createPet);
codegen.postProcessModels(TestUtils.createCodegenModelWrapper(cm));

CodegenProperty status = cm.getVars().stream()
.filter(v -> "status".equals(v.getName()))
.findFirst()
.orElseThrow(() -> new AssertionError("Expected status property on CreatePetRequest model"));

Assert.assertNotNull(
status.getDefaultValue(),
"Enum ref + OpenAPI default should set CodegenProperty.defaultValue (see AbstractPhpCodegen.toDefaultValue"
+ " ref+default handling and updateCodegenPropertyEnum)");
Assert.assertFalse(
status.getDefaultValue().startsWith("self::"),
"Invalid PHP: backed enum default must not use self:: prefix, got: " + status.getDefaultValue());
Assert.assertTrue(
status.getDefaultValue().contains("::AVAILABLE"),
"Expected PetModelPetStatus::AVAILABLE (or FQCN::AVAILABLE), got: " + status.getDefaultValue());
}

/**
* Runs {@code php -l} on the file. Skips if {@code php} is not available (optional toolchain).
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
# Minimal OpenAPI 3.1 spec: optional query with enum $ref + default (components.parameters).
# Repro pattern: omitting the query key should behave like the declared default; php-symfony
# may still validate null as enum type before business logic. See project troubleshooting doc.
# Minimal OpenAPI 3.1 spec (pet store style):
# - Optional query: enum $ref + default (components.parameters) — regression for query/controller path.
# - Model property: enum $ref + sibling default on an object schema — invalid PHP may be emitted for the
# property initializer (e.g. self::..._CASE) when default flows through AbstractPhpCodegen.toEnumDefaultValue.
openapi: 3.1.0
info:
title: Optional enum query ref with default (php-symfony repro)
version: '1.0'
servers:
- url: https://petstore.example.com/api
# Explicit empty security for minimal test fixtures (no global auth).
security: []
paths:
/pets:
post:
summary: Create a pet (request body uses enum ref + default on a property)
operationId: createPet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet.HTTP.CreatePetRequest'
responses:
'201':
description: Created
/pets/feed-hints:
get:
summary: List feed hints (optional enum query ref + default)
operationId: listFeedHints
parameters:
- $ref: '#/components/parameters/ToneQuery'
Expand Down Expand Up @@ -35,6 +54,19 @@ components:
$ref: '#/components/schemas/PetAnnouncementTone'
default: friendly
schemas:
Pet.Model.PetStatus:
type: string
enum:
- available
- pending
- sold
Pet.HTTP.CreatePetRequest:
type: object
properties:
# OAS 3.1: sibling keys beside $ref are allowed.
status:
$ref: '#/components/schemas/Pet.Model.PetStatus'
default: available
PetAnnouncementTone:
type: string
enum:
Expand Down
Loading