Skip to content

Commit 9df4dfd

Browse files
author
Enno Woortmann
committed
mixed enums
1 parent 9884141 commit 9df4dfd

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

src/SchemaProcessor/PostProcessor/EnumPostProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ private function renderEnum(
202202
$cases = [];
203203

204204
foreach ($values as $value) {
205-
$cases[ucfirst($map ? array_search($value, $map) : $value)] = var_export($value, true);
205+
$cases[ucfirst($map ? array_search($value, $map, true) : $value)] = var_export($value, true);
206206
}
207207

208208
$backedType = null;

src/SchemaProcessor/PostProcessor/Templates/Enum.phptpl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ declare(strict_types=1);
44

55
namespace {{ namespace }};
66

7+
{% if not backedType %}
8+
use ValueError;
9+
{% endif %}
10+
711
enum {{ name }}{% if backedType %}: {{ backedType }}{% endif %} {
812
{% foreach cases as case, value %}
913
case {{ case }}{% if backedType %} = {{ value }}{% endif %};
@@ -12,16 +16,25 @@ enum {{ name }}{% if backedType %}: {{ backedType }}{% endif %} {
1216
{% if not backedType %}
1317
public static function from(mixed $value): self
1418
{
15-
switch ($value) {
19+
switch (true) {
1620
{% foreach cases as case, value %}
17-
case {{ value }}: return self::{{ case }};
21+
case $value === {{ value }}: return self::{{ case }};
1822
{% endforeach %}
1923
default: throw new ValueError(
2024
sprintf('Invalid enum value %s for enum %s', var_export($value, true), self::class)
2125
);
2226
}
2327
}
2428

29+
public static function tryFrom(mixed $value): ?self
30+
{
31+
try {
32+
return self::from($value);
33+
} catch (ValueError) {
34+
return null;
35+
}
36+
}
37+
2538
public function value(): mixed
2639
{
2740
switch ($this) {

tests/PostProcessor/EnumPostProcessorTest.php

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
use PHPModelGenerator\SchemaProcessor\PostProcessor\EnumPostProcessor;
1414
use PHPModelGenerator\Tests\AbstractPHPModelGeneratorTest;
1515
use ReflectionEnum;
16+
use UnitEnum;
1617

17-
// TODO: mixed enums, multiple enums, enum redirect
18+
// TODO: multiple enums, enum redirect
1819
class EnumPostProcessorTest extends AbstractPHPModelGeneratorTest
1920
{
2021
/**
@@ -267,6 +268,65 @@ public function testIntOnlyEnum(): void
267268
$object->setProperty(1);
268269
}
269270

271+
/**
272+
* @requires PHP >= 8.1
273+
*/
274+
public function testMixedEnum(): void
275+
{
276+
$this->addPostProcessor();
277+
278+
$className = $this->generateClassFromFileTemplate(
279+
'EnumPropertyMapped.json',
280+
['["Hans", 100, true]', '{"a": "Hans", "b": 100, "c": true}'],
281+
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false),
282+
false
283+
);
284+
285+
$this->includeGeneratedEnums(1);
286+
287+
$object = new $className(['property' => 'Hans']);
288+
$this->assertSame('Hans', $object->getProperty()->value());
289+
290+
$object->setProperty(100);
291+
$this->assertSame(100, $object->getProperty()->value());
292+
293+
$object->setProperty(null);
294+
$this->assertNull($object->getProperty());
295+
296+
$returnType = $this->getReturnType($object, 'getProperty');
297+
$this->assertTrue($returnType->allowsNull());
298+
$enum = $returnType->getName();
299+
300+
$this->assertTrue(enum_exists($enum));
301+
$reflectionEnum = new ReflectionEnum($enum);
302+
$enumName = $reflectionEnum->getShortName();
303+
304+
$this->assertEqualsCanonicalizing(
305+
[$enumName, 'null'],
306+
explode('|', $this->getReturnTypeAnnotation($object, 'getProperty'))
307+
);
308+
309+
$this->assertNull($reflectionEnum->getBackingType());
310+
311+
$this->assertEqualsCanonicalizing(
312+
['A', 'B', 'C'],
313+
array_map(function (UnitEnum $value): string { return $value->name; }, $enum::cases())
314+
);
315+
316+
$object->setProperty($enum::C);
317+
$this->assertSame(true, $object->getProperty()->value());
318+
319+
$this->assertNull($this->getParameterType($object, 'setProperty'));
320+
321+
$this->assertSame($enum::A, $enum::from('Hans'));
322+
$this->assertSame($enum::A, $enum::tryFrom('Hans'));
323+
$this->assertNull($enum::tryFrom('Dieter'));
324+
325+
$this->expectException(EnumException::class);
326+
$this->expectExceptionMessage('Invalid value for property declined by enum constraint');
327+
$object->setProperty(1);
328+
}
329+
270330
/**
271331
* @requires PHP >= 8.1
272332
*/

0 commit comments

Comments
 (0)