Skip to content

Commit 67a951f

Browse files
committed
Fix compositions with null values
1 parent 2cdd9a1 commit 67a951f

File tree

9 files changed

+99
-18
lines changed

9 files changed

+99
-18
lines changed

src/Model/Validator/RequiredPropertyValidator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class RequiredPropertyValidator extends PropertyValidator
2222
public function __construct(PropertyInterface $property)
2323
{
2424
parent::__construct(
25-
"!isset(\$modelData['{$property->getName()}'])",
25+
"!array_key_exists('{$property->getName()}', \$modelData)",
2626
InvalidArgumentException::class,
2727
"Missing required value for {$property->getName()}"
2828
);

src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ protected function generateValidators(PropertyInterface $property, array $proper
6363
'viewHelper' => new RenderHelper(),
6464
'availableAmount' => $availableAmount,
6565
'composedValueValidation' => $this->getComposedValueValidation($availableAmount),
66+
'onlyForDefinedValues' => $propertyData['onlyForDefinedValues'] &&
67+
$this instanceof AbstractComposedPropertiesProcessor,
6668
]
6769
),
6870
100

src/PropertyProcessor/Property/AbstractPropertyProcessor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ protected function addComposedValueValidator(PropertyInterface $property, array
115115
[
116116
'type' => $composedValueKeyword,
117117
'composition' => $propertyData[$composedValueKeyword],
118+
'onlyForDefinedValues' => !($this instanceof BaseProcessor) && !$property->isRequired(),
118119
]
119120
);
120121

src/Templates/Validator/ComposedItem.phptpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
{%if onlyForDefinedValues %}
2+
$value !== null &&
3+
{% endif %}
14
(function ($value) use (&$modelData) {
25
$succeededCompositionElements = {{ availableAmount }};
36
$originalModelData = $value;

tests/ComposedValue/ComposedOneOfTest.php

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,53 @@
1414
class ComposedOneOfTest extends AbstractPHPModelGeneratorTest
1515
{
1616
/**
17-
* @dataProvider oneOfSchemaFileDataProvider
17+
* @dataProvider propertyLevelOneOfSchemaFileDataProvider
1818
*
1919
* @param string $schema
2020
*/
21-
public function testNotProvidedOneOfTypePropertyThrowsAnException(string $schema): void
21+
public function testNotProvidedPropertyLevelOneOfIsValid(string $schema): void
2222
{
23-
$this->expectException(InvalidArgumentException::class);
24-
2523
$className = $this->generateObjectFromFile($schema);
2624

27-
new $className([]);
25+
$object = new $className([]);
26+
$this->assertNull($object->getProperty());
2827
}
2928

30-
public function oneOfSchemaFileDataProvider(): array
29+
public function propertyLevelOneOfSchemaFileDataProvider(): array
3130
{
3231
return [
3332
'OneOfType.json' => ['OneOfType.json'],
3433
'ExtendedPropertyDefinition.json' => ['ExtendedPropertyDefinition.json'],
3534
'ReferencedObjectSchema.json' => ['ReferencedObjectSchema.json'],
35+
];
36+
}
37+
38+
/**
39+
* @dataProvider objectLevelOneOfSchemaFileDataProvider
40+
*
41+
* @param string $schema
42+
*/
43+
public function testNotProvidedObjectLevelOneOfThrowsAnException(string $schema): void
44+
{
45+
$this->expectException(InvalidArgumentException::class);
46+
$this->expectExceptionMessageRegExp('/^Invalid value for (.*?) declined by composition constraint$/');
47+
48+
$className = $this->generateObjectFromFile($schema);
49+
50+
new $className([]);
51+
}
52+
53+
public function objectLevelOneOfSchemaFileDataProvider(): array
54+
{
55+
return [
3656
'ObjectLevelComposition.json' => ['ObjectLevelComposition.json'],
57+
'ObjectLevelCompositionRequired.json' => ['ObjectLevelCompositionRequired.json'],
3758
];
3859
}
3960

4061
/**
4162
* @dataProvider validPropertyTypeDataProvider
63+
* @dataProvider nullDataProvider
4264
*
4365
* @param $propertyValue
4466
*/
@@ -84,10 +106,44 @@ public function invalidPropertyTypeDataProvider(): array
84106
'float' => [0.92],
85107
'array' => [[]],
86108
'object' => [new stdClass()],
87-
'null' => [null],
88109
];
89110
}
90111

112+
113+
/**
114+
* @dataProvider validPropertyTypeDataProvider
115+
*
116+
* @param $propertyValue
117+
*/
118+
public function testValidProvidedRequiredOneOfTypePropertyIsValid($propertyValue): void
119+
{
120+
$className = $this->generateObjectFromFile('OneOfTypeRequired.json');
121+
122+
$object = new $className(['property' => $propertyValue]);
123+
$this->assertSame($propertyValue, $object->getProperty());
124+
}
125+
126+
/**
127+
* @dataProvider invalidPropertyTypeDataProvider
128+
* @dataProvider nullDataProvider
129+
*
130+
* @param $propertyValue
131+
*/
132+
public function testInvalidProvidedRequiredOneOfTypePropertyThrowsAnException($propertyValue): void
133+
{
134+
$this->expectException(InvalidArgumentException::class);
135+
$this->expectExceptionMessage('Invalid value for property declined by composition constraint');
136+
137+
$className = $this->generateObjectFromFile('OneOfTypeRequired.json');
138+
139+
new $className(['property' => $propertyValue]);
140+
}
141+
142+
public function nullDataProvider(): array
143+
{
144+
return ['null' => [null]];
145+
}
146+
91147
/**
92148
* @dataProvider validExtendedPropertyDataProvider
93149
*
@@ -99,7 +155,7 @@ public function testExtendedPropertyDefinitionWithValidValues($propertyValue): v
99155

100156
$object = new $className(['property' => $propertyValue]);
101157
// cast expected to float as an int is casted to an float internally for a number property
102-
$this->assertSame((float) $propertyValue, $object->getProperty());
158+
$this->assertSame(is_int($propertyValue) ? (float) $propertyValue : $propertyValue, $object->getProperty());
103159
}
104160

105161
public function validExtendedPropertyDataProvider(): array
@@ -108,7 +164,7 @@ public function validExtendedPropertyDataProvider(): array
108164
'int 12' => [12],
109165
'float 12.' => [12.],
110166
'int 15' => [15],
111-
// TODO 'null' => [null],
167+
'null' => [null],
112168
];
113169
}
114170

@@ -155,13 +211,14 @@ public function testMatchingObjectPropertyWithReferencedSchemaIsValid($propertyV
155211
{
156212
$className = $this->generateObjectFromFile('ReferencedObjectSchema.json');
157213

158-
$object = new $className(['person' => $propertyValue]);
159-
$this->assertSame($propertyValue, $object->getPerson());
214+
$object = new $className(['property' => $propertyValue]);
215+
$this->assertSame($propertyValue, $object->getProperty());
160216
}
161217

162218
public function objectPropertyWithReferencedSchemaDataProvider(): array
163219
{
164220
return [
221+
'null' => [null],
165222
'string matching required length' => ['Hanne'],
166223
'Matching object' => [['name' => 'Ha', 'age' => 42]],
167224
];
@@ -175,17 +232,16 @@ public function objectPropertyWithReferencedSchemaDataProvider(): array
175232
public function testNotMatchingObjectPropertyWithReferencedSchemaThrowsAnException($propertyValue): void
176233
{
177234
$this->expectException(InvalidArgumentException::class);
178-
$this->expectExceptionMessage('Invalid value for person declined by composition constraint');
235+
$this->expectExceptionMessage('Invalid value for property declined by composition constraint');
179236

180237
$className = $this->generateObjectFromFile('ReferencedObjectSchema.json');
181238

182-
new $className(['person' => $propertyValue]);
239+
new $className(['property' => $propertyValue]);
183240
}
184241

185242
public function invalidObjectPropertyWithReferencedSchemaDataProvider(): array
186243
{
187244
return [
188-
'null' => [null],
189245
'int' => [0],
190246
'float' => [0.92],
191247
'bool' => [true],

tests/Objects/EnumPropertyTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public function testNotProvidedValueForTypedEnumThrowsAnException(): void
124124
public function testNullProvidedForTypedEnumThrowsAnException(): void
125125
{
126126
$this->expectException(InvalidArgumentException::class);
127-
$this->expectExceptionMessage("Missing required value for property");
127+
$this->expectExceptionMessage("invalid type for property");
128128

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

tests/Objects/RequiredPropertyTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public function testNotProvidedRequiredPropertyThrowsAnException(): void
6363
public function testNullProvidedForRequiredPropertyThrowsAnException(): void
6464
{
6565
$this->expectException(InvalidArgumentException::class);
66-
$this->expectExceptionMessage("Missing required value for property");
66+
$this->expectExceptionMessage("invalid type for property");
6767

6868
$className = $this->generateObjectFromFile('RequiredStringProperty.json');
6969

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"property": {
5+
"oneOf": [
6+
{
7+
"type": "string"
8+
},
9+
{
10+
"type": "integer"
11+
},
12+
{
13+
"type": "boolean"
14+
}
15+
]
16+
}
17+
},
18+
"required": ["property"]
19+
}

tests/Schema/ComposedOneOfTest/ReferencedObjectSchema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
},
2121
"type": "object",
2222
"properties": {
23-
"person": {
23+
"property": {
2424
"oneOf": [
2525
{
2626
"$ref": "#/definitions/person"

0 commit comments

Comments
 (0)