Skip to content

Commit 5a00115

Browse files
committed
Fix type hints for multi type properties
Add null type hint via decorator instead of model render logic
1 parent 8877270 commit 5a00115

File tree

7 files changed

+57
-17
lines changed

7 files changed

+57
-17
lines changed

src/PropertyProcessor/Decorator/TypeHint/CompositionTypeHintDecorator.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use PHPModelGenerator\Model\Property\PropertyInterface;
88

99
/**
10-
* Class ArrayTypeHintDecorator
10+
* Class CompositionTypeHintDecorator
1111
*
1212
* @package PHPModelGenerator\PropertyProcessor\Decorator\Property
1313
*/
@@ -17,7 +17,7 @@ class CompositionTypeHintDecorator implements TypeHintDecoratorInterface
1717
protected $nestedProperty;
1818

1919
/**
20-
* ArrayTypeHintDecorator constructor.
20+
* CompositionTypeHintDecorator constructor.
2121
*
2222
* @param PropertyInterface $nestedProperty
2323
*/
@@ -31,11 +31,6 @@ public function __construct(PropertyInterface $nestedProperty)
3131
*/
3232
public function decorate(string $input): string
3333
{
34-
// don't add the same type hint multiple times
35-
if ($input && in_array($this->nestedProperty->getTypeHint(), explode('|', $input))) {
36-
return $input;
37-
}
38-
39-
return ($input ? "$input|" : '') . $this->nestedProperty->getTypeHint();
34+
return (new TypeHintDecorator(explode('|', $this->nestedProperty->getTypeHint())))->decorate($input);
4035
}
4136
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace PHPModelGenerator\PropertyProcessor\Decorator\TypeHint;
6+
7+
/**
8+
* Class TypeHintDecorator
9+
*
10+
* @package PHPModelGenerator\PropertyProcessor\Decorator\Property
11+
*/
12+
class TypeHintDecorator implements TypeHintDecoratorInterface
13+
{
14+
/** @var array */
15+
protected $types;
16+
17+
/**
18+
* TypeHintDecorator constructor.
19+
*
20+
* @param array $types
21+
*/
22+
public function __construct(array $types)
23+
{
24+
$this->types = $types;
25+
}
26+
27+
/**
28+
* @inheritdoc
29+
*/
30+
public function decorate(string $input): string
31+
{
32+
return implode('|', array_unique(array_filter(array_merge(explode('|', $input), $this->types))));
33+
}
34+
}

src/PropertyProcessor/Property/AbstractValueProcessor.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPModelGenerator\Model\Property\Property;
99
use PHPModelGenerator\Model\Property\PropertyInterface;
1010
use PHPModelGenerator\Model\Schema;
11+
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\TypeHintDecorator;
1112
use PHPModelGenerator\PropertyProcessor\Filter\FilterProcessor;
1213
use PHPModelGenerator\PropertyProcessor\PropertyMetaDataCollection;
1314
use PHPModelGenerator\SchemaProcessor\SchemaProcessor;
@@ -55,6 +56,10 @@ public function process(string $propertyName, array $propertyData): PropertyInte
5556
$this->schemaProcessor->getGeneratorConfiguration()->isImmutable()
5657
);
5758

59+
if ($this->schemaProcessor->getGeneratorConfiguration()->isImplicitNullAllowed() && !$property->isRequired()) {
60+
$property->addTypeHintDecorator(new TypeHintDecorator(['null']));
61+
}
62+
5863
$this->generateValidators($property, $propertyData);
5964

6065
if (isset($propertyData['filter'])) {

src/PropertyProcessor/Property/MultiTypeProcessor.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPModelGenerator\Model\Validator\MultiTypeCheckValidator;
1111
use PHPModelGenerator\Model\Validator\TypeCheckInterface;
1212
use PHPModelGenerator\PropertyProcessor\Decorator\Property\PropertyTransferDecorator;
13+
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\TypeHintDecorator;
1314
use PHPModelGenerator\PropertyProcessor\PropertyMetaDataCollection;
1415
use PHPModelGenerator\PropertyProcessor\PropertyProcessorFactory;
1516
use PHPModelGenerator\PropertyProcessor\PropertyProcessorInterface;
@@ -26,7 +27,7 @@ class MultiTypeProcessor extends AbstractValueProcessor
2627
/** @var PropertyProcessorInterface[] */
2728
protected $propertyProcessors = [];
2829
/** @var string[] */
29-
protected $allowedPropertyTypeChecks = [];
30+
protected $allowedPropertyTypes = [];
3031
/** @var string[] */
3132
protected $checks = [];
3233

@@ -81,13 +82,15 @@ public function process(string $propertyName, array $propertyData): PropertyInte
8182

8283
$this->processSubProperties($propertyName, $propertyData, $property);
8384

84-
if (empty($this->allowedPropertyTypeChecks)) {
85+
if (empty($this->allowedPropertyTypes)) {
8586
return $property;
8687
}
8788

89+
$property->addTypeHintDecorator(new TypeHintDecorator($this->allowedPropertyTypes));
90+
8891
return $property->addValidator(
8992
new MultiTypeCheckValidator(
90-
array_unique($this->allowedPropertyTypeChecks),
93+
array_unique($this->allowedPropertyTypes),
9194
$property,
9295
$this->isImplicitNullAllowed($property)
9396
),
@@ -108,7 +111,7 @@ protected function transferValidators(PropertyInterface $source, PropertyInterfa
108111

109112
// filter out type checks to create a single type check which covers all allowed types
110113
if ($validator instanceof TypeCheckInterface) {
111-
array_push($this->allowedPropertyTypeChecks, ...$validator->getTypes());
114+
array_push($this->allowedPropertyTypes, ...$validator->getTypes());
112115

113116
continue;
114117
}

src/Templates/Model.phptpl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class {{ class }} implements \PHPModelGenerator\Interfaces\JSONModelInterface
2222
{% if generatorConfiguration.hasSerializationEnabled() %}use \PHPModelGenerator\Traits\SerializableTrait;{% endif %}
2323

2424
{% foreach properties as property %}
25-
/** @var {{ property.getTypeHint(true) }}{% if viewHelper.implicitNull(property) %}|null{% endif %}{% if property.getDescription() %} {{ property.getDescription() }}{% endif %} */
25+
/**{% if property.getTypeHint(true) %} @var {{ property.getTypeHint(true) }}{% endif %}{% if property.getDescription() %} {{ property.getDescription() }}{% endif %} */
2626
protected ${{ property.getAttribute() }}{% if not viewHelper.isNull(property.getDefaultValue()) %} = {{ property.getDefaultValue() }}{% endif %};
2727
{% endforeach %}
2828
/** @var array */
@@ -99,7 +99,7 @@ class {{ class }} implements \PHPModelGenerator\Interfaces\JSONModelInterface
9999
*
100100
* {% if property.getDescription() %}{{ property.getDescription() }}{% endif %}
101101
*
102-
* @return {{ property.getTypeHint(true) }}{% if viewHelper.implicitNull(property) %}|null{% endif %}
102+
* {% if property.getTypeHint(true) %}@return {{ property.getTypeHint(true) }}{% endif %}
103103
*/
104104
public function get{{ viewHelper.ucfirst(property.getAttribute()) }}()
105105
{% if property.getType(true) %}: {% if not property.isRequired() %}?{% endif %}{{ property.getType(true) }}{% endif %}
@@ -111,14 +111,14 @@ class {{ class }} implements \PHPModelGenerator\Interfaces\JSONModelInterface
111111
/**
112112
* Set the value of {{ property.getName() }}.
113113
*
114-
* @param {{ property.getTypeHint() }}{% if viewHelper.implicitNull(property) %}|null{% endif %} ${{ property.getAttribute() }}{% if property.getDescription() %} {{ property.getDescription() }}{% endif %}
114+
* @param {{ property.getTypeHint() }} ${{ property.getAttribute() }}{% if property.getDescription() %} {{ property.getDescription() }}{% endif %}
115115
*
116116
* {% if property.getValidators() %}@throws {% if generatorConfiguration.collectErrors() %}{{ viewHelper.getSimpleClassName(generatorConfiguration.getErrorRegistryClass()) }}{% else %}ValidationException{% endif %}{% endif %}
117117
*
118118
* @return self
119119
*/
120120
public function set{{ viewHelper.ucfirst(property.getAttribute()) }}(
121-
{% if property.getType() %}{% if viewHelper.implicitNull(property) %}?{% endif %}{{ property.getType() }} {% endif %}${{ property.getAttribute() }}
121+
{% if property.getType() %}{% if viewHelper.isPropertyNullable(property) %}?{% endif %}{{ property.getType() }} {% endif %}${{ property.getAttribute() }}
122122
): self {
123123
$value = $modelData['{{ property.getName() }}'] = ${{ property.getAttribute() }};
124124

src/Utils/RenderHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public function validationError(PropertyValidatorInterface $validator): string
100100
return "throw $exceptionConstructor;";
101101
}
102102

103-
public function implicitNull(PropertyInterface $property): bool
103+
public function isPropertyNullable(PropertyInterface $property): bool
104104
{
105105
return $this->generatorConfiguration->isImplicitNullAllowed() && !$property->isRequired();
106106
}

tests/Objects/MultiTypePropertyTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public function testValidProvidedValuePassesValidation($propertyValue): void
4040

4141
$object = new $className(['property' => $propertyValue]);
4242
$this->assertEquals($propertyValue, $object->getProperty());
43+
44+
$this->assertSame('null|float|string|array', $this->getPropertyType($object, 'property'));
45+
$this->assertSame('null|float|string|array', $this->getMethodReturnType($object, 'getProperty'));
4346
}
4447

4548
public function validValueDataProvider(): array

0 commit comments

Comments
 (0)