From 0ff4f64054401c3b5523214c339c73687ae895a4 Mon Sep 17 00:00:00 2001 From: Enno Woortmann Date: Thu, 14 Sep 2023 13:37:38 +0200 Subject: [PATCH] Fix creation of dynamic property for composed item validators on properties (fixes #77) --- phpunit.xml | 1 + .../Validator/PropertyTemplateValidator.php | 2 + .../AbstractComposedValueProcessor.php | 4 - src/Templates/Validator/ComposedItem.phptpl | 20 ++--- src/Utils/RenderHelper.php | 5 ++ tests/Issues/Issue/Issue77Test.php | 27 +++++++ tests/Schema/Issues/77/dynamicProperty.json | 79 +++++++++++++++++++ 7 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 tests/Issues/Issue/Issue77Test.php create mode 100644 tests/Schema/Issues/77/dynamicProperty.json diff --git a/phpunit.xml b/phpunit.xml index 9418892..4faa221 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,6 +6,7 @@ convertErrorsToExceptions="true" convertWarningsToExceptions="true" convertNoticesToExceptions="true" + convertDeprecationsToExceptions="true" processIsolation="false" stopOnFailure="false" bootstrap="tests/bootstrap.php" diff --git a/src/Model/Validator/PropertyTemplateValidator.php b/src/Model/Validator/PropertyTemplateValidator.php index 9ccffcb..109eb57 100644 --- a/src/Model/Validator/PropertyTemplateValidator.php +++ b/src/Model/Validator/PropertyTemplateValidator.php @@ -56,6 +56,8 @@ public function setScope(Schema $schema): void if (isset($this->templateValues['schema'])) { $this->templateValues['schema'] = $schema; } + + $this->templateValues['isBaseValidator'] = in_array($this, $schema->getBaseValidators()); } /** diff --git a/src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php b/src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php index 5e8bb72..b5a7a41 100644 --- a/src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php +++ b/src/PropertyProcessor/ComposedValue/AbstractComposedValueProcessor.php @@ -5,9 +5,7 @@ namespace PHPModelGenerator\PropertyProcessor\ComposedValue; use PHPModelGenerator\Exception\SchemaException; -use PHPModelGenerator\Model\MethodInterface; use PHPModelGenerator\Model\Property\CompositionPropertyDecorator; -use PHPModelGenerator\Model\Property\Property; use PHPModelGenerator\Model\Property\PropertyInterface; use PHPModelGenerator\Model\Property\PropertyType; use PHPModelGenerator\Model\Schema; @@ -15,8 +13,6 @@ use PHPModelGenerator\Model\Validator; use PHPModelGenerator\Model\Validator\ComposedPropertyValidator; use PHPModelGenerator\Model\Validator\RequiredPropertyValidator; -use PHPModelGenerator\PropertyProcessor\Decorator\Property\ObjectInstantiationDecorator; -use PHPModelGenerator\PropertyProcessor\Decorator\SchemaNamespaceTransferDecorator; use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\ClearTypeHintDecorator; use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\CompositionTypeHintDecorator; use PHPModelGenerator\PropertyProcessor\Property\AbstractValueProcessor; diff --git a/src/Templates/Validator/ComposedItem.phptpl b/src/Templates/Validator/ComposedItem.phptpl index be2425f..58b69e3 100644 --- a/src/Templates/Validator/ComposedItem.phptpl +++ b/src/Templates/Validator/ComposedItem.phptpl @@ -14,7 +14,7 @@ $proposedValue = null; $modifiedValues = []; - {% if not generatorConfiguration.isImmutable() %} + {% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %} $originalPropertyValidationState = $this->_propertyValidationState ?? []; {% endif %} @@ -24,7 +24,7 @@ {% foreach compositionProperties as compositionProperty %} try { - {% if not generatorConfiguration.isImmutable() %} + {% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %} // check if the state of the validator is already known. // If none of the properties affected by the validator are changed the validator must not be re-evaluated if (isset($validatorIndex) && @@ -71,7 +71,7 @@ {% if generatorConfiguration.collectErrors() %} $compositionErrorCollection[] = $this->_errorRegistry; - {% if not generatorConfiguration.isImmutable() %} + {% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %} if (isset($validatorIndex)) { $this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = $this->_errorRegistry; } @@ -91,7 +91,7 @@ if (is_object($value)) { $modifiedValues = array_merge($modifiedValues, $this->{{ modifiedValuesMethod }}($originalModelData, $value)); } - {% if not generatorConfiguration.isImmutable() %} + {% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %} {% if not generatorConfiguration.collectErrors() %} if (isset($validatorIndex)) { $this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = true; @@ -100,10 +100,12 @@ } {% endif %} } catch (\Exception $e) { - {% if not generatorConfiguration.collectErrors() %} - if (isset($validatorIndex)) { - $this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = false; - } + {% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %} + {% if not generatorConfiguration.collectErrors() %} + if (isset($validatorIndex)) { + $this->_propertyValidationState[$validatorIndex][$validatorComponentIndex] = false; + } + {% endif %} {% endif %} {% foreach compositionProperty.getAffectedObjectProperties() as affectedObjectProperty %} @@ -137,7 +139,7 @@ $result = !({{ composedValueValidation }}); - {% if not generatorConfiguration.isImmutable() %} + {% if viewHelper.isMutableBaseValidator(generatorConfiguration, isBaseValidator) %} if ($result) { $this->_propertyValidationState = $originalPropertyValidationState; } diff --git a/src/Utils/RenderHelper.php b/src/Utils/RenderHelper.php index 879bc25..980832e 100644 --- a/src/Utils/RenderHelper.php +++ b/src/Utils/RenderHelper.php @@ -197,6 +197,11 @@ public function renderMethods(Schema $schema): string return $renderedMethods; } + public function isMutableBaseValidator(GeneratorConfiguration $generatorConfiguration, bool $isBaseValidator): bool + { + return !$generatorConfiguration->isImmutable() && $isBaseValidator; + } + public static function varExportArray(array $values): string { return preg_replace('(\d+\s=>)', '', var_export($values, true)); diff --git a/tests/Issues/Issue/Issue77Test.php b/tests/Issues/Issue/Issue77Test.php new file mode 100644 index 0000000..408ad28 --- /dev/null +++ b/tests/Issues/Issue/Issue77Test.php @@ -0,0 +1,27 @@ +generateClassFromFile('dynamicProperty.json', (new GeneratorConfiguration())->setImmutable(false)); + + $object = new $className(['values' => [1, 10, 1000], 'pet' => ['type' => 'dog', 'age' => 0, 'name' => 'Hans']]); + + $this->assertSame([1, 10, 1000], $object->getValues()); + $this->assertSame('dog', $object->getPet()->getType()); + $this->assertSame(0, $object->getPet()->getAge()); + $this->assertSame('Hans', $object->getPet()->getName()); + + $this->expectExceptionMessage('Value for item of array values must not be smaller than 1'); + + new $className(['values' => [0]]); + } +} diff --git a/tests/Schema/Issues/77/dynamicProperty.json b/tests/Schema/Issues/77/dynamicProperty.json new file mode 100644 index 0000000..33a7730 --- /dev/null +++ b/tests/Schema/Issues/77/dynamicProperty.json @@ -0,0 +1,79 @@ +{ + "type": "object", + "definitions": { + "number": { + "type": "integer", + "minimum": 0, + "maximum": 1000 + }, + "values": { + "type": "array", + "items": { + "allOf": [ + { + "$ref": "#/definitions/number" + }, + { + "type": "integer", + "minimum": 1 + } + ] + } + }, + "pet": { + "oneOf": [ + { + "$ref": "#/definitions/pets/dog" + }, + { + "$ref": "#/definitions/pets/spider" + } + ] + }, + "pets": { + "dog": { + "type": "object", + "$id": "dog", + "properties": { + "age": { + "$ref": "#/definitions/number" + }, + "name": { + "type": "string" + }, + "type": { + "const": "dog" + } + }, + "required": [ + "type" + ] + }, + "spider": { + "type": "object", + "properties": { + "age": { + "$ref": "#/definitions/number" + }, + "weight": { + "type": "number" + }, + "type": { + "const": "spider" + } + }, + "required": [ + "type" + ] + } + } + }, + "properties": { + "values": { + "$ref": "#/definitions/values" + }, + "pet": { + "$ref": "#/definitions/pet" + } + } +}