Skip to content

Commit ba50f98

Browse files
committed
int backed enums
1 parent 28bfd32 commit ba50f98

File tree

5 files changed

+91
-10
lines changed

5 files changed

+91
-10
lines changed

docs/source/nonStandardExtensions/filter.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Filters may change the type of the property. For example the builtin filter **da
9191

9292
As the required check is executed before the filter a filter may transform a required value into a null value. Be aware when writing custom filters which transform values to not break your validation rules by adding filters to a property.
9393

94-
Only one transforming filter per property is allowed. may be positioned anywhere in the filter chain of a single property. If multiple filters are applied and a transforming filter is among them you have to make sure the property types are compatible. If you use a custom filter after the dateTime filter for example the custom filter has to accept a DateTime value. Filters used before a transforming filter must accept the base type of the property the filter is applied to defined in the schema. If the transformation of a property fails (the transforming filter throws an exception), subsequent filters won't be executed as their execution would add another error due to incompatible types which is irrelevant for the currently provided value.
94+
Only one transforming filter per property is allowed. The filter may be positioned anywhere in the filter chain of a single property. If multiple filters are applied and a transforming filter is among them you have to make sure the property types are compatible. If you use a custom filter after the dateTime filter for example the custom filter has to accept a DateTime value. Filters used before a transforming filter must accept the base type of the property the filter is applied to defined in the schema. If the transformation of a property fails (the transforming filter throws an exception), subsequent filters won't be executed as their execution would add another error due to incompatible types which is irrelevant for the currently provided value.
9595

9696
If you write a custom transforming filter you must define the return type of your filter function as the implementation uses Reflection methods to determine to which type a value is transformed by a filter.
9797

src/SchemaProcessor/PostProcessor/EnumFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class EnumFilter implements TransformingFilterInterface
1111
{
1212
public function getAcceptedTypes(): array
1313
{
14-
return ['string', 'null'];
14+
return ['string', 'integer', 'null'];
1515
}
1616

1717
public function getToken(): string

src/SchemaProcessor/PostProcessor/EnumPostProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private function renderEnum(
210210
'cases' => $cases,
211211
'backedType' => match ($this->getArrayTypes($values)) {
212212
['string'] => 'string',
213-
['int'] => 'int',
213+
['integer'] => 'int',
214214
default => null,
215215
},
216216
]

src/SchemaProcessor/PostProcessor/Templates/Enum.phptpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum {{ name }}{% if backedType %}: {{ backedType }}{% endif %} {
2222
}
2323
}
2424

25-
public function to(): mixed
25+
public function value(): mixed
2626
{
2727
switch ($this) {
2828
{% foreach cases as case, value %}

tests/PostProcessor/EnumPostProcessorTest.php

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,31 @@
55
namespace PHPModelGenerator\Tests\PostProcessor;
66

77
use BackedEnum;
8+
use Exception;
89
use PHPModelGenerator\Exception\Generic\EnumException;
910
use PHPModelGenerator\Exception\SchemaException;
1011
use PHPModelGenerator\Model\GeneratorConfiguration;
1112
use PHPModelGenerator\ModelGenerator;
1213
use PHPModelGenerator\SchemaProcessor\PostProcessor\EnumPostProcessor;
1314
use PHPModelGenerator\Tests\AbstractPHPModelGeneratorTest;
14-
use ReflectionClass;
1515
use ReflectionEnum;
1616

1717
class EnumPostProcessorTest extends AbstractPHPModelGeneratorTest
1818
{
19-
public function setUp(): void
19+
/**
20+
* @requires PHP < 8.1
21+
*/
22+
public function testEnumPostProcessorThrowsAnExceptionPriorToPhp81(): void
2023
{
21-
if (PHP_VERSION_ID < 80100) {
22-
$this->markTestSkipped('Enumerations are only allowed since PHP 8.1');
23-
}
24+
$this->expectException(Exception::class);
25+
$this->expectExceptionMessage('Enumerations are only allowed since PHP 8.1');
2426

25-
parent::setUp();
27+
new EnumPostProcessor('', '');
2628
}
2729

30+
/**
31+
* @requires PHP >= 8.1
32+
*/
2833
public function testStringOnlyEnum(): void
2934
{
3035
$this->addPostProcessor();
@@ -50,6 +55,8 @@ public function testStringOnlyEnum(): void
5055
$returnType = $this->getReturnType($object, 'getProperty');
5156
$this->assertTrue($returnType->allowsNull());
5257
$enum = $returnType->getName();
58+
$this->assertTrue(enum_exists($enum));
59+
5360
$reflectionEnum = new ReflectionEnum($enum);
5461
$enumName = $reflectionEnum->getShortName();
5562

@@ -83,6 +90,9 @@ public function testStringOnlyEnum(): void
8390
$object->setProperty('Meier');
8491
}
8592

93+
/**
94+
* @requires PHP >= 8.1
95+
*/
8696
public function testInvalidStringOnlyEnumValue(): void
8797
{
8898
$this->addPostProcessor();
@@ -95,6 +105,9 @@ public function testInvalidStringOnlyEnumValue(): void
95105
new $className(['property' => 'Meier']);
96106
}
97107

108+
/**
109+
* @requires PHP >= 8.1
110+
*/
98111
public function testMappedStringOnlyEnum(): void
99112
{
100113
$this->addPostProcessor();
@@ -141,6 +154,7 @@ public function testMappedStringOnlyEnum(): void
141154

142155
/**
143156
* @dataProvider unmappedEnumThrowsAnExceptionDataProvider
157+
* @requires PHP >= 8.1
144158
*/
145159
public function testUnmappedEnumThrowsAnException(string $enumValues): void
146160
{
@@ -163,6 +177,7 @@ public function unmappedEnumThrowsAnExceptionDataProvider(): array
163177

164178
/**
165179
* @dataProvider invalidEnumMapThrowsAnExceptionDataProvider
180+
* @requires PHP >= 8.1
166181
*/
167182
public function testInvalidEnumMapThrowsAnException(string $enumValues, string $enumMap): void
168183
{
@@ -188,6 +203,72 @@ public function invalidEnumMapThrowsAnExceptionDataProvider(): array
188203
];
189204
}
190205

206+
/**
207+
* @requires PHP >= 8.1
208+
*/
209+
public function testIntOnlyEnum(): void
210+
{
211+
$this->addPostProcessor();
212+
213+
$className = $this->generateClassFromFileTemplate(
214+
'EnumPropertyMapped.json',
215+
['[10, 100]', '{"a": 10, "b": 100}'],
216+
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false),
217+
false
218+
);
219+
220+
$this->includeGeneratedEnums(1);
221+
222+
$object = new $className(['property' => 10]);
223+
$this->assertSame(10, $object->getProperty()->value);
224+
225+
$object->setProperty(100);
226+
$this->assertSame(100, $object->getProperty()->value);
227+
228+
$object->setProperty(null);
229+
$this->assertNull($object->getProperty());
230+
231+
$returnType = $this->getReturnType($object, 'getProperty');
232+
$this->assertTrue($returnType->allowsNull());
233+
$enum = $returnType->getName();
234+
235+
$this->assertTrue(enum_exists($enum));
236+
$reflectionEnum = new ReflectionEnum($enum);
237+
$enumName = $reflectionEnum->getShortName();
238+
239+
$this->assertEqualsCanonicalizing(
240+
[$enumName, 'null'],
241+
explode('|', $this->getReturnTypeAnnotation($object, 'getProperty'))
242+
);
243+
244+
$this->assertSame('int', $reflectionEnum->getBackingType()->getName());
245+
246+
$this->assertEqualsCanonicalizing(
247+
['A', 'B'],
248+
array_map(function (BackedEnum $value): string { return $value->name; }, $enum::cases())
249+
);
250+
$this->assertEqualsCanonicalizing(
251+
[10, 100],
252+
array_map(function (BackedEnum $value): int { return $value->value; }, $enum::cases())
253+
);
254+
255+
$object->setProperty($enum::A);
256+
$this->assertSame(10, $object->getProperty()->value);
257+
258+
$this->assertNull($this->getParameterType($object, 'setProperty'));
259+
$this->assertEqualsCanonicalizing(
260+
[$enumName, 'int', 'null'],
261+
explode('|', $this->getParameterTypeAnnotation($object, 'setProperty'))
262+
);
263+
264+
$this->expectException(EnumException::class);
265+
$this->expectExceptionMessage('Invalid value for property declined by enum constraint');
266+
$object->setProperty(1);
267+
}
268+
269+
/**
270+
* @requires PHP >= 8.1
271+
*/
191272
public function testEnumPropertyWithTransformingFilterThrowsAnException(): void
192273
{
193274
$this->expectException(SchemaException::class);

0 commit comments

Comments
 (0)