Skip to content

Commit eaf9c98

Browse files
author
Enno Woortmann
committed
Merge remote-tracking branch 'origin/enumPostProcessor' into enumPostProcessor
2 parents 37db123 + 3cc76f8 commit eaf9c98

25 files changed

+340
-143
lines changed

phpunit.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
convertErrorsToExceptions="true"
77
convertWarningsToExceptions="true"
88
convertNoticesToExceptions="true"
9+
convertDeprecationsToExceptions="true"
910
processIsolation="false"
1011
stopOnFailure="false"
1112
bootstrap="tests/bootstrap.php"

src/Model/Property/Property.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,15 @@ public function getType(bool $outputType = false): ?PropertyType
8989
/**
9090
* @inheritdoc
9191
*/
92-
public function setType(PropertyType $type = null, PropertyType $outputType = null): PropertyInterface
93-
{
92+
public function setType(
93+
PropertyType $type = null,
94+
PropertyType $outputType = null,
95+
$reset = false
96+
): PropertyInterface {
97+
if ($reset) {
98+
$this->typeHintDecorators = [];
99+
}
100+
94101
$this->type = $type;
95102
$this->outputType = $outputType;
96103

src/Model/Property/PropertyInterface.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,15 @@ public function getType(bool $outputType = false): ?PropertyType;
4343
* @param PropertyType|null $type
4444
* @param PropertyType|null $outputType By default the output type will be equal to the base type but due to applied
4545
* filters the output type may change
46+
* @param bool $reset set to true for a full type reset (including type hint decorators like array, ...)
4647
*
4748
* @return PropertyInterface
4849
*/
49-
public function setType(PropertyType $type = null, PropertyType $outputType = null): PropertyInterface;
50+
public function setType(
51+
PropertyType $type = null,
52+
PropertyType $outputType = null,
53+
bool $reset = false
54+
): PropertyInterface;
5055

5156
/**
5257
* @param bool $outputType If set to true the output type hint will be returned (may differ from the base type)

src/Model/Property/PropertyProxy.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,11 @@ public function getType(bool $outputType = false): ?PropertyType
6969
/**
7070
* @inheritdoc
7171
*/
72-
public function setType(PropertyType $type = null, PropertyType $outputType = null): PropertyInterface
73-
{
72+
public function setType(
73+
PropertyType $type = null,
74+
PropertyType $outputType = null,
75+
bool $reset = false
76+
): PropertyInterface {
7477
return $this->getProperty()->setType($type, $outputType);
7578
}
7679

src/Model/Validator/PropertyTemplateValidator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ public function setScope(Schema $schema): void
5656
if (isset($this->templateValues['schema'])) {
5757
$this->templateValues['schema'] = $schema;
5858
}
59+
60+
$this->templateValues['isBaseValidator'] = in_array($this, $schema->getBaseValidators());
5961
}
6062

6163
/**

src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,14 @@
55
namespace PHPModelGenerator\PropertyProcessor\ComposedValue;
66

77
use PHPModelGenerator\Exception\SchemaException;
8-
use PHPModelGenerator\Model\MethodInterface;
98
use PHPModelGenerator\Model\Property\CompositionPropertyDecorator;
10-
use PHPModelGenerator\Model\Property\Property;
119
use PHPModelGenerator\Model\Property\PropertyInterface;
1210
use PHPModelGenerator\Model\Property\PropertyType;
1311
use PHPModelGenerator\Model\Schema;
1412
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
1513
use PHPModelGenerator\Model\Validator;
1614
use PHPModelGenerator\Model\Validator\ComposedPropertyValidator;
1715
use PHPModelGenerator\Model\Validator\RequiredPropertyValidator;
18-
use PHPModelGenerator\PropertyProcessor\Decorator\Property\ObjectInstantiationDecorator;
19-
use PHPModelGenerator\PropertyProcessor\Decorator\SchemaNamespaceTransferDecorator;
2016
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\ClearTypeHintDecorator;
2117
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\CompositionTypeHintDecorator;
2218
use PHPModelGenerator\PropertyProcessor\Property\AbstractValueProcessor;

src/SchemaProcessor/PostProcessor/EnumPostProcessor.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
use PHPModelGenerator\Model\Validator\EnumValidator;
1717
use PHPModelGenerator\Model\Validator\FilterValidator;
1818
use PHPModelGenerator\ModelGenerator;
19+
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\ClearTypeHintDecorator;
1920
use PHPModelGenerator\PropertyProcessor\Filter\FilterProcessor;
2021

22+
/**
23+
* Generates a PHP enum for enums from JSON schemas which are automatically mapped for properties holding the enum
24+
*/
2125
class EnumPostProcessor extends PostProcessor
2226
{
2327
private $generatedEnums = [];
@@ -31,8 +35,6 @@ class EnumPostProcessor extends PostProcessor
3135
/** @var bool */
3236
private $skipNonMappedEnums;
3337

34-
private $hasAddedFilter = false;
35-
3638
/**
3739
* @param string $targetDirectory The directory where to put the generated PHP enums
3840
* @param string $namespace The namespace for the generated enums
@@ -60,10 +62,7 @@ public function __construct(
6062

6163
public function process(Schema $schema, GeneratorConfiguration $generatorConfiguration): void
6264
{
63-
if (!$this->hasAddedFilter) {
64-
$generatorConfiguration->addFilter(new EnumFilter());
65-
$this->hasAddedFilter = true;
66-
}
65+
$generatorConfiguration->addFilter(new EnumFilter());
6766

6867
foreach ($schema->getProperties() as $property) {
6968
$json = $property->getJsonSchema()->getJson();
@@ -94,13 +93,13 @@ public function process(Schema $schema, GeneratorConfiguration $generatorConfigu
9493

9594
(new FilterProcessor())->process(
9695
$property,
97-
['filter' => 'php_model_generator_enum', 'fqcn' => $fqcn],
96+
['filter' => (new EnumFilter())->getToken(), 'fqcn' => $fqcn],
9897
$generatorConfiguration,
9998
$schema
10099
);
101100

102101
$schema->addUsedClass($fqcn);
103-
$property->setType($inputType, new PropertyType($name, !$property->isRequired()));
102+
$property->setType($inputType, new PropertyType($name, !$property->isRequired()), true);
104103

105104
if ($property->getDefaultValue() && in_array($property->getJsonSchema()->getJson()['default'], $values)) {
106105
$property->setDefaultValue("$name::{$property->getJsonSchema()->getJson()['default']}", true);
@@ -135,7 +134,6 @@ private function checkForExistingTransformingFilter(PropertyInterface $property)
135134

136135
public function postProcess(): void
137136
{
138-
$this->hasAddedFilter = false;
139137
$this->generatedEnums = [];
140138

141139
parent::postProcess();
@@ -155,6 +153,8 @@ private function validateEnum(PropertyInterface $property): bool
155153

156154
$types = $this->getArrayTypes($json['enum']);
157155

156+
// the enum must contain either only string or int values to be represented by a backed enum or provide a value
157+
// map to resolve the values
158158
if ($types !== ['string'] && !isset($json['map'])) {
159159
if ($this->skipNonMappedEnums) {
160160
return false;
@@ -196,7 +196,7 @@ private function renderEnum(
196196
$cases = [];
197197

198198
foreach ($values as $value) {
199-
$cases[$map ? array_search($value, $map) : $value] = var_export($value, true);
199+
$cases[ucfirst($map ? array_search($value, $map) : $value)] = var_export($value, true);
200200
}
201201

202202
file_put_contents(
@@ -206,8 +206,12 @@ private function renderEnum(
206206
[
207207
'namespace' => $this->namespace,
208208
'name' => $name,
209-
'backedType' => $this->getArrayTypes($values) === ['int'] ? 'int' : 'string',
210209
'cases' => $cases,
210+
'backedType' => match ($this->getArrayTypes($values)) {
211+
['string'] => 'string',
212+
['int'] => 'int',
213+
default => null,
214+
},
211215
]
212216
)
213217
);

src/SchemaProcessor/PostProcessor/Templates/Enum.phptpl

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

55
namespace {{ namespace }};
66

7-
enum {{ name }}: {{ backedType }} {
7+
enum {{ name }}{% if backedType %}: {{ backedType }}{% endif %} {
88
{% foreach cases as case, value %}
9-
case {{ case }} = {{ value }};
9+
case {{ case }}{% if backedType %} = {{ value }}{% endif %};
1010
{% endforeach %}
11+
12+
{% if not backedType %}
13+
public static function from(mixed $value): self
14+
{
15+
switch ($value) {
16+
{% foreach cases as case, value %}
17+
case {{ value }}: return self::{{ case }};
18+
{% endforeach %}
19+
default: throw new ValueError(
20+
sprintf('Invalid enum value %s for enum %s', var_export($value, true), self::class)
21+
);
22+
}
23+
}
24+
25+
public function to(): mixed
26+
{
27+
switch ($this) {
28+
{% foreach cases as case, value %}
29+
case self::{{ case }}: return {{ value }};
30+
{% endforeach %}
31+
}
32+
}
33+
{% endif %}
1134
}

src/Templates/Validator/ComposedItem.phptpl

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
$proposedValue = null;
1515
$modifiedValues = [];
1616

17-
{% if not generatorConfiguration.isImmutable() %}
17+
{% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %}
1818
$originalPropertyValidationState = $this->_propertyValidationState ?? [];
1919
{% endif %}
2020

@@ -24,7 +24,7 @@
2424

2525
{% foreach compositionProperties as compositionProperty %}
2626
try {
27-
{% if not generatorConfiguration.isImmutable() %}
27+
{% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %}
2828
// check if the state of the validator is already known.
2929
// If none of the properties affected by the validator are changed the validator must not be re-evaluated
3030
if (isset($validatorIndex) &&
@@ -71,7 +71,7 @@
7171
{% if generatorConfiguration.collectErrors() %}
7272
$compositionErrorCollection[] = $this->_errorRegistry;
7373

74-
{% if not generatorConfiguration.isImmutable() %}
74+
{% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %}
7575
if (isset($validatorIndex)) {
7676
$this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = $this->_errorRegistry;
7777
}
@@ -91,7 +91,7 @@
9191
if (is_object($value)) {
9292
$modifiedValues = array_merge($modifiedValues, $this->{{ modifiedValuesMethod }}($originalModelData, $value));
9393
}
94-
{% if not generatorConfiguration.isImmutable() %}
94+
{% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %}
9595
{% if not generatorConfiguration.collectErrors() %}
9696
if (isset($validatorIndex)) {
9797
$this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = true;
@@ -100,10 +100,12 @@
100100
}
101101
{% endif %}
102102
} catch (\Exception $e) {
103-
{% if not generatorConfiguration.collectErrors() %}
104-
if (isset($validatorIndex)) {
105-
$this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = false;
106-
}
103+
{% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %}
104+
{% if not generatorConfiguration.collectErrors() %}
105+
if (isset($validatorIndex)) {
106+
$this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = false;
107+
}
108+
{% endif %}
107109
{% endif %}
108110

109111
{% foreach compositionProperty.getAffectedObjectProperties() as affectedObjectProperty %}
@@ -137,7 +139,7 @@
137139

138140
$result = !({{ composedValueValidation }});
139141

140-
{% if not generatorConfiguration.isImmutable() %}
142+
{% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %}
141143
if ($result) {
142144
$this->_propertyValidationState = $originalPropertyValidationState;
143145
}

src/Templates/Validator/Filter.phptpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// make sure exceptions from the filter are caught and added to the error handling
66
try {
77
$value = \{{ filterClass }}::{{ filterMethod }}($value, {{ filterOptions }});
8-
} catch (\Exception $filterException) {
8+
} catch (\Throwable $filterException) {
99
{% if isTransformingFilter %}
1010
$transformationFailed = true;
1111
{% endif %}

0 commit comments

Comments
 (0)