Skip to content

Commit 83e9c82

Browse files
author
Anton Bialetski
committed
Array of enums support
1 parent 0c611b4 commit 83e9c82

18 files changed

+597
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [11.1.0] - 2025.07.08
8+
### Added
9+
- Support for array of enum elements in Schemas
10+
711
## [11.0.0] - 2025.04.21
812
### Added
913
- Support for OpenAPI 3.1

src/Generator/EnumGenerator.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public function generate(Specification $specification, PhpFileCollection $fileRe
4343
}
4444
}
4545
}
46+
47+
if ($field->isEnum()) {
48+
$this->generateEnum($field, $fileRegistry);
49+
}
4650
}
4751
foreach ($specification->getOperations() as $operation) {
4852
foreach ($operation->request->fields as $field) {

src/Generator/MutatorAccessorClassGeneratorAbstract.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ protected function generateEnumStatements(Field $field): array
113113
}
114114

115115
$statements = [];
116-
$enumValues = $field->getEnumValues();
116+
$enumValues = $field->isArrayOfEnums() ? $field->getArrayItem()->getEnumValues() : $field->getEnumValues();
117117
if (!empty($enumValues)) {
118118
foreach ($enumValues as $enumValue) {
119119
if (is_string($enumValue)) {

src/Generator/SchemaGenerator.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,27 @@ private function collectSerializationFields(Field $root, Variable $arrayVariable
325325
if ($propertyField->isNullable()) {
326326
$value = $this->builder->nullsafePropertyFetch($value, 'value');
327327
}
328+
} elseif ($propertyField->isArrayOfEnums() && $this->phpVersion->isEnumSupported()) {
329+
$enumField = $propertyField->getArrayItem();
330+
$arrayMapCall = $this->builder->funcCall(
331+
'array_map',
332+
[
333+
$this->builder->arrowFunction(
334+
$this->builder->propertyFetch($this->builder->var('item'), 'value'),
335+
[$this->builder->param('item')->setType($enumField->getPhpClassName())->getNode()],
336+
$enumField->getType()->toPhpType(),
337+
),
338+
$value,
339+
]
340+
);
341+
342+
$value = $propertyField->isNullable()
343+
? $this->builder->ternary(
344+
$this->builder->notEquals($value, $this->builder->val(null)),
345+
$arrayMapCall,
346+
$this->builder->val(null)
347+
)
348+
: $arrayMapCall;
328349
}
329350

330351
$fieldName = $this->builder->val($propertyField->getName());

src/Generator/SchemaMapperGenerator.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,29 @@ protected function generateMapStatementsForObject(Field $root, Variable $payload
362362
} else {
363363
$requiredVars[] = $newEnum;
364364
}
365+
} elseif ($field->isArrayOfEnums() && $this->phpVersion->isEnumSupported()) {
366+
$enumField = $field->getArrayItem();
367+
$this->addImport($this->fqdn($this->withSubNamespace(SchemaGenerator::NAMESPACE_SUBPATH), $enumField->getPhpClassName()));
368+
369+
$arrowFunctionParam = $this->builder->param('item')->setType($enumField->getType()->toPhpType())->getNode();
370+
$arrayMapCall = $this->builder->funcCall(
371+
'array_map',
372+
[
373+
$this->builder->arrowFunction(
374+
$this->builder->staticCall($enumField->getPhpClassName(), 'from', [$this->builder->var('item')]),
375+
[$arrowFunctionParam],
376+
$enumField->getPhpClassName(),
377+
),
378+
$requiredResponseItems[$i],
379+
]
380+
);
381+
$requiredVars[] = $field->isNullable()
382+
? $this->builder->ternary(
383+
$this->builder->notEquals($requiredResponseItems[$i], $this->builder->val(null)),
384+
$arrayMapCall,
385+
$this->builder->val(null)
386+
)
387+
: $arrayMapCall;
365388
} else {
366389
$requiredVars[] = $requiredResponseItems[$i];
367390
}
@@ -409,6 +432,29 @@ protected function generateMapStatementsForObject(Field $root, Variable $payload
409432
} elseif ($field->isEnum() && $this->phpVersion->isEnumSupported()) {
410433
$this->addImport($this->fqdn($this->withSubNamespace(SchemaGenerator::NAMESPACE_SUBPATH), $field->getPhpClassName()));
411434
$optionalVar = $this->builder->staticCall($field->getPhpClassName(), 'from', [$optionalResponseItems[$i]]);
435+
} elseif ($field->isArrayOfEnums() && $this->phpVersion->isEnumSupported()) {
436+
$enumField = $field->getArrayItem();
437+
$this->addImport($this->fqdn($this->withSubNamespace(SchemaGenerator::NAMESPACE_SUBPATH), $enumField->getPhpClassName()));
438+
439+
$arrowFunctionParam = $this->builder->param('item')->setType($enumField->getType()->toPhpType())->getNode();
440+
$arrayMapCall = $this->builder->funcCall(
441+
'array_map',
442+
[
443+
$this->builder->arrowFunction(
444+
$this->builder->staticCall($enumField->getPhpClassName(), 'from', [$this->builder->var('item')]),
445+
[$arrowFunctionParam],
446+
$enumField->getPhpClassName(),
447+
),
448+
$optionalResponseItems[$i],
449+
]
450+
);
451+
$optionalVar = $field->isNullable()
452+
? $this->builder->ternary(
453+
$this->builder->notEquals($optionalResponseItems[$i], $this->builder->val(null)),
454+
$arrayMapCall,
455+
$this->builder->val(null)
456+
)
457+
: $arrayMapCall;
412458
} else {
413459
$optionalVar = $optionalResponseItems[$i];
414460
}

src/Input/Parser.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66

77
use cebe\openapi\ReferenceContext;
88
use cebe\openapi\spec\OpenApi;
9+
use DoclerLabs\ApiClientGenerator\Ast\PhpVersion;
910
use DoclerLabs\ApiClientGenerator\Entity\Field;
1011
use DoclerLabs\ApiClientGenerator\Entity\FieldCollection;
1112
use DoclerLabs\ApiClientGenerator\Entity\OperationCollection;
1213
use DoclerLabs\ApiClientGenerator\Input\Factory\OperationCollectionFactory;
1314

1415
class Parser
1516
{
16-
public function __construct(private OperationCollectionFactory $operationCollectionFactory)
17-
{
17+
public function __construct(
18+
private OperationCollectionFactory $operationCollectionFactory,
19+
private PhpVersion $phpVersion
20+
) {
1821
}
1922

2023
public function parse(array $data, string $contextUri): Specification
@@ -79,6 +82,10 @@ private function extractField(Field $field, FieldCollection $allFields): void
7982
$allFields->add($field->getArrayItem());
8083
$this->extractPropertyFields($field->getArrayItem(), $allFields);
8184
}
85+
86+
if ($field->isArrayOfEnums() && $this->phpVersion->isEnumSupported()) {
87+
$allFields->add($field->getArrayItem());
88+
}
8289
}
8390

8491
private function extractPropertyFields(Field $rootObject, FieldCollection $allFields): void

src/ServiceProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ public function register(Container $pimple): void
143143
$pimple[FileReader::class] = static fn () => new FileReader();
144144

145145
$pimple[OpenApiParser::class] = static fn (Container $container) => new OpenApiParser(
146-
$container[OperationCollectionFactory::class]
146+
$container[OperationCollectionFactory::class],
147+
$container[PhpVersion::class]
147148
);
148149

149150
$pimple[CodeBuilder::class] = static fn (Container $container) => new CodeBuilder(

test/suite/functional/Generator/EnumGeneratorTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ public function exampleProvider(): array
3535
self::BASE_NAMESPACE . SchemaGenerator::NAMESPACE_SUBPATH . '\\ItemMandatoryEnum',
3636
ConfigurationBuilder::fake()->withPhpVersion(PhpVersion::VERSION_PHP81)->build(),
3737
],
38+
'Array of Enums - String Enum' => [
39+
'/Schema/arrayOfEnums.yaml',
40+
'/Schema/StringParamOneEnum.php',
41+
self::BASE_NAMESPACE . SchemaGenerator::NAMESPACE_SUBPATH . '\\StringParamOneEnum',
42+
ConfigurationBuilder::fake()->withPhpVersion(PhpVersion::VERSION_PHP81)->build(),
43+
],
44+
'Array of Enums - Integer Enum' => [
45+
'/Schema/arrayOfEnums.yaml',
46+
'/Schema/IntParamEnum.php',
47+
self::BASE_NAMESPACE . SchemaGenerator::NAMESPACE_SUBPATH . '\\IntParamEnum',
48+
ConfigurationBuilder::fake()->withPhpVersion(PhpVersion::VERSION_PHP81)->build(),
49+
],
3850
];
3951
}
4052

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file was generated by docler-labs/api-client-generator.
7+
*
8+
* Do not edit it manually.
9+
*/
10+
11+
namespace Test\Schema;
12+
13+
enum IntParamEnum: int
14+
{
15+
case V_2 = 2;
16+
case V_4 = 4;
17+
case V_6 = 6;
18+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file was generated by docler-labs/api-client-generator.
7+
*
8+
* Do not edit it manually.
9+
*/
10+
11+
namespace Test\Schema;
12+
13+
use JsonSerializable;
14+
15+
class ItemWithArraysOfEnumProperties implements SerializableInterface, JsonSerializable
16+
{
17+
public const MANDATORY_STRING_ENUM_ARRAY_OPTION1 = 'option1';
18+
19+
public const MANDATORY_STRING_ENUM_ARRAY_OPTION2 = 'option2';
20+
21+
public const MANDATORY_STRING_ENUM_ARRAY_OPTION3 = 'option3';
22+
23+
public const MANDATORY_NULLABLE_STRING_ENUM_ARRAY_OPTION1 = 'option1';
24+
25+
public const MANDATORY_NULLABLE_STRING_ENUM_ARRAY_OPTION2 = 'option2';
26+
27+
public const MANDATORY_NULLABLE_STRING_ENUM_ARRAY_OPTION3 = 'option3';
28+
29+
public const OPTIONAL_STRING_ENUM_ARRAY_OPTION_A = 'optionA';
30+
31+
public const OPTIONAL_STRING_ENUM_ARRAY_OPTION_B = 'optionB';
32+
33+
public const OPTIONAL_STRING_ENUM_ARRAY_OPTION_C = 'optionC';
34+
35+
public const NULLABLE_STRING_ENUM_ARRAY_OPTION_A = 'optionA';
36+
37+
public const NULLABLE_STRING_ENUM_ARRAY_OPTION_B = 'optionB';
38+
39+
public const NULLABLE_STRING_ENUM_ARRAY_OPTION_C = 'optionC';
40+
41+
private array $mandatoryStringEnumArray;
42+
43+
private ?array $mandatoryNullableStringEnumArray = null;
44+
45+
private ?array $optionalStringEnumArray = null;
46+
47+
private array $mandatoryIntegerEnumArray;
48+
49+
private ?array $nullableStringEnumArray = null;
50+
51+
private array $optionalPropertyChanged = ['optionalStringEnumArray' => false, 'nullableStringEnumArray' => false];
52+
53+
/**
54+
* @param string[] $mandatoryStringEnumArray
55+
* @param string[]|null $mandatoryNullableStringEnumArray
56+
* @param int[] $mandatoryIntegerEnumArray
57+
*/
58+
public function __construct(array $mandatoryStringEnumArray, ?array $mandatoryNullableStringEnumArray, array $mandatoryIntegerEnumArray)
59+
{
60+
$this->mandatoryStringEnumArray = $mandatoryStringEnumArray;
61+
$this->mandatoryNullableStringEnumArray = $mandatoryNullableStringEnumArray;
62+
$this->mandatoryIntegerEnumArray = $mandatoryIntegerEnumArray;
63+
}
64+
65+
/**
66+
* @param string[] $optionalStringEnumArray
67+
*/
68+
public function setOptionalStringEnumArray(array $optionalStringEnumArray): self
69+
{
70+
$this->optionalStringEnumArray = $optionalStringEnumArray;
71+
$this->optionalPropertyChanged['optionalStringEnumArray'] = true;
72+
73+
return $this;
74+
}
75+
76+
/**
77+
* @param string[]|null $nullableStringEnumArray
78+
*/
79+
public function setNullableStringEnumArray(?array $nullableStringEnumArray): self
80+
{
81+
$this->nullableStringEnumArray = $nullableStringEnumArray;
82+
$this->optionalPropertyChanged['nullableStringEnumArray'] = true;
83+
84+
return $this;
85+
}
86+
87+
public function hasOptionalStringEnumArray(): bool
88+
{
89+
return $this->optionalPropertyChanged['optionalStringEnumArray'];
90+
}
91+
92+
public function hasNullableStringEnumArray(): bool
93+
{
94+
return $this->optionalPropertyChanged['nullableStringEnumArray'];
95+
}
96+
97+
/**
98+
* @return string[]
99+
*/
100+
public function getMandatoryStringEnumArray(): array
101+
{
102+
return $this->mandatoryStringEnumArray;
103+
}
104+
105+
/**
106+
* @return string[]|null
107+
*/
108+
public function getMandatoryNullableStringEnumArray(): ?array
109+
{
110+
return $this->mandatoryNullableStringEnumArray;
111+
}
112+
113+
/**
114+
* @return string[]|null
115+
*/
116+
public function getOptionalStringEnumArray(): ?array
117+
{
118+
return $this->optionalStringEnumArray;
119+
}
120+
121+
/**
122+
* @return int[]
123+
*/
124+
public function getMandatoryIntegerEnumArray(): array
125+
{
126+
return $this->mandatoryIntegerEnumArray;
127+
}
128+
129+
/**
130+
* @return string[]|null
131+
*/
132+
public function getNullableStringEnumArray(): ?array
133+
{
134+
return $this->nullableStringEnumArray;
135+
}
136+
137+
public function toArray(): array
138+
{
139+
$fields = [];
140+
$fields['mandatoryStringEnumArray'] = $this->mandatoryStringEnumArray;
141+
$fields['mandatoryNullableStringEnumArray'] = $this->mandatoryNullableStringEnumArray;
142+
if ($this->hasOptionalStringEnumArray()) {
143+
$fields['optionalStringEnumArray'] = $this->optionalStringEnumArray;
144+
}
145+
$fields['mandatoryIntegerEnumArray'] = $this->mandatoryIntegerEnumArray;
146+
if ($this->hasNullableStringEnumArray()) {
147+
$fields['nullableStringEnumArray'] = $this->nullableStringEnumArray;
148+
}
149+
150+
return $fields;
151+
}
152+
153+
public function jsonSerialize(): array
154+
{
155+
return $this->toArray();
156+
}
157+
}

0 commit comments

Comments
 (0)