Skip to content

Commit f4edb49

Browse files
author
Enno Woortmann
committed
Add first enum test cases
Add strict_types to test cases
1 parent 12d69d2 commit f4edb49

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+311
-42
lines changed

src/Model/GeneratorConfiguration.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,6 @@ public function addFilter(FilterInterface ...$additionalFilter): self
9595
}
9696
}
9797

98-
if (isset($this->filter[$filter->getToken()])) {
99-
throw new Exception("duplicate filter token {$filter->getToken()}");
100-
}
101-
10298
$this->filter[$filter->getToken()] = $filter;
10399
}
104100

src/PropertyProcessor/ComposedValue/AllOfProcessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
46

57
/**

src/PropertyProcessor/ComposedValue/AnyOfProcessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
46

57
/**

src/PropertyProcessor/ComposedValue/IfProcessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPModelGenerator\Exception\SchemaException;
88
use PHPModelGenerator\Model\Property\CompositionPropertyDecorator;
99
use PHPModelGenerator\Model\Property\PropertyInterface;
10+
use PHPModelGenerator\Model\Schema;
1011
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
1112
use PHPModelGenerator\Model\Validator;
1213
use PHPModelGenerator\Model\Validator\ComposedPropertyValidator;
@@ -16,6 +17,7 @@
1617
use PHPModelGenerator\PropertyProcessor\PropertyMetaDataCollection;
1718
use PHPModelGenerator\PropertyProcessor\PropertyFactory;
1819
use PHPModelGenerator\PropertyProcessor\PropertyProcessorFactory;
20+
use PHPModelGenerator\SchemaProcessor\SchemaProcessor;
1921
use PHPModelGenerator\Utils\RenderHelper;
2022

2123
/**

src/PropertyProcessor/ComposedValue/NotProcessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
46

57
use PHPModelGenerator\Model\Property\PropertyInterface;

src/PropertyProcessor/ComposedValue/OneOfProcessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
46

57
/**

src/PropertyProcessor/ComposedValueProcessorFactory.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor;
46

57
use PHPModelGenerator\Exception\SchemaException;
68
use PHPModelGenerator\Model\Schema;
9+
use PHPModelGenerator\PropertyProcessor\ComposedValue\AbstractComposedValueProcessor;
710
use PHPModelGenerator\SchemaProcessor\SchemaProcessor;
811

912
/**
@@ -39,6 +42,12 @@ public function getProcessor(
3942
): PropertyProcessorInterface {
4043
$processor = '\\PHPModelGenerator\\PropertyProcessor\\ComposedValue\\' . ucfirst($type) . 'Processor';
4144

42-
return new $processor($propertyMetaDataCollection, $schemaProcessor, $schema, $this->rootLevelComposition);
45+
$params = [$propertyMetaDataCollection, $schemaProcessor, $schema];
46+
47+
if (is_a($processor, AbstractComposedValueProcessor::class, true)) {
48+
$params[] = $this->rootLevelComposition;
49+
}
50+
51+
return new $processor(...$params);
4352
}
4453
}

src/PropertyProcessor/ProcessorFactoryInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor;
46

57
use PHPModelGenerator\Model\Schema;

src/PropertyProcessor/PropertyProcessorFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace PHPModelGenerator\PropertyProcessor;
46

57
use PHPModelGenerator\Exception\SchemaException;

src/SchemaProcessor/PostProcessor/EnumPostProcessor.php

Lines changed: 117 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PHPModelGenerator\SchemaProcessor\PostProcessor;
66

7+
use Exception;
78
use PHPMicroTemplate\Render;
89
use PHPModelGenerator\Exception\SchemaException;
910
use PHPModelGenerator\Filter\TransformingFilterInterface;
@@ -19,26 +20,42 @@
1920

2021
class EnumPostProcessor extends PostProcessor
2122
{
23+
private $generatedEnums = [];
24+
2225
/** @var string */
2326
private $namespace;
2427
/** @var Render */
2528
private $renderer;
2629
/** @var string */
2730
private $targetDirectory;
31+
/** @var bool */
32+
private $skipNonMappedEnums;
2833

2934
private $hasAddedFilter = false;
3035

31-
public function __construct(string $targetDirectory, string $namespace)
32-
{
36+
/**
37+
* @param string $targetDirectory The directory where to put the generated PHP enums
38+
* @param string $namespace The namespace for the generated enums
39+
* @param bool $skipNonMappedEnums By default, enums which not contain only strings and don't provide a mapping for
40+
* the enum will throw an exception. If set to true, those enums will be skipped
41+
*
42+
* @throws Exception
43+
*/
44+
public function __construct(
45+
string $targetDirectory,
46+
string $namespace,
47+
bool $skipNonMappedEnums = false
48+
) {
3349
if (PHP_VERSION_ID < 80100) {
34-
throw new \Exception('Enumerations are only allowed since PHP 8.1');
50+
throw new Exception('Enumerations are only allowed since PHP 8.1');
3551
}
3652

3753
(new ModelGenerator())->generateModelDirectory($targetDirectory);
3854

3955
$this->renderer = new Render(__DIR__ . DIRECTORY_SEPARATOR . 'Templates' . DIRECTORY_SEPARATOR);
4056
$this->namespace = trim($namespace, '\\');
4157
$this->targetDirectory = $targetDirectory;
58+
$this->skipNonMappedEnums = $skipNonMappedEnums;
4259
}
4360

4461
public function process(Schema $schema, GeneratorConfiguration $generatorConfiguration): void
@@ -49,42 +66,30 @@ public function process(Schema $schema, GeneratorConfiguration $generatorConfigu
4966
}
5067

5168
foreach ($schema->getProperties() as $property) {
52-
if (!isset($property->getJsonSchema()->getJson()['enum'])) {
69+
$json = $property->getJsonSchema()->getJson();
70+
71+
if (!isset($json['enum']) || !$this->validateEnum($property)) {
5372
continue;
5473
}
5574

5675
$this->checkForExistingTransformingFilter($property);
5776

58-
$values = $property->getJsonSchema()->getJson()['enum'];
77+
$values = $json['enum'];
5978
sort($values);
60-
61-
$name = $schema->getClassName() . ucfirst($property->getName());
62-
file_put_contents(
63-
$this->targetDirectory . DIRECTORY_SEPARATOR . $name . '.php',
64-
$this->renderer->renderTemplate(
65-
'Enum.phptpl',
66-
[
67-
'namespace' => $this->namespace,
68-
'name' => $name,
69-
'backedType' => 'string',
70-
'cases' => array_combine(
71-
$values,
72-
array_map(
73-
static function ($value): string {
74-
return var_export($value, true);
75-
},
76-
$values
77-
)
78-
),
79-
]
80-
)
81-
);
82-
83-
$fqcn = "$this->namespace\\$name";
84-
if ($generatorConfiguration->isOutputEnabled()) {
85-
echo "Rendered enum $fqcn\n";
79+
$hash = md5(print_r($values, true));
80+
81+
if (!isset($this->generatedEnums[$hash])) {
82+
$this->generatedEnums[$hash] = $this->renderEnum(
83+
$generatorConfiguration,
84+
$json['$id'] ?? $schema->getClassName() . ucfirst($property->getName()),
85+
$values,
86+
$json['map'] ?? null
87+
);
8688
}
8789

90+
$fqcn = $this->generatedEnums[$hash];
91+
$name = substr($fqcn, strrpos($fqcn, "\\") + 1);
92+
8893
$inputType = $property->getType();
8994

9095
(new FilterProcessor())->process(
@@ -103,7 +108,6 @@ static function ($value): string {
103108

104109
// remove the enum validator as the validation is performed by the PHP enum
105110
$property->filterValidators(static function (Validator $validator): bool {
106-
echo "filter validator: " . $validator->getValidator()::class . PHP_EOL;
107111
return !is_a($validator->getValidator(), EnumValidator::class);
108112
});
109113
}
@@ -128,7 +132,88 @@ private function checkForExistingTransformingFilter(PropertyInterface $property)
128132
public function postProcess(): void
129133
{
130134
$this->hasAddedFilter = false;
135+
$this->generatedEnums = [];
131136

132137
parent::postProcess();
133138
}
139+
140+
private function validateEnum(PropertyInterface $property): bool
141+
{
142+
$throw = fn (string $message) => throw new SchemaException(
143+
sprintf(
144+
$message,
145+
$property->getName(),
146+
$property->getJsonSchema()->getFile()
147+
)
148+
);
149+
150+
$json = $property->getJsonSchema()->getJson();
151+
152+
$types = $this->getArrayTypes($json['enum']);
153+
154+
if ($types !== ['string'] && !isset($json['map'])) {
155+
if ($this->skipNonMappedEnums) {
156+
return false;
157+
}
158+
159+
$throw('Unmapped enum %s in file %s');
160+
}
161+
162+
if (isset($json['map'])) {
163+
if (count(array_uintersect(
164+
$json['map'],
165+
$json['enum'],
166+
fn($a, $b) => $a === $b ? 0 : 1
167+
)) !== count($json['enum'])
168+
) {
169+
$throw('invalid enum map %s in file %s');
170+
}
171+
}
172+
173+
return true;
174+
}
175+
176+
private function getArrayTypes(array $array): array
177+
{
178+
return array_unique(array_map(
179+
static function ($item): string {
180+
return gettype($item);
181+
},
182+
$array
183+
));
184+
}
185+
186+
private function renderEnum(
187+
GeneratorConfiguration $generatorConfiguration,
188+
string $name,
189+
array $values,
190+
?array $map
191+
): string {
192+
$cases = [];
193+
194+
foreach ($values as $value) {
195+
$cases[$map ? array_search($value, $map) : $value] = var_export($value, true);
196+
}
197+
198+
file_put_contents(
199+
$this->targetDirectory . DIRECTORY_SEPARATOR . $name . '.php',
200+
$this->renderer->renderTemplate(
201+
'Enum.phptpl',
202+
[
203+
'namespace' => $this->namespace,
204+
'name' => $name,
205+
'backedType' => $this->getArrayTypes($values) === ['int'] ? 'int' : 'string',
206+
'cases' => $cases,
207+
]
208+
)
209+
);
210+
211+
$fqcn = "$this->namespace\\$name";
212+
213+
if ($generatorConfiguration->isOutputEnabled()) {
214+
echo "Rendered enum $fqcn\n";
215+
}
216+
217+
return $fqcn;
218+
}
134219
}

0 commit comments

Comments
 (0)