Skip to content

Commit 91aee31

Browse files
committed
Added ability to map to backed enums
1 parent 73a725e commit 91aee31

File tree

5 files changed

+44
-2
lines changed

5 files changed

+44
-2
lines changed

src/EnvMapper.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,22 @@ public function map(string $class, bool $requireValues = false, ?array $source =
7676
* @return int|float|string|bool
7777
* The passed value, but now with the correct type.
7878
*/
79-
private function typeNormalize(string $val, \ReflectionProperty $rProp): int|float|string|bool
79+
private function typeNormalize(string $val, \ReflectionProperty $rProp): int|float|string|bool|\BackedEnum
8080
{
8181
$rType = $rProp->getType();
8282
if ($rType instanceof \ReflectionNamedType) {
83-
return match ($rType->getName()) {
83+
$name = $rType->getName();
84+
85+
if (is_a($name, \BackedEnum::class, true)) {
86+
$rEnum = new \ReflectionEnum($name);
87+
$backingType = $rEnum->getBackingType();
88+
assert($backingType instanceof \ReflectionNamedType);
89+
$isIntBacked = $backingType->getName() === 'int';
90+
91+
return $name::from($isIntBacked ? (int) $val : $val);
92+
}
93+
94+
return match ($name) {
8495
'string' => $val,
8596
'float' => is_numeric($val)
8697
? (float) $val

tests/EnvMapperTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Crell\EnvMapper\Envs\EnvWithDefaults;
88
use Crell\EnvMapper\Envs\EnvWithMissingValue;
99
use Crell\EnvMapper\Envs\EnvWithTypeMismatch;
10+
use Crell\EnvMapper\Envs\IntegerBackedEnum;
1011
use Crell\EnvMapper\Envs\SampleEnvironment;
12+
use Crell\EnvMapper\Envs\StringBackedEnum;
1113
use PHPUnit\Framework\Attributes\Test;
1214
use PHPUnit\Framework\TestCase;
1315

@@ -22,6 +24,8 @@ class EnvMapperTest extends TestCase
2224
'SHLVL' => '1',
2325
'ZIP_CODE' => '01234',
2426
'BOOL' => '1',
27+
'STRING_BACKED_ENUM' => 'FOO',
28+
'INTEGER_BACKED_ENUM' => '2',
2529
];
2630

2731
#[Test]
@@ -39,6 +43,8 @@ public function mapping_different_types_with_defaults_parses_correctly(): void
3943
self::assertNotNull($env->shlvl);
4044
self::assertSame('01234', $env->zipCode);
4145
self::assertSame(true, $env->bool);
46+
self::assertEquals(StringBackedEnum::Foo, $env->stringBackedEnum);
47+
self::assertEquals(IntegerBackedEnum::Bar, $env->integerBackedEnum);
4248
self::assertEquals('default', $env->missing);
4349
self::assertEquals(false, $env->missingFalse);
4450
self::assertEquals('', $env->missingEmptyString);

tests/Envs/IntegerBackedEnum.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Crell\EnvMapper\Envs;
6+
7+
enum IntegerBackedEnum: int {
8+
case Foo = 1;
9+
case Bar = 2;
10+
case Baz = 3;
11+
}

tests/Envs/SampleEnvironment.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ public function __construct(
1919
// This is a numeric string, but should stay a string.
2020
public readonly string $zipCode,
2121
public readonly bool $bool,
22+
// These should be mapped using ::from()
23+
public readonly StringBackedEnum $stringBackedEnum,
24+
public readonly IntegerBackedEnum $integerBackedEnum,
2225
// This is not defined in the environment, so the default value should be used.
2326
public readonly string $missing = 'default',
2427
// These are not defined in the environment, so the default falsy values should be used.

tests/Envs/StringBackedEnum.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Crell\EnvMapper\Envs;
6+
7+
enum StringBackedEnum: string {
8+
case Foo = 'FOO';
9+
case Bar = 'BAR';
10+
case Baz = 'BAZ';
11+
}

0 commit comments

Comments
 (0)