Skip to content

Commit 2ece5de

Browse files
committed
Added extended additionalProperties validation
1 parent 90ac342 commit 2ece5de

File tree

9 files changed

+388
-5
lines changed

9 files changed

+388
-5
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace PHPModelGenerator\Model\Validator;
6+
7+
use PHPMicroTemplate\Exception\FileSystemException;
8+
use PHPMicroTemplate\Exception\SyntaxErrorException;
9+
use PHPMicroTemplate\Exception\UndefinedSymbolException;
10+
use PHPModelGenerator\Exception\SchemaException;
11+
use PHPModelGenerator\Model\Schema;
12+
use PHPModelGenerator\PropertyProcessor\PropertyCollectionProcessor;
13+
use PHPModelGenerator\PropertyProcessor\PropertyFactory;
14+
use PHPModelGenerator\PropertyProcessor\PropertyProcessorFactory;
15+
use PHPModelGenerator\SchemaProcessor\SchemaProcessor;
16+
use PHPModelGenerator\Utils\RenderHelper;
17+
18+
/**
19+
* Class AdditionalPropertiesValidator
20+
*
21+
* @package PHPModelGenerator\Model\Validator
22+
*/
23+
class AdditionalPropertiesValidator extends AbstractComposedPropertyValidator
24+
{
25+
/**
26+
* AdditionalPropertiesValidator constructor.
27+
*
28+
* @param SchemaProcessor $schemaProcessor
29+
* @param Schema $schema
30+
* @param array $propertyStructure
31+
*
32+
* @throws FileSystemException
33+
* @throws SchemaException
34+
* @throws SyntaxErrorException
35+
* @throws UndefinedSymbolException
36+
*/
37+
public function __construct(
38+
SchemaProcessor $schemaProcessor,
39+
Schema $schema,
40+
array $propertyStructure
41+
) {
42+
$propertyFactory = new PropertyFactory(new PropertyProcessorFactory());
43+
44+
$validationProperty = $propertyFactory->create(
45+
new PropertyCollectionProcessor(),
46+
$schemaProcessor,
47+
$schema,
48+
'additional property',
49+
$propertyStructure['additionalProperties']
50+
);
51+
52+
parent::__construct(
53+
$this->getRenderer()->renderTemplate(
54+
DIRECTORY_SEPARATOR . 'Exception' . DIRECTORY_SEPARATOR . 'InvalidPropertiesException.phptpl',
55+
['error' => 'Provided JSON contains invalid additional properties.']
56+
),
57+
DIRECTORY_SEPARATOR . 'Validator' . DIRECTORY_SEPARATOR . 'AdditionalProperties.phptpl',
58+
[
59+
'validationProperty' => $validationProperty,
60+
'additionalProperties' => preg_replace(
61+
'(\d+\s=>)',
62+
'',
63+
var_export(array_keys($propertyStructure['properties'] ?? []), true)
64+
),
65+
'generatorConfiguration' => $schemaProcessor->getGeneratorConfiguration(),
66+
'viewHelper' => new RenderHelper($schemaProcessor->getGeneratorConfiguration()),
67+
]
68+
);
69+
}
70+
71+
/**
72+
* Initialize all variables which are required to execute a property names validator
73+
*
74+
* @return string
75+
*/
76+
public function getValidatorSetUp(): string
77+
{
78+
return '$invalidProperties = [];';
79+
}
80+
}

src/Model/Validator/PropertyNamesValidator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public function __construct(
4949

5050
parent::__construct(
5151
$this->getRenderer()->renderTemplate(
52-
DIRECTORY_SEPARATOR . 'Exception' . DIRECTORY_SEPARATOR . 'PropertyNamesException.phptpl'
52+
DIRECTORY_SEPARATOR . 'Exception' . DIRECTORY_SEPARATOR . 'InvalidPropertiesException.phptpl',
53+
['error' => 'Provided JSON contains properties with invalid names.']
5354
),
5455
DIRECTORY_SEPARATOR . 'Validator' . DIRECTORY_SEPARATOR . 'PropertyNames.phptpl',
5556
[

src/PropertyProcessor/Property/BaseProcessor.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PHPModelGenerator\Model\Property\PropertyInterface;
1313
use PHPModelGenerator\Model\Validator;
1414
use PHPModelGenerator\Model\Validator\AbstractComposedPropertyValidator;
15+
use PHPModelGenerator\Model\Validator\AdditionalPropertiesValidator;
1516
use PHPModelGenerator\Model\Validator\PropertyNamesValidator;
1617
use PHPModelGenerator\Model\Validator\PropertyTemplateValidator;
1718
use PHPModelGenerator\Model\Validator\PropertyValidator;
@@ -92,13 +93,30 @@ protected function addPropertyNamesValidator(array $propertyData): void
9293
* Add an object validator to disallow properties which are not defined in the schema
9394
*
9495
* @param array $propertyData
96+
*
97+
* @throws FileSystemException
98+
* @throws SchemaException
99+
* @throws SyntaxErrorException
100+
* @throws UndefinedSymbolException
95101
*/
96102
protected function addAdditionalPropertiesValidator(array $propertyData): void
97103
{
98104
if (!isset($propertyData['additionalProperties']) || $propertyData['additionalProperties'] === true) {
99105
return;
100106
}
101107

108+
if (!is_bool($propertyData['additionalProperties'])) {
109+
$this->schema->addBaseValidator(
110+
new AdditionalPropertiesValidator(
111+
$this->schemaProcessor,
112+
$this->schema,
113+
$propertyData
114+
)
115+
);
116+
117+
return;
118+
}
119+
102120
$this->schema->addBaseValidator(
103121
new PropertyValidator(
104122
sprintf(

src/Templates/Exception/PropertyNamesException.phptpl renamed to src/Templates/Exception/InvalidPropertiesException.phptpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Provided JSON contains properties with invalid names."
1+
{{ error }}"
22
. (function (array $invalidProperties) {
33
$output = '';
44
foreach ($invalidProperties as $propertyName => $errors) {

src/Templates/Model.phptpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ class {{ class }}
2323
protected ${{ property.getAttribute() }}{% if not viewHelper.isNull(property.getDefaultValue()) %} = {{ property.getDefaultValue() }}{% endif %};
2424
{% endforeach %}
2525
/** @var array */
26-
protected $rawModelDataInput;
26+
private $rawModelDataInput;
2727

2828
{% if generatorConfiguration.collectErrors() %}
2929
/** @var ErrorRegistryExceptionInterface Collect all validation errors */
30-
protected $errorRegistry;
30+
private $errorRegistry;
3131
/** @var bool Store if the current class is the initial class which must throw a collected exception after
3232
* the validation process is finished
3333
*/
34-
protected $isInitialClass = false;
34+
private $isInitialClass = false;
3535
{% endif %}
3636

3737
/**
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
(function () use ($modelData, &$invalidProperties) {
2+
{% if generatorConfiguration.collectErrors() %}
3+
$originalErrorRegistry = $this->errorRegistry;
4+
{% endif %}
5+
6+
foreach (array_diff(array_keys($modelData), {{ additionalProperties }}) as $propertyKey) {
7+
try {
8+
$value = $modelData[$propertyKey];
9+
10+
{% if generatorConfiguration.collectErrors() %}
11+
$this->errorRegistry = new {{ viewHelper.getSimpleClassName(generatorConfiguration.getErrorRegistryClass()) }}();
12+
{% endif %}
13+
14+
{{ viewHelper.resolvePropertyDecorator(validationProperty) }}
15+
16+
{% foreach validationProperty.getOrderedValidators() as validator %}
17+
{{ validator.getValidatorSetUp() }}
18+
if ({{ validator.getCheck() }}) {
19+
{{ viewHelper.validationError(validator.getExceptionMessage()) }}
20+
}
21+
{% endforeach %}
22+
23+
{% if generatorConfiguration.collectErrors() %}
24+
if ($this->errorRegistry->getErrors()) {
25+
$invalidProperties[$propertyKey] = $this->errorRegistry->getErrors();
26+
}
27+
{% endif %}
28+
} catch (\Exception $e) {
29+
// collect all errors concerning invalid property names
30+
isset($invalidProperties[$propertyKey])
31+
? $invalidProperties[$propertyKey][] = $e->getMessage()
32+
: $invalidProperties[$propertyKey] = [$e->getMessage()];
33+
}
34+
}
35+
36+
{% if generatorConfiguration.collectErrors() %}
37+
$this->errorRegistry = $originalErrorRegistry;
38+
{% endif %}
39+
40+
return !empty($invalidProperties);
41+
})()

0 commit comments

Comments
 (0)