Skip to content

Commit dbac05e

Browse files
committed
serialization, injection of wrong enums, adopt changes for InvalidTypeException
1 parent 2a389a7 commit dbac05e

16 files changed

+99
-21
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
],
1313
"require": {
1414
"symfony/polyfill-php81": "^1.28",
15-
"wol-soft/php-json-schema-model-generator-production": "dev-enumPostProcessor",
15+
"wol-soft/php-json-schema-model-generator-production": "^0.19.0",
1616
"wol-soft/php-micro-template": "^1.9.0",
1717

1818
"php": ">=7.2",

src/ModelGenerator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ public function __construct(GeneratorConfiguration $generatorConfiguration = nul
5050
->addPostProcessor(new AdditionalPropertiesPostProcessor())
5151
->addPostProcessor(new PatternPropertiesPostProcessor())
5252
->addPostProcessor(new ExtendObjectPropertiesMatchingPatternPropertiesPostProcessor());
53-
54-
if ($this->generatorConfiguration->hasSerializationEnabled()) {
55-
$this->addPostProcessor(new SerializationPostProcessor());
56-
}
5753
}
5854

5955
/**
@@ -113,6 +109,10 @@ public function generateModels(SchemaProviderInterface $schemaProvider, string $
113109
throw new FileSystemException("Destination directory '$destination' doesn't exist or is not empty");
114110
}
115111

112+
if ($this->generatorConfiguration->hasSerializationEnabled()) {
113+
$this->addPostProcessor(new SerializationPostProcessor());
114+
}
115+
116116
$renderQueue = new RenderQueue();
117117
$schemaProcessor = new SchemaProcessor(
118118
$schemaProvider->getBaseDirectory(),

src/SchemaProcessor/PostProcessor/EnumPostProcessor.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Exception;
88
use PHPMicroTemplate\Render;
9+
use PHPModelGenerator\Exception\Generic\InvalidTypeException;
910
use PHPModelGenerator\Exception\SchemaException;
1011
use PHPModelGenerator\Filter\TransformingFilterInterface;
1112
use PHPModelGenerator\Model\GeneratorConfiguration;
@@ -16,6 +17,7 @@
1617
use PHPModelGenerator\Model\Validator;
1718
use PHPModelGenerator\Model\Validator\EnumValidator;
1819
use PHPModelGenerator\Model\Validator\FilterValidator;
20+
use PHPModelGenerator\Model\Validator\PropertyValidator;
1921
use PHPModelGenerator\ModelGenerator;
2022
use PHPModelGenerator\PropertyProcessor\Filter\FilterProcessor;
2123
use PHPModelGenerator\Utils\ArrayHash;
@@ -124,6 +126,24 @@ public function process(Schema $schema, GeneratorConfiguration $generatorConfigu
124126
$property->filterValidators(static function (Validator $validator): bool {
125127
return !is_a($validator->getValidator(), EnumValidator::class);
126128
});
129+
130+
// if an enum value is provided the transforming filter will add a value pass through. As the filter doesn't
131+
// know the exact enum type the pass through allows every UnitEnum instance. Consequently add a validator to
132+
// avoid wrong enums by validating against the generated enum
133+
$property->addValidator(
134+
new class ($property, $enumName) extends PropertyValidator {
135+
public function __construct(PropertyInterface $property, string $enumName)
136+
{
137+
parent::__construct(
138+
$property,
139+
sprintf('$value instanceof UnitEnum && !($value instanceof %s)', $enumName),
140+
InvalidTypeException::class,
141+
[$enumName]
142+
);
143+
}
144+
},
145+
0
146+
);
127147
}
128148
}
129149

tests/Basic/AdditionalPropertiesTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ public function invalidTypedAdditionalPropertiesDataProvider(): array
203203
],
204204
'invalid type for additional property (object)' => [
205205
['additional1' => new stdClass(), 'additional2' => 'Hello'],
206-
sprintf($exception, 'Invalid type for additional property. Requires string, got object')
206+
sprintf($exception, 'Invalid type for additional property. Requires string, got stdClass')
207207
],
208208
'empty short string' => [
209209
['additional1' => '', 'additional2' => 'Hello'],

tests/Basic/PatternPropertiesTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public function testTypedPatternPropertyWithInvalidInputThrowsAnException(
3333
): void {
3434
$this->expectValidationError(
3535
$configuration,
36-
'Invalid type for pattern property. Requires string, got ' . gettype($propertyValue)
36+
'Invalid type for pattern property. Requires string, got ' .
37+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
3738
);
3839

3940
$className = $this->generateClassFromFile('TypedPatternProperty.json', $configuration);

tests/Objects/ArrayPropertyTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ public function testInvalidPropertyTypeThrowsAnException(
234234
): void {
235235
$this->expectValidationError(
236236
$configuration,
237-
'Invalid type for property. Requires array, got ' . gettype($propertyValue)
237+
'Invalid type for property. Requires array, got ' .
238+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
238239
);
239240

240241
$className = $this->generateClassFromFile('ArrayProperty.json', $configuration);

tests/Objects/BooleanPropertyTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ public function validInputProvider(): array
6969
public function testInvalidPropertyTypeThrowsAnException($propertyValue): void
7070
{
7171
$this->expectException(ValidationException::class);
72-
$this->expectExceptionMessage('Invalid type for property. Requires bool, got ' . gettype($propertyValue));
72+
$this->expectExceptionMessage(
73+
'Invalid type for property. Requires bool, got ' .
74+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
75+
);
7376

7477
$className = $this->generateClassFromFile('BooleanProperty.json');
7578

tests/Objects/EnumPropertyTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ public function invalidEnumEntriesDataProvider(): array
119119
public function testInvalidItemTypeThrowsAnException($propertyValue): void
120120
{
121121
$this->expectException(ValidationException::class);
122-
$this->expectExceptionMessage('Invalid type for property. Requires string, got ' . gettype($propertyValue));
122+
$this->expectExceptionMessage(
123+
'Invalid type for property. Requires string, got ' .
124+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
125+
);
123126

124127
$className = $this->generateEnumClass('string', static::ENUM_STRING);
125128

tests/Objects/IntegerPropertyTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ public function validInputProvider(): array
6969
public function testInvalidPropertyTypeThrowsAnException($propertyValue): void
7070
{
7171
$this->expectException(ValidationException::class);
72-
$this->expectExceptionMessage('Invalid type for property. Requires int, got ' . gettype($propertyValue));
72+
$this->expectExceptionMessage(
73+
'Invalid type for property. Requires int, got ' .
74+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
75+
);
7376

7477
$className = $this->generateClassFromFile('IntegerProperty.json');
7578

tests/Objects/MultiTypePropertyTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public function invalidValueDataProvider(): array
129129
{
130130
return [
131131
'Bool' => [true, 'Invalid type for property. Requires [float, string, array], got boolean'],
132-
'Object' => [new stdClass(), 'Invalid type for property. Requires [float, string, array], got object'],
132+
'Object' => [new stdClass(), 'Invalid type for property. Requires [float, string, array], got stdClass'],
133133
'Invalid int' => [9, 'Value for property must not be smaller than 10'],
134134
'zero' => [0, 'Value for property must not be smaller than 10'],
135135
'Invalid float' => [9.9, 'Value for property must not be smaller than 10'],

tests/Objects/NullPropertyTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ public function testProvidedOptionalNullPropertyIsValid(): void
5656
public function testInvalidPropertyTypeThrowsAnException($propertyValue): void
5757
{
5858
$this->expectException(ValidationException::class);
59-
$this->expectExceptionMessage('Invalid type for property. Requires null, got ' . gettype($propertyValue));
59+
$this->expectExceptionMessage(
60+
'Invalid type for property. Requires null, got ' .
61+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
62+
);
6063

6164
$className = $this->generateClassFromFile('NullProperty.json');
6265

tests/Objects/NumberPropertyTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ public function validInputProvider(): array
8585
public function testInvalidPropertyTypeThrowsAnException($propertyValue): void
8686
{
8787
$this->expectException(ValidationException::class);
88-
$this->expectExceptionMessage('Invalid type for property. Requires float, got ' . gettype($propertyValue));
88+
$this->expectExceptionMessage(
89+
'Invalid type for property. Requires float, got ' .
90+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
91+
);
8992

9093
$className = $this->generateClassFromFile('NumberProperty.json');
9194

tests/Objects/StringPropertyTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ public function testInvalidPropertyTypeThrowsAnException(
8585
): void {
8686
$this->expectValidationError(
8787
$configuration,
88-
'Invalid type for property. Requires string, got ' . gettype($propertyValue)
88+
'Invalid type for property. Requires string, got ' .
89+
(is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue))
8990
);
9091

9192
$className = $this->generateClassFromFile('StringProperty.json', $configuration);

tests/Objects/TupleArrayPropertyTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public function invalidAdditionalItemsDataProvider(): array
285285
],
286286
'invalid type for additional item (object)' => [
287287
[3, 'Avenue', new stdClass()],
288-
sprintf($exception, 'Invalid type for additional item. Requires string, got object')
288+
sprintf($exception, 'Invalid type for additional item. Requires string, got stdClass')
289289
],
290290
'invalid type for additional item (array)' => [
291291
[3, 'Avenue', [1, 2]],

tests/PostProcessor/EnumPostProcessorTest.php

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use BackedEnum;
88
use Exception;
99
use PHPModelGenerator\Exception\Generic\EnumException;
10+
use PHPModelGenerator\Exception\Generic\InvalidTypeException;
1011
use PHPModelGenerator\Exception\Object\RequiredValueException;
1112
use PHPModelGenerator\Exception\SchemaException;
1213
use PHPModelGenerator\Model\GeneratorConfiguration;
@@ -39,7 +40,10 @@ public function testStringOnlyEnum(): void
3940
$className = $this->generateClassFromFileTemplate(
4041
'EnumProperty.json',
4142
['["hans", "dieter"]'],
42-
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false),
43+
(new GeneratorConfiguration())
44+
->setImmutable(false)
45+
->setCollectErrors(false)
46+
->setSerialization(true),
4347
false
4448
);
4549

@@ -48,6 +52,7 @@ public function testStringOnlyEnum(): void
4852
$object = new $className(['property' => 'hans', 'stringProperty' => 'abc']);
4953
$this->assertSame('hans', $object->getProperty()->value);
5054
$this->assertSame('abc', $object->getStringProperty());
55+
$this->assertSame(['property' => 'hans', 'stringProperty' => 'abc'], $object->toArray());
5156

5257
$object->setProperty('dieter');
5358
$this->assertSame('dieter', $object->getProperty()->value);
@@ -96,7 +101,7 @@ public function testStringOnlyEnum(): void
96101
/**
97102
* @requires PHP >= 8.1
98103
*/
99-
public function testInvalidStringOnlyEnumValue(): void
104+
public function testInvalidStringOnlyEnumValueThrowsAnException(): void
100105
{
101106
$this->addPostProcessor();
102107
$className = $this->generateClassFromFileTemplate('EnumProperty.json', ['["Hans", "Dieter"]'], null, false);
@@ -108,6 +113,20 @@ public function testInvalidStringOnlyEnumValue(): void
108113
new $className(['property' => 'Meier']);
109114
}
110115

116+
public function testInvalidEnumThrowsAnException(): void
117+
{
118+
$this->addPostProcessor();
119+
120+
$className = $this->generateClassFromFileTemplate('EnumProperty.json', ['["Hans", "Dieter"]'], null, false);
121+
122+
$this->expectException(InvalidTypeException::class);
123+
$this->expectExceptionMessageMatches(
124+
'/Invalid type for property\. Requires EnumPostProcessorTest_.*Property, got PHPModelGenerator\\\\Tests\\\\PostProcessor\\\\IntEnum/'
125+
);
126+
127+
new $className(['property' => IntEnum::A]);
128+
}
129+
111130
/**
112131
* @requires PHP >= 8.1
113132
*/
@@ -118,7 +137,10 @@ public function testMappedStringOnlyEnum(): void
118137
$className = $this->generateClassFromFileTemplate(
119138
'EnumPropertyMapped.json',
120139
['["Hans", "Dieter"]', '{"Ceo": "Hans", "Cto": "Dieter"}'],
121-
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false),
140+
(new GeneratorConfiguration())
141+
->setImmutable(false)
142+
->setCollectErrors(false)
143+
->setSerialization(true),
122144
false
123145
);
124146

@@ -127,6 +149,7 @@ public function testMappedStringOnlyEnum(): void
127149
$object = new $className(['property' => 'Hans']);
128150
$this->assertSame('Hans', $object->getProperty()->value);
129151
$this->assertSame('Ceo', $object->getProperty()->name);
152+
$this->assertSame(['property' => 'Hans'], $object->toArray());
130153

131154
$object->setProperty('Dieter');
132155
$this->assertSame('Dieter', $object->getProperty()->value);
@@ -238,14 +261,18 @@ public function testIntOnlyEnum(): void
238261
$className = $this->generateClassFromFileTemplate(
239262
'EnumPropertyMapped.json',
240263
['[10, 100]', '{"a": 10, "b": 100}'],
241-
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false),
264+
(new GeneratorConfiguration())
265+
->setImmutable(false)
266+
->setCollectErrors(false)
267+
->setSerialization(true),
242268
false
243269
);
244270

245271
$this->includeGeneratedEnums(1);
246272

247273
$object = new $className(['property' => 10]);
248274
$this->assertSame(10, $object->getProperty()->value);
275+
$this->assertSame(['property' => 10], $object->toArray());
249276

250277
$object->setProperty(100);
251278
$this->assertSame(100, $object->getProperty()->value);
@@ -301,20 +328,23 @@ public function testMixedEnum(): void
301328
$className = $this->generateClassFromFileTemplate(
302329
'EnumPropertyMapped.json',
303330
['["Hans", 100, true]', '{"a": "Hans", "b": 100, "c": true}'],
304-
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false),
331+
(new GeneratorConfiguration())->setImmutable(false)->setCollectErrors(false)->setSerialization(true),
305332
false
306333
);
307334

308335
$this->includeGeneratedEnums(1);
309336

310337
$object = new $className(['property' => 'Hans']);
311338
$this->assertSame('Hans', $object->getProperty()->value());
339+
$this->assertSame(['property' => 'Hans'], $object->toArray());
312340

313341
$object->setProperty(100);
314342
$this->assertSame(100, $object->getProperty()->value());
343+
$this->assertSame(['property' => 100], $object->toArray());
315344

316345
$object->setProperty(null);
317346
$this->assertNull($object->getProperty());
347+
$this->assertSame(['property' => null], $object->toArray());
318348

319349
$returnType = $this->getReturnType($object, 'getProperty');
320350
$this->assertTrue($returnType->allowsNull());
@@ -575,6 +605,7 @@ public function normalizedNamesDataProvider(): array
575605
'numeric' => ['100', '_100'],
576606
];
577607
}
608+
578609
private function addPostProcessor(): void
579610
{
580611
$this->modifyModelGenerator = static function (ModelGenerator $generator): void {

tests/PostProcessor/IntEnum.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace PHPModelGenerator\Tests\PostProcessor;
4+
5+
enum IntEnum: int
6+
{
7+
case A = 1;
8+
case B = 2;
9+
}

0 commit comments

Comments
 (0)