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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [11.1.3] - 2025.12.08
### Fixed
- Fixed content type construction parameter generation - issue #128, fixed
- with multiple content type values
- with content type value received from parameters

## [11.1.2] - 2025.10.28
### Fixed
- Enum with invalid PHP constant value
Expand Down
14 changes: 14 additions & 0 deletions example/PetStoreClient/doc/petstore3.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@
"summary": "Add a new pet to the store",
"description": "Add a new pet to the store",
"operationId": "addPet",
"parameters": [
{
"in" : "header",
"name": "Content-Type",
"required": true,
"schema": {
"type": "string",
"enum": [
"application/json",
"application/xml"
]
}
}
],
"requestBody": {
"description": "Create a new pet in the store",
"content": {
Expand Down
17 changes: 13 additions & 4 deletions example/PetStoreClient/src/Request/AddPetRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@
namespace OpenApi\PetStoreClient\Request;

use OpenApi\PetStoreClient\Schema\Pet;
use OpenApi\PetStoreClient\Schema\SerializableInterface;

class AddPetRequest implements RequestInterface
{
private Pet $pet;
public const CONTENT_TYPE_APPLICATION_JSON = 'application/json';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Are these constants used anywhere?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not from the Client. I extended the example with ContentType header enum and test run re-generated this example.
As I see these constants consumers. From PHP 8.1 it's not generated, becasue the enum class is used.


public const CONTENT_TYPE_APPLICATION_XML = 'application/xml';

private string $contentType;

public function __construct(Pet $pet, string $contentType)
private Pet $pet;

public function __construct(string $contentType, Pet $pet)
{
$this->pet = $pet;
$this->contentType = $contentType;
$this->pet = $pet;
}

public function getContentType(): string
Expand Down Expand Up @@ -56,7 +61,11 @@ public function getCookies(): array

public function getHeaders(): array
{
return ['Content-Type' => $this->contentType];
return array_merge(['Content-Type' => $this->contentType], array_map(static function ($value) {
return $value instanceof SerializableInterface ? $value->toArray() : $value;
}, array_filter(['Content-Type' => $this->contentType], static function ($value) {
return null !== $value;
})));
}

/**
Expand Down
14 changes: 14 additions & 0 deletions example/petstore3.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@
"summary": "Add a new pet to the store",
"description": "Add a new pet to the store",
"operationId": "addPet",
"parameters": [
{
"in" : "header",
"name": "Content-Type",
"required": true,
"schema": {
"type": "string",
"enum": [
"application/json",
"application/xml"
]
}
}
],
"requestBody": {
"description": "Create a new pet in the store",
"content": {
Expand Down
52 changes: 40 additions & 12 deletions src/Generator/RequestGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ class RequestGenerator extends MutatorAccessorClassGeneratorAbstract

public const SUBDIRECTORY = 'Request/';

private const CONTENT_TYPE_PARAMETER_NAME = 'contentType';

/** @var SecurityStrategyInterface[] */
private array $securityStrategies;

private bool $isContentTypeEnum = false;

public function __construct(
string $baseNamespace,
CodeBuilder $builder,
Expand All @@ -45,6 +49,7 @@ public function __construct(
public function generate(Specification $specification, PhpFileCollection $fileRegistry): void
{
foreach ($specification->getOperations() as $operation) {
$this->isContentTypeEnum = false;
$this->generateRequest($fileRegistry, $operation, $specification);
}
}
Expand Down Expand Up @@ -92,6 +97,7 @@ protected function generateEnums(Request $request): array
protected function generateProperties(Request $request, Operation $operation, Specification $specification): array
{
$statements = [];
$fieldNames = [];

foreach ($request->fields as $field) {
if ($field->isComposite()) {
Expand All @@ -117,13 +123,21 @@ protected function generateProperties(Request $request, Operation $operation, Sp
}

$statements[] = $this->generateProperty($field);
$fieldNames[] = $field->getPhpVariableName();
}

$default = null;
if (count($request->bodyContentTypes) < 2) {
$default = null;
$bodyContentTypesCount = count($request->bodyContentTypes);
if ($bodyContentTypesCount < 2) {
$default = $this->builder->val($request->bodyContentTypes[0] ?? '');
}
$statements[] = $this->builder->localProperty('contentType', 'string', 'string', false, $default);

if (
($bodyContentTypesCount < 2 || !$this->phpVersion->isConstructorPropertyPromotionSupported())
&& !in_array(self::CONTENT_TYPE_PARAMETER_NAME, $fieldNames, true)
) {
$statements[] = $this->builder->localProperty(self::CONTENT_TYPE_PARAMETER_NAME, 'string', 'string', false, $default);
}

foreach ($this->securityStrategies as $securityStrategy) {
array_push($statements, ...$securityStrategy->getProperties($operation, $specification));
Expand All @@ -137,6 +151,7 @@ protected function generateConstructor(
Operation $operation,
Specification $specification
): ?ClassMethod {
$paramNames = [];
$params = [];
$paramInits = [];
$validations = [];
Expand All @@ -163,7 +178,16 @@ protected function generateConstructor(
}
}

$params[] = $param;
$params[] = $param;
$paramNames[] = $field->getPhpVariableName();

if (
$field->isEnum()
&& $this->phpVersion->isEnumSupported()
&& $field->getPhpVariableName() === self::CONTENT_TYPE_PARAMETER_NAME
) {
$this->isContentTypeEnum = true;
}

$paramInits[] = $this->builder->assign(
$this->builder->localPropertyFetch($field->getPhpVariableName()),
Expand All @@ -177,14 +201,12 @@ protected function generateConstructor(
array_push($paramInits, ...$securityStrategy->getConstructorParamInits($operation, $specification));
}

if (count($request->bodyContentTypes) > 1) {
$contentTypeVariableName = 'contentType';

$params[] = $this->builder->param($contentTypeVariableName)->setType('string');
if (count($request->bodyContentTypes) > 1 && !in_array(self::CONTENT_TYPE_PARAMETER_NAME, $paramNames, true)) {
$params[] = $this->builder->param(self::CONTENT_TYPE_PARAMETER_NAME)->setType('string');

$paramInits[] = $this->builder->assign(
$this->builder->localPropertyFetch($contentTypeVariableName),
$this->builder->var($contentTypeVariableName)
$this->builder->localPropertyFetch(self::CONTENT_TYPE_PARAMETER_NAME),
$this->builder->var(self::CONTENT_TYPE_PARAMETER_NAME)
);
}

Expand Down Expand Up @@ -242,8 +264,14 @@ private function generateSetters(Request $request): array

private function generateGetContentType(): ClassMethod
{
$return = $this->builder->return($this->builder->localPropertyFetch('contentType'));
$returnType = 'string';
$localProperty = $this->builder->localPropertyFetch(self::CONTENT_TYPE_PARAMETER_NAME);
$returnType = 'string';

if ($this->isContentTypeEnum) {
$localProperty = $this->builder->propertyFetch($localProperty, 'value');
}

$return = $this->builder->return($localProperty);

return $this
->builder
Expand Down