Skip to content

Commit 758bfe2

Browse files
committed
Split up additionalPropertiesPostProcessor and PatternPropertiesPostProcessor to support serialization without adding the corresponding accessor methods
1 parent 4f55cb1 commit 758bfe2

20 files changed

+495
-333
lines changed

src/Model/Validator/PatternPropertiesValidator.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ class PatternPropertiesValidator extends PropertyTemplateValidator
2929
private $pattern;
3030
/** @var string */
3131
private $key;
32-
/** @var bool */
33-
private $collectPatternProperties = false;
3432

3533
/**
3634
* PatternPropertiesValidator constructor.
@@ -70,22 +68,13 @@ public function __construct(
7068
'validationProperty' => $this->validationProperty,
7169
'generatorConfiguration' => $schemaProcessor->getGeneratorConfiguration(),
7270
'viewHelper' => new RenderHelper($schemaProcessor->getGeneratorConfiguration()),
73-
'collectPatternProperties' => &$this->collectPatternProperties,
7471
'schemaProperties' => $schema->getProperties(),
7572
],
7673
InvalidPatternPropertiesException::class,
7774
[$this->pattern, '&$invalidProperties']
7875
);
7976
}
8077

81-
/**
82-
* @param bool $collectPatternProperties
83-
*/
84-
public function setCollectPatternProperties(bool $collectPatternProperties): void
85-
{
86-
$this->collectPatternProperties = $collectPatternProperties;
87-
}
88-
8978
/**
9079
* @inheritDoc
9180
*/

src/ModelGenerator.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
use PHPModelGenerator\Exception\SchemaException;
1111
use PHPModelGenerator\Model\GeneratorConfiguration;
1212
use PHPModelGenerator\SchemaProcessor\PostProcessor\Internal\ {
13+
AdditionalPropertiesPostProcessor,
1314
CompositionValidationPostProcessor,
1415
ExtendObjectPropertiesMatchingPatternPropertiesPostProcessor,
16+
PatternPropertiesPostProcessor,
1517
SerializationPostProcessor
1618
};
1719
use PHPModelGenerator\SchemaProcessor\PostProcessor\PostProcessor;
@@ -45,6 +47,8 @@ public function __construct(GeneratorConfiguration $generatorConfiguration = nul
4547
// add internal post processors which must always be executed
4648
$this
4749
->addPostProcessor(new CompositionValidationPostProcessor())
50+
->addPostProcessor(new AdditionalPropertiesPostProcessor())
51+
->addPostProcessor(new PatternPropertiesPostProcessor())
4852
->addPostProcessor(new ExtendObjectPropertiesMatchingPatternPropertiesPostProcessor());
4953

5054
if ($this->generatorConfiguration->hasSerializationEnabled()) {

src/SchemaProcessor/PostProcessor/AdditionalPropertiesAccessorPostProcessor.php

Lines changed: 43 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,21 @@
44

55
namespace PHPModelGenerator\SchemaProcessor\PostProcessor;
66

7-
use Exception;
87
use PHPModelGenerator\Exception\Object\MinPropertiesException;
98
use PHPModelGenerator\Exception\Object\RegularPropertyAsAdditionalPropertyException;
109
use PHPModelGenerator\Exception\SchemaException;
11-
use PHPModelGenerator\Filter\TransformingFilterInterface;
1210
use PHPModelGenerator\Model\GeneratorConfiguration;
1311
use PHPModelGenerator\Model\Property\Property;
1412
use PHPModelGenerator\Model\Property\PropertyInterface;
1513
use PHPModelGenerator\Model\Property\PropertyType;
1614
use PHPModelGenerator\Model\Schema;
17-
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
18-
use PHPModelGenerator\Model\SerializedValue;
1915
use PHPModelGenerator\Model\Validator\AdditionalPropertiesValidator;
20-
use PHPModelGenerator\Model\Validator\FilterValidator;
21-
use PHPModelGenerator\Model\Validator\PropertyTemplateValidator;
2216
use PHPModelGenerator\Model\Validator\PropertyValidator;
2317
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\ArrayTypeHintDecorator;
2418
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\TypeHintDecorator;
2519
use PHPModelGenerator\SchemaProcessor\Hook\SchemaHookResolver;
20+
use PHPModelGenerator\SchemaProcessor\PostProcessor\Internal\AdditionalPropertiesPostProcessor;
21+
use PHPModelGenerator\SchemaProcessor\PostProcessor\Internal\SerializationPostProcessor;
2622
use PHPModelGenerator\Utils\RenderHelper;
2723

2824
/**
@@ -70,102 +66,28 @@ public function process(Schema $schema, GeneratorConfiguration $generatorConfigu
7066
$validationProperty = null;
7167
foreach ($schema->getBaseValidators() as $validator) {
7268
if (is_a($validator, AdditionalPropertiesValidator::class)) {
73-
$validator->setCollectAdditionalProperties(true);
7469
$validationProperty = $validator->getValidationProperty();
7570
}
7671
}
7772

78-
$this->addAdditionalPropertiesCollectionProperty($schema, $validationProperty);
79-
$this->addGetAdditionalPropertyMethod($schema, $generatorConfiguration, $validationProperty);
80-
81-
if ($generatorConfiguration->hasSerializationEnabled()) {
82-
$this->addSerializeAdditionalPropertiesMethod($schema, $generatorConfiguration, $validationProperty);
73+
// check if basic code must be added
74+
if ($this->addForModelsWithoutAdditionalPropertiesDefinition && !isset($json['additionalProperties'])) {
75+
(new AdditionalPropertiesPostProcessor())->addAdditionalPropertiesCollectionProperty($schema);
76+
}
77+
if ($generatorConfiguration->hasSerializationEnabled() &&
78+
$this->addForModelsWithoutAdditionalPropertiesDefinition &&
79+
!isset($json['additionalProperties'])
80+
) {
81+
(new SerializationPostProcessor())->addAdditionalPropertiesSerialization($schema, $generatorConfiguration);
8382
}
8483

84+
$this->addGetAdditionalPropertiesMethod($schema, $generatorConfiguration, $validationProperty);
85+
$this->addGetAdditionalPropertyMethod($schema, $generatorConfiguration, $validationProperty);
86+
8587
if (!$generatorConfiguration->isImmutable()) {
8688
$this->addSetAdditionalPropertyMethod($schema, $generatorConfiguration, $validationProperty);
8789
$this->addRemoveAdditionalPropertyMethod($schema, $generatorConfiguration);
8890
}
89-
90-
if (!isset($json['additionalProperties']) || $json['additionalProperties'] === true) {
91-
$this->addUpdateAdditionalProperties($schema);
92-
}
93-
}
94-
95-
/**
96-
* Adds an array property to the schema which holds all additional properties
97-
*
98-
* @param Schema $schema
99-
* @param PropertyInterface|null $validationProperty
100-
*
101-
* @throws SchemaException
102-
*/
103-
private function addAdditionalPropertiesCollectionProperty(
104-
Schema $schema,
105-
?PropertyInterface $validationProperty
106-
): void {
107-
$additionalPropertiesCollectionProperty = (new Property(
108-
'additionalProperties',
109-
new PropertyType('array'),
110-
new JsonSchema(__FILE__, []),
111-
'Collect all additional properties provided to the schema'
112-
))
113-
->setDefaultValue([])
114-
->setReadOnly(true);
115-
116-
if ($validationProperty) {
117-
$additionalPropertiesCollectionProperty->addTypeHintDecorator(
118-
new ArrayTypeHintDecorator($validationProperty)
119-
);
120-
}
121-
122-
$schema->addProperty($additionalPropertiesCollectionProperty);
123-
}
124-
125-
/**
126-
* Adds a custom serialization function to the schema to merge all additional properties into the serialization
127-
* result on serializations
128-
*
129-
* @param Schema $schema
130-
* @param GeneratorConfiguration $generatorConfiguration
131-
* @param PropertyInterface|null $validationProperty
132-
*/
133-
private function addSerializeAdditionalPropertiesMethod(
134-
Schema $schema,
135-
GeneratorConfiguration $generatorConfiguration,
136-
?PropertyInterface $validationProperty
137-
): void {
138-
$transformingFilterValidator = null;
139-
140-
if ($validationProperty) {
141-
foreach ($validationProperty->getValidators() as $validator) {
142-
$validator = $validator->getValidator();
143-
144-
if ($validator instanceof FilterValidator &&
145-
$validator->getFilter() instanceof TransformingFilterInterface
146-
) {
147-
$transformingFilterValidator = $validator;
148-
[$serializerClass, $serializerMethod] = $validator->getFilter()->getSerializer();
149-
}
150-
}
151-
}
152-
153-
$schema->addUsedClass(SerializedValue::class);
154-
$schema->addMethod(
155-
'serializeAdditionalProperties',
156-
new RenderedMethod(
157-
$schema,
158-
$generatorConfiguration,
159-
'AdditionalProperties/AdditionalPropertiesSerializer.phptpl',
160-
[
161-
'serializerClass' => $serializerClass ?? null,
162-
'serializerMethod' => $serializerMethod ?? null,
163-
'serializerOptions' => $transformingFilterValidator
164-
? var_export($transformingFilterValidator->getFilterOptions(), true)
165-
: [],
166-
]
167-
)
168-
);
16991
}
17092

17193
/**
@@ -277,47 +199,36 @@ private function addGetAdditionalPropertyMethod(
277199
);
278200
}
279201

280-
/**
281-
* Usually the AdditionalPropertiesValidator validates all additional properties against the constraints and updates
282-
* the internal storage of the additional properties. If no additional property constraints are defined for the
283-
* schema the provided additional properties must be updated separately as no AdditionalPropertiesValidator is added
284-
* to the generated class.
285-
*
286-
* @param Schema $schema
287-
*/
288-
private function addUpdateAdditionalProperties(Schema $schema): void
289-
{
290-
$schema->addBaseValidator(
291-
new class ($schema) extends PropertyTemplateValidator {
292-
public function __construct(Schema $schema)
293-
{
294-
$patternProperties = array_keys($schema->getJsonSchema()->getJson()['patternProperties'] ?? []);
202+
private function addGetAdditionalPropertiesMethod(
203+
Schema $schema,
204+
GeneratorConfiguration $generatorConfiguration,
205+
?PropertyInterface $validationProperty
206+
): void {
207+
$validationProperty = $validationProperty
208+
// type hint always without null as the getter always returns an array
209+
? (clone $validationProperty)
210+
->setRequired(true)
211+
->addTypeHintDecorator(new ArrayTypeHintDecorator($validationProperty))
212+
: null;
213+
214+
if ($validationProperty && $validationProperty->getType(true)) {
215+
$validationProperty->setType(
216+
$validationProperty->getType(),
217+
new PropertyType($validationProperty->getType(true)->getName(), false)
218+
);
219+
}
295220

296-
parent::__construct(
297-
new Property($schema->getClassName(), null, $schema->getJsonSchema()),
298-
join(
299-
DIRECTORY_SEPARATOR,
300-
[
301-
'..',
302-
'SchemaProcessor',
303-
'PostProcessor',
304-
'Templates',
305-
'AdditionalProperties',
306-
'UpdateAdditionalProperties.phptpl',
307-
]
308-
),
309-
[
310-
'patternProperties' => $patternProperties
311-
? RenderHelper::varExportArray($patternProperties)
312-
: null,
313-
'additionalProperties' => RenderHelper::varExportArray(
314-
array_keys($schema->getJsonSchema()->getJson()['properties'] ?? [])
315-
),
316-
],
317-
Exception::class
318-
);
319-
}
320-
}
221+
$schema->addMethod(
222+
'getAdditionalProperties',
223+
new RenderedMethod(
224+
$schema,
225+
$generatorConfiguration,
226+
'AdditionalProperties/GetAdditionalProperties.phptpl',
227+
[
228+
'validationProperty' => $validationProperty,
229+
230+
]
231+
)
321232
);
322233
}
323234
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPModelGenerator\SchemaProcessor\PostProcessor\Internal;
6+
7+
use Exception;
8+
use PHPModelGenerator\Exception\SchemaException;
9+
use PHPModelGenerator\Model\GeneratorConfiguration;
10+
use PHPModelGenerator\Model\Property\Property;
11+
use PHPModelGenerator\Model\Property\PropertyType;
12+
use PHPModelGenerator\Model\Schema;
13+
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
14+
use PHPModelGenerator\Model\Validator\AdditionalPropertiesValidator;
15+
use PHPModelGenerator\Model\Validator\PropertyTemplateValidator;
16+
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\ArrayTypeHintDecorator;
17+
use PHPModelGenerator\SchemaProcessor\PostProcessor\PostProcessor;
18+
use PHPModelGenerator\Utils\RenderHelper;
19+
20+
/**
21+
* Class AdditionalPropertiesPostProcessor
22+
*
23+
* @package PHPModelGenerator\SchemaProcessor\PostProcessor\Internal
24+
*/
25+
class AdditionalPropertiesPostProcessor extends PostProcessor
26+
{
27+
/**
28+
* @param Schema $schema
29+
* @param GeneratorConfiguration $generatorConfiguration
30+
*
31+
* @throws SchemaException
32+
*/
33+
public function process(Schema $schema, GeneratorConfiguration $generatorConfiguration): void
34+
{
35+
$json = $schema->getJsonSchema()->getJson();
36+
37+
if (isset($json['additionalProperties']) && $json['additionalProperties'] !== false) {
38+
$this->addAdditionalPropertiesCollectionProperty($schema);
39+
}
40+
}
41+
42+
/**
43+
* @param Schema $schema
44+
*
45+
* @throws SchemaException
46+
*/
47+
public function addAdditionalPropertiesCollectionProperty(Schema $schema): void
48+
{
49+
$validationProperty = null;
50+
foreach ($schema->getBaseValidators() as $validator) {
51+
if (is_a($validator, AdditionalPropertiesValidator::class)) {
52+
$validator->setCollectAdditionalProperties(true);
53+
$validationProperty = $validator->getValidationProperty();
54+
}
55+
}
56+
57+
$additionalPropertiesCollectionProperty = (new Property(
58+
'additionalProperties',
59+
new PropertyType('array'),
60+
new JsonSchema(__FILE__, []),
61+
'Collect all additional properties provided to the schema'
62+
))
63+
->setDefaultValue([])
64+
->setInternal(true);
65+
66+
if ($validationProperty) {
67+
$additionalPropertiesCollectionProperty->addTypeHintDecorator(
68+
new ArrayTypeHintDecorator($validationProperty)
69+
);
70+
}
71+
72+
$schema->addProperty($additionalPropertiesCollectionProperty);
73+
74+
$json = $schema->getJsonSchema()->getJson();
75+
if (!isset($json['additionalProperties']) || $json['additionalProperties'] === true) {
76+
$this->addUpdateAdditionalProperties($schema);
77+
}
78+
}
79+
80+
/**
81+
* Usually the AdditionalPropertiesValidator validates all additional properties against the constraints and updates
82+
* the internal storage of the additional properties. If no additional property constraints are defined for the
83+
* schema the provided additional properties must be updated separately as no AdditionalPropertiesValidator is added
84+
* to the generated class.
85+
*
86+
* @param Schema $schema
87+
*/
88+
private function addUpdateAdditionalProperties(Schema $schema): void
89+
{
90+
$schema->addBaseValidator(
91+
new class ($schema) extends PropertyTemplateValidator {
92+
public function __construct(Schema $schema)
93+
{
94+
$patternProperties = array_keys($schema->getJsonSchema()->getJson()['patternProperties'] ?? []);
95+
96+
parent::__construct(
97+
new Property($schema->getClassName(), null, $schema->getJsonSchema()),
98+
join(
99+
DIRECTORY_SEPARATOR,
100+
[
101+
'..',
102+
'SchemaProcessor',
103+
'PostProcessor',
104+
'Templates',
105+
'AdditionalProperties',
106+
'UpdateAdditionalProperties.phptpl',
107+
]
108+
),
109+
[
110+
'patternProperties' => $patternProperties
111+
? RenderHelper::varExportArray($patternProperties)
112+
: null,
113+
'additionalProperties' => RenderHelper::varExportArray(
114+
array_keys($schema->getJsonSchema()->getJson()['properties'] ?? [])
115+
),
116+
],
117+
Exception::class
118+
);
119+
}
120+
}
121+
);
122+
}
123+
}

0 commit comments

Comments
 (0)