Skip to content

Commit 2fbe8bc

Browse files
committed
Merge remote-tracking branch 'origin/master' into enumPostProcessor
# Conflicts: # composer.json
2 parents e60c325 + 85aa9b5 commit 2fbe8bc

File tree

11 files changed

+228
-16
lines changed

11 files changed

+228
-16
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ To avoid adding all dependencies of the php-json-schema-model-generator to your
4444

4545
Check out the [docs](https://php-json-schema-model-generator.readthedocs.io/en/latest/) for more details.
4646

47-
The base object for generating models is the *Generator*. After you have created a Generator you can use the object to generate your model classes without any further configuration:
47+
The base object for generating models is the *ModelGenerator*. After you have created a Generator you can use the object to generate your model classes without any further configuration:
4848

4949
```php
50-
(new Generator())
50+
(new ModelGenerator())
5151
->generateModels(new RecursiveDirectoryProvider(__DIR__ . '/schema'), __DIR__ . '/result');
5252
```
5353
The first parameter of the *generateModels* method must be a class implementing the *SchemaProviderInterface*. The provider fetches the JSON schema files and provides them for the generator. The following providers are available:
@@ -62,7 +62,7 @@ The second parameter must point to an existing and empty directory (you may use
6262
As an optional parameter you can set up a *GeneratorConfiguration* object (check out the docs for all available options) to configure your Generator and/or use the method *generateModelDirectory* to generate your model directory (will generate the directory if it doesn't exist; if it exists, all contained files and folders will be removed for a clean generation process):
6363

6464
```php
65-
$generator = new Generator(
65+
$generator = new ModelGenerator(
6666
(new GeneratorConfiguration())
6767
->setNamespacePrefix('MyApp\Model')
6868
->setImmutable(false)

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/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/Internal/SerializationPostProcessor.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
use PHPModelGenerator\Filter\TransformingFilterInterface;
99
use PHPModelGenerator\Interfaces\SerializationInterface;
1010
use PHPModelGenerator\Model\GeneratorConfiguration;
11+
use PHPModelGenerator\Model\Property\Property;
12+
use PHPModelGenerator\Model\Property\PropertyInterface;
13+
use PHPModelGenerator\Model\Property\PropertyType;
1114
use PHPModelGenerator\Model\Schema;
15+
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
1216
use PHPModelGenerator\Model\Validator\AdditionalPropertiesValidator;
1317
use PHPModelGenerator\Model\Validator\FilterValidator;
1418
use PHPModelGenerator\Model\Validator\PatternPropertiesValidator;
@@ -40,6 +44,7 @@ public function process(Schema $schema, GeneratorConfiguration $generatorConfigu
4044

4145
$this->addSerializeFunctionsForTransformingFilters($schema, $generatorConfiguration);
4246
$this->addSerializationHookMethod($schema, $generatorConfiguration);
47+
$this->addSkipNotProvidedPropertiesMap($schema, $generatorConfiguration);
4348

4449
$this->addPatternPropertiesSerialization($schema, $generatorConfiguration);
4550

@@ -229,4 +234,36 @@ public function getCode(): string
229234
}
230235
);
231236
}
237+
238+
private function addSkipNotProvidedPropertiesMap(
239+
Schema $schema,
240+
GeneratorConfiguration $generatorConfiguration
241+
): void {
242+
if ($generatorConfiguration->isImplicitNullAllowed()) {
243+
return;
244+
}
245+
246+
$skipNotProvidedValues = array_map(
247+
static function (PropertyInterface $property): string {
248+
return $property->getAttribute(true);
249+
},
250+
array_filter(
251+
$schema->getProperties(),
252+
static function (PropertyInterface $property): bool {
253+
return !$property->isRequired() && !$property->getDefaultValue();
254+
}
255+
)
256+
);
257+
258+
$schema->addProperty(
259+
(new Property(
260+
'skipNotProvidedPropertiesMap',
261+
new PropertyType('array'),
262+
new JsonSchema(__FILE__, []),
263+
'Values which might be skipped for serialization if not provided'
264+
))
265+
->setDefaultValue($skipNotProvidedValues)
266+
->setInternal(true)
267+
);
268+
}
232269
}

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/Utils/RenderHelper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ public function renderMethods(Schema $schema): string
197197
return $renderedMethods;
198198
}
199199

200+
public function isMutableBaseValidator(GeneratorConfiguration $generatorConfiguration, bool $isBaseValidator): bool
201+
{
202+
return !$generatorConfiguration->isImmutable() && $isBaseValidator;
203+
}
204+
200205
public static function varExportArray(array $values): string
201206
{
202207
return preg_replace('(\d+\s=>)', '', var_export($values, true));

tests/Issues/Issue/Issue76Test.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPModelGenerator\Tests\Issues\Issue;
6+
7+
use PHPModelGenerator\Model\GeneratorConfiguration;
8+
use PHPModelGenerator\Tests\Issues\AbstractIssueTest;
9+
10+
class Issue76Test extends AbstractIssueTest
11+
{
12+
public function testSerializeWithImplicitNullEnabledIncludesAllFields(): void
13+
{
14+
$className = $this->generateClassFromFile(
15+
'optionalPropertySerialization.json',
16+
(new GeneratorConfiguration())->setSerialization(true)
17+
);
18+
19+
$object = new $className(['property1' => 'Hello']);
20+
21+
$this->assertEqualsCanonicalizing(
22+
['property1' => 'Hello', 'property2' => null, 'property3' => 'Moin'],
23+
$object->toArray()
24+
);
25+
}
26+
27+
public function testSerializeSkipsNotProvidedOptionalProperties(): void
28+
{
29+
$className = $this->generateClassFromFile(
30+
'optionalPropertySerialization.json',
31+
(new GeneratorConfiguration())->setSerialization(true)->setImmutable(false),
32+
false,
33+
false
34+
);
35+
36+
$object = new $className(['property1' => 'Hello']);
37+
38+
$this->assertEqualsCanonicalizing(['property1' => 'Hello', 'property3' => 'Moin'], $object->toArray());
39+
$object->setProperty2('World');
40+
$this->assertEqualsCanonicalizing(
41+
['property1' => 'Hello', 'property2' => 'World', 'property3' => 'Moin'],
42+
$object->toArray()
43+
);
44+
}
45+
}

tests/Issues/Issue/Issue77Test.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPModelGenerator\Tests\Issues\Issue;
6+
7+
use PHPModelGenerator\Model\GeneratorConfiguration;
8+
use PHPModelGenerator\Tests\Issues\AbstractIssueTest;
9+
10+
class Issue77Test extends AbstractIssueTest
11+
{
12+
public function testCompositionValidatorOnPropertyGeneratesNoDynamicProperty(): void
13+
{
14+
$className = $this->generateClassFromFile('dynamicProperty.json', (new GeneratorConfiguration())->setImmutable(false));
15+
16+
$object = new $className(['values' => [1, 10, 1000], 'pet' => ['type' => 'dog', 'age' => 0, 'name' => 'Hans']]);
17+
18+
$this->assertSame([1, 10, 1000], $object->getValues());
19+
$this->assertSame('dog', $object->getPet()->getType());
20+
$this->assertSame(0, $object->getPet()->getAge());
21+
$this->assertSame('Hans', $object->getPet()->getName());
22+
23+
$this->expectExceptionMessage('Value for item of array values must not be smaller than 1');
24+
25+
new $className(['values' => [0]]);
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"property1": {
5+
"type": "string"
6+
},
7+
"property2": {
8+
"type": "string"
9+
},
10+
"property3": {
11+
"type": "string",
12+
"default": "Moin"
13+
}
14+
},
15+
"required": [
16+
"property1"
17+
]
18+
}

0 commit comments

Comments
 (0)