From 5b1771a00e55f5f14e05f35ef4b467017806e3d0 Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Mon, 16 Sep 2024 22:57:08 +0300 Subject: [PATCH 1/8] Added support for non required const-properties --- .../Property/ConstProcessor.php | 36 ++++++++++---- tests/Objects/ConstPropertyTest.php | 48 ++++++++++++------- tests/Objects/RequiredPropertyTest.php | 25 ++++++++++ .../RequiredAndOptionalConstProperties.json | 14 ++++++ .../RequiredAndOptionalConstProperties.json | 14 ++++++ 5 files changed, 113 insertions(+), 24 deletions(-) create mode 100644 tests/Schema/ConstPropertyTest/RequiredAndOptionalConstProperties.json create mode 100644 tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index 9ca86d8e..895ce512 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -10,7 +10,9 @@ use PHPModelGenerator\Model\Property\PropertyType; use PHPModelGenerator\Model\SchemaDefinition\JsonSchema; use PHPModelGenerator\Model\Validator\PropertyValidator; +use PHPModelGenerator\PropertyProcessor\PropertyMetaDataCollection; use PHPModelGenerator\PropertyProcessor\PropertyProcessorInterface; +use PHPModelGenerator\Utils\RenderHelper; use PHPModelGenerator\Utils\TypeConverter; /** @@ -20,6 +22,20 @@ */ class ConstProcessor implements PropertyProcessorInterface { + /** @var PropertyMetaDataCollection */ + protected $propertyMetaDataCollection; + + /** + * ConstProcessor constructor. + * + * @param PropertyMetaDataCollection $propertyMetaDataCollection + */ + public function __construct( + PropertyMetaDataCollection $propertyMetaDataCollection, + ) { + $this->propertyMetaDataCollection = $propertyMetaDataCollection; + } + /** * @inheritdoc */ @@ -34,13 +50,17 @@ public function process(string $propertyName, JsonSchema $propertySchema): Prope $json['description'] ?? '', ); - return $property - ->setRequired(true) - ->addValidator(new PropertyValidator( - $property, - '$value !== ' . var_export($json['const'], true), - InvalidConstException::class, - [$json['const']], - )); + $property->setRequired($this->propertyMetaDataCollection->isAttributeRequired($propertyName)); + + $check = $property->isRequired() + ? '$value !== ' . var_export($json['const'], true) + : '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)'; + + return $property->addValidator(new PropertyValidator( + $property, + $check, + InvalidConstException::class, + [$json['const']], + )); } } diff --git a/tests/Objects/ConstPropertyTest.php b/tests/Objects/ConstPropertyTest.php index 3f87ec06..4d822a95 100644 --- a/tests/Objects/ConstPropertyTest.php +++ b/tests/Objects/ConstPropertyTest.php @@ -33,21 +33,6 @@ public function testProvidedConstPropertyIsValid(): void $this->assertSame(42, $object->getIntegerProperty()); } - /** - * @throws FileSystemException - * @throws RenderException - * @throws SchemaException - */ - public function testNotProvidedConstPropertyThrowsAnException(): void - { - $this->expectException(ValidationException::class); - $this->expectExceptionMessage('Invalid value for stringProperty declined by const constraint'); - - $className = $this->generateClassFromFile('ConstProperty.json'); - - new $className([]); - } - /** * @dataProvider invalidPropertyDataProvider * @@ -76,7 +61,38 @@ public function invalidPropertyDataProvider(): array 'array' => [[]], 'object' => [new stdClass()], 'string' => ['null'], - 'null' => [null], + ]; + } + + /** + * @dataProvider invalidRequiredAndOptionalConstPropertiesDataProvider + * + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testNotMatchingRequiredAndOptionalProvidedDataThrowsAnException( + string $reqPropertyValue, + ?string $optPropertyValue, + string $exceptionMessage + ): void + { + $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); + + $this->expectException(ValidationException::class); + $this->expectExceptionMessage($exceptionMessage); + + new $className(['requiredProperty' => $reqPropertyValue, 'optionalProperty' => $optPropertyValue]); + } + + public function invalidRequiredAndOptionalConstPropertiesDataProvider(): array + { + return [ + ['blue', 'green', 'Invalid value for requiredProperty declined by const constraint'], + ['blue', null, 'Invalid value for requiredProperty declined by const constraint'], + ['red', 'blue', 'Invalid value for optionalProperty declined by const constraint'], + ['red', '0', 'Invalid value for optionalProperty declined by const constraint'], + ['red', '', 'Invalid value for optionalProperty declined by const constraint'], ]; } } diff --git a/tests/Objects/RequiredPropertyTest.php b/tests/Objects/RequiredPropertyTest.php index fed8b83c..8c516926 100644 --- a/tests/Objects/RequiredPropertyTest.php +++ b/tests/Objects/RequiredPropertyTest.php @@ -162,4 +162,29 @@ public function requiredStringPropertyDataProvider(): array ], ); } + + /** + * @dataProvider requiredAndOptionalPropertiesDataProvider + * + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedConstPropertiesIsValid(string $reqPropertyValue, ?string $optPropertyValue): void + { + $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); + + $object = new $className(['requiredProperty' => $reqPropertyValue, 'optionalProperty' => $optPropertyValue]); + + $this->assertSame($reqPropertyValue, $object->getRequiredProperty()); + $this->assertSame($optPropertyValue, $object->getOptionalProperty()); + } + + public function requiredAndOptionalPropertiesDataProvider(): array + { + return [ + ['red', 'green'], + ['red', null], + ]; + } } diff --git a/tests/Schema/ConstPropertyTest/RequiredAndOptionalConstProperties.json b/tests/Schema/ConstPropertyTest/RequiredAndOptionalConstProperties.json new file mode 100644 index 00000000..06987a0a --- /dev/null +++ b/tests/Schema/ConstPropertyTest/RequiredAndOptionalConstProperties.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "properties": { + "requiredProperty": { + "const": "red" + }, + "optionalProperty": { + "const": "green" + } + }, + "required": [ + "requiredProperty" + ] +} \ No newline at end of file diff --git a/tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json b/tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json new file mode 100644 index 00000000..06987a0a --- /dev/null +++ b/tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "properties": { + "requiredProperty": { + "const": "red" + }, + "optionalProperty": { + "const": "green" + } + }, + "required": [ + "requiredProperty" + ] +} \ No newline at end of file From 115ee95ea9771036e868ae1649454a8c4735c100 Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Mon, 16 Sep 2024 23:18:07 +0300 Subject: [PATCH 2/8] Replaced interface to abstract class --- .../Property/ConstProcessor.php | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index 895ce512..40c41c68 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -10,8 +10,6 @@ use PHPModelGenerator\Model\Property\PropertyType; use PHPModelGenerator\Model\SchemaDefinition\JsonSchema; use PHPModelGenerator\Model\Validator\PropertyValidator; -use PHPModelGenerator\PropertyProcessor\PropertyMetaDataCollection; -use PHPModelGenerator\PropertyProcessor\PropertyProcessorInterface; use PHPModelGenerator\Utils\RenderHelper; use PHPModelGenerator\Utils\TypeConverter; @@ -20,22 +18,8 @@ * * @package PHPModelGenerator\PropertyProcessor\Property */ -class ConstProcessor implements PropertyProcessorInterface +class ConstProcessor extends AbstractPropertyProcessor { - /** @var PropertyMetaDataCollection */ - protected $propertyMetaDataCollection; - - /** - * ConstProcessor constructor. - * - * @param PropertyMetaDataCollection $propertyMetaDataCollection - */ - public function __construct( - PropertyMetaDataCollection $propertyMetaDataCollection, - ) { - $this->propertyMetaDataCollection = $propertyMetaDataCollection; - } - /** * @inheritdoc */ From 7868a1eba688c36f900296c31f9d433bab883a7f Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Tue, 17 Sep 2024 15:11:47 +0300 Subject: [PATCH 3/8] Added implementation of implicit null for constant properties --- .../Property/ConstProcessor.php | 4 +- tests/Objects/ConstPropertyTest.php | 113 ++++++++++++++++-- tests/Objects/RequiredPropertyTest.php | 25 ---- .../RequiredAndOptionalConstProperties.json | 14 --- 4 files changed, 106 insertions(+), 50 deletions(-) delete mode 100644 tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index 40c41c68..57dddb89 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -34,7 +34,9 @@ public function process(string $propertyName, JsonSchema $propertySchema): Prope $json['description'] ?? '', ); - $property->setRequired($this->propertyMetaDataCollection->isAttributeRequired($propertyName)); + $isAttributeRequired = $this->propertyMetaDataCollection->isAttributeRequired($propertyName); + $isImplicitNullAllowed = $this->schemaProcessor->getGeneratorConfiguration()->isImplicitNullAllowed(); + $property->setRequired($isAttributeRequired || !$isImplicitNullAllowed); $check = $property->isRequired() ? '$value !== ' . var_export($json['const'], true) diff --git a/tests/Objects/ConstPropertyTest.php b/tests/Objects/ConstPropertyTest.php index 4d822a95..8163d9a8 100644 --- a/tests/Objects/ConstPropertyTest.php +++ b/tests/Objects/ConstPropertyTest.php @@ -4,10 +4,12 @@ namespace PHPModelGenerator\Tests\Objects; +use PHPModelGenerator\Exception\ErrorRegistryException; use PHPModelGenerator\Exception\FileSystemException; use PHPModelGenerator\Exception\ValidationException; use PHPModelGenerator\Exception\RenderException; use PHPModelGenerator\Exception\SchemaException; +use PHPModelGenerator\Model\GeneratorConfiguration; use PHPModelGenerator\Tests\AbstractPHPModelGeneratorTestCase; use stdClass; @@ -33,6 +35,21 @@ public function testProvidedConstPropertyIsValid(): void $this->assertSame(42, $object->getIntegerProperty()); } + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testNotProvidedConstPropertyThrowsAnException(): void + { + $this->expectException(ValidationException::class); + $this->expectExceptionMessage('Invalid value for stringProperty declined by const constraint'); + + $className = $this->generateClassFromFile('ConstProperty.json', null, false, false); + + new $className([]); + } + /** * @dataProvider invalidPropertyDataProvider * @@ -47,7 +64,7 @@ public function testNotMatchingProvidedDataThrowsAnException($propertyValue): vo $this->expectException(ValidationException::class); $this->expectExceptionMessage('Invalid value for stringProperty declined by const constraint'); - $className = $this->generateClassFromFile('ConstProperty.json'); + $className = $this->generateClassFromFile('ConstProperty.json', null, false, false); new $className(['stringProperty' => $propertyValue]); } @@ -61,9 +78,76 @@ public function invalidPropertyDataProvider(): array 'array' => [[]], 'object' => [new stdClass()], 'string' => ['null'], + 'null' => [null], ]; } + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedConstOnlyRequiredPropertyIsValid(): void + { + $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); + + $object = new $className(['requiredProperty' => 'red']); + + $this->assertSame('red', $object->getRequiredProperty()); + $this->assertNull($object->getOptionalProperty()); + } + + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedNullOptionalPropertyConstPropertyIsValid(): void + { + $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); + + $object = new $className(['requiredProperty' => 'red', 'optionalProperty' => null]); + + $this->assertSame('red', $object->getRequiredProperty()); + $this->assertNull($object->getOptionalProperty()); + } + + /** + * @dataProvider requiredAndOptionalPropertiesDataProvider + * + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedConstPropertiesIsValidWithDifferentImplicitNull( + bool $implicitNull, + string $reqPropertyValue, + string $optPropertyValue + ): void + { + $className = $this->generateClassFromFile( + 'RequiredAndOptionalConstProperties.json', + new GeneratorConfiguration(), + false, + $implicitNull, + ); + + $object = new $className(['requiredProperty' => $reqPropertyValue, 'optionalProperty' => $optPropertyValue]); + + $this->assertSame($reqPropertyValue, $object->getRequiredProperty()); + $this->assertSame($optPropertyValue, $object->getOptionalProperty()); + } + + public function requiredAndOptionalPropertiesDataProvider(): array + { + return $this->combineDataProvider( + $this->implicitNullDataProvider(), + [ + ['red', 'green'], + ], + ); + } + /** * @dataProvider invalidRequiredAndOptionalConstPropertiesDataProvider * @@ -72,14 +156,20 @@ public function invalidPropertyDataProvider(): array * @throws SchemaException */ public function testNotMatchingRequiredAndOptionalProvidedDataThrowsAnException( + bool $implicitNull, string $reqPropertyValue, ?string $optPropertyValue, string $exceptionMessage ): void { - $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); + $className = $this->generateClassFromFile( + 'RequiredAndOptionalConstProperties.json', + new GeneratorConfiguration(), + false, + $implicitNull, + ); - $this->expectException(ValidationException::class); + $this->expectException(ErrorRegistryException::class); $this->expectExceptionMessage($exceptionMessage); new $className(['requiredProperty' => $reqPropertyValue, 'optionalProperty' => $optPropertyValue]); @@ -87,12 +177,15 @@ public function testNotMatchingRequiredAndOptionalProvidedDataThrowsAnException( public function invalidRequiredAndOptionalConstPropertiesDataProvider(): array { - return [ - ['blue', 'green', 'Invalid value for requiredProperty declined by const constraint'], - ['blue', null, 'Invalid value for requiredProperty declined by const constraint'], - ['red', 'blue', 'Invalid value for optionalProperty declined by const constraint'], - ['red', '0', 'Invalid value for optionalProperty declined by const constraint'], - ['red', '', 'Invalid value for optionalProperty declined by const constraint'], - ]; + return $this->combineDataProvider( + $this->implicitNullDataProvider(), + [ + ['blue', 'green', 'Invalid value for requiredProperty declined by const constraint'], + ['blue', null, 'Invalid value for requiredProperty declined by const constraint'], + ['red', 'blue', 'Invalid value for optionalProperty declined by const constraint'], + ['red', '0', 'Invalid value for optionalProperty declined by const constraint'], + ['red', '', 'Invalid value for optionalProperty declined by const constraint'], + ], + ); } } diff --git a/tests/Objects/RequiredPropertyTest.php b/tests/Objects/RequiredPropertyTest.php index 8c516926..fed8b83c 100644 --- a/tests/Objects/RequiredPropertyTest.php +++ b/tests/Objects/RequiredPropertyTest.php @@ -162,29 +162,4 @@ public function requiredStringPropertyDataProvider(): array ], ); } - - /** - * @dataProvider requiredAndOptionalPropertiesDataProvider - * - * @throws FileSystemException - * @throws RenderException - * @throws SchemaException - */ - public function testProvidedConstPropertiesIsValid(string $reqPropertyValue, ?string $optPropertyValue): void - { - $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); - - $object = new $className(['requiredProperty' => $reqPropertyValue, 'optionalProperty' => $optPropertyValue]); - - $this->assertSame($reqPropertyValue, $object->getRequiredProperty()); - $this->assertSame($optPropertyValue, $object->getOptionalProperty()); - } - - public function requiredAndOptionalPropertiesDataProvider(): array - { - return [ - ['red', 'green'], - ['red', null], - ]; - } } diff --git a/tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json b/tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json deleted file mode 100644 index 06987a0a..00000000 --- a/tests/Schema/RequiredPropertyTest/RequiredAndOptionalConstProperties.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "object", - "properties": { - "requiredProperty": { - "const": "red" - }, - "optionalProperty": { - "const": "green" - } - }, - "required": [ - "requiredProperty" - ] -} \ No newline at end of file From 683e7ab031a17a75df52867ea4e78a3f2e68bcd3 Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Wed, 18 Sep 2024 11:15:01 +0300 Subject: [PATCH 4/8] Changed the check setRequired --- .../Property/ConstProcessor.php | 10 +++---- tests/Objects/ConstPropertyTest.php | 29 +++++++++---------- .../NullValueConstProperty.json | 11 +++++++ 3 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 tests/Schema/ConstPropertyTest/NullValueConstProperty.json diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index 57dddb89..c2ef9e26 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -34,13 +34,11 @@ public function process(string $propertyName, JsonSchema $propertySchema): Prope $json['description'] ?? '', ); - $isAttributeRequired = $this->propertyMetaDataCollection->isAttributeRequired($propertyName); - $isImplicitNullAllowed = $this->schemaProcessor->getGeneratorConfiguration()->isImplicitNullAllowed(); - $property->setRequired($isAttributeRequired || !$isImplicitNullAllowed); + $property->setRequired($this->propertyMetaDataCollection->isAttributeRequired($propertyName)); - $check = $property->isRequired() - ? '$value !== ' . var_export($json['const'], true) - : '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)'; + $check = $this->isImplicitNullAllowed($property) + ? "array_key_exists('{$property->getName()}', \$modelData) && " . '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)' + : "array_key_exists('{$property->getName()}', \$modelData) && \$value !== " . var_export($json['const'], true); return $property->addValidator(new PropertyValidator( $property, diff --git a/tests/Objects/ConstPropertyTest.php b/tests/Objects/ConstPropertyTest.php index 8163d9a8..edec16df 100644 --- a/tests/Objects/ConstPropertyTest.php +++ b/tests/Objects/ConstPropertyTest.php @@ -35,21 +35,6 @@ public function testProvidedConstPropertyIsValid(): void $this->assertSame(42, $object->getIntegerProperty()); } - /** - * @throws FileSystemException - * @throws RenderException - * @throws SchemaException - */ - public function testNotProvidedConstPropertyThrowsAnException(): void - { - $this->expectException(ValidationException::class); - $this->expectExceptionMessage('Invalid value for stringProperty declined by const constraint'); - - $className = $this->generateClassFromFile('ConstProperty.json', null, false, false); - - new $className([]); - } - /** * @dataProvider invalidPropertyDataProvider * @@ -188,4 +173,18 @@ public function invalidRequiredAndOptionalConstPropertiesDataProvider(): array ], ); } + + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedNullValueConstPropertyIsValid(): void + { + $className = $this->generateClassFromFile('NullValueConstProperty.json', null, false, false); + + $object = new $className(['nullProperty' => null]); + + $this->assertNull($object->getNullProperty()); + } } diff --git a/tests/Schema/ConstPropertyTest/NullValueConstProperty.json b/tests/Schema/ConstPropertyTest/NullValueConstProperty.json new file mode 100644 index 00000000..8ee4dc45 --- /dev/null +++ b/tests/Schema/ConstPropertyTest/NullValueConstProperty.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "properties": { + "nullProperty": { + "const": null + } + }, + "required": [ + "nullProperty" + ] +} \ No newline at end of file From 3ae77c5d2dbdc08980ee0689c73cbb95587db226 Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Wed, 18 Sep 2024 12:53:51 +0300 Subject: [PATCH 5/8] Remove modelData from check conditions --- src/PropertyProcessor/Property/ConstProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index c2ef9e26..48601776 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -37,8 +37,8 @@ public function process(string $propertyName, JsonSchema $propertySchema): Prope $property->setRequired($this->propertyMetaDataCollection->isAttributeRequired($propertyName)); $check = $this->isImplicitNullAllowed($property) - ? "array_key_exists('{$property->getName()}', \$modelData) && " . '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)' - : "array_key_exists('{$property->getName()}', \$modelData) && \$value !== " . var_export($json['const'], true); + ? '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)' + : '$value !== ' . var_export($json['const'], true); return $property->addValidator(new PropertyValidator( $property, From 522c52a0f1ba190f3d729d724158fc42e2606807 Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Wed, 18 Sep 2024 13:21:52 +0300 Subject: [PATCH 6/8] Added call generateValidators() and unit test --- .../Property/ConstProcessor.php | 6 +++++- tests/Objects/ConstPropertyTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index 48601776..eda913d4 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -40,11 +40,15 @@ public function process(string $propertyName, JsonSchema $propertySchema): Prope ? '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)' : '$value !== ' . var_export($json['const'], true); - return $property->addValidator(new PropertyValidator( + $property->addValidator(new PropertyValidator( $property, $check, InvalidConstException::class, [$json['const']], )); + + $this->generateValidators($property, $propertySchema); + + return $property; } } diff --git a/tests/Objects/ConstPropertyTest.php b/tests/Objects/ConstPropertyTest.php index edec16df..12253559 100644 --- a/tests/Objects/ConstPropertyTest.php +++ b/tests/Objects/ConstPropertyTest.php @@ -6,6 +6,7 @@ use PHPModelGenerator\Exception\ErrorRegistryException; use PHPModelGenerator\Exception\FileSystemException; +use PHPModelGenerator\Exception\Object\RequiredValueException; use PHPModelGenerator\Exception\ValidationException; use PHPModelGenerator\Exception\RenderException; use PHPModelGenerator\Exception\SchemaException; @@ -133,6 +134,21 @@ public function requiredAndOptionalPropertiesDataProvider(): array ); } + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testNotProvidedRequiredPropertyThrowsAnException(): void + { + $this->expectException(RequiredValueException::class); + $this->expectExceptionMessage('Missing required value for requiredProperty'); + + $className = $this->generateClassFromFile('RequiredAndOptionalConstProperties.json'); + + new $className([]); + } + /** * @dataProvider invalidRequiredAndOptionalConstPropertiesDataProvider * From 3a92e6dffe2aacb3e47e6cc034342eb2b2379104 Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Wed, 18 Sep 2024 13:55:19 +0300 Subject: [PATCH 7/8] Replaced check with three conditions --- src/PropertyProcessor/Property/ConstProcessor.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/PropertyProcessor/Property/ConstProcessor.php b/src/PropertyProcessor/Property/ConstProcessor.php index eda913d4..d5ad8097 100644 --- a/src/PropertyProcessor/Property/ConstProcessor.php +++ b/src/PropertyProcessor/Property/ConstProcessor.php @@ -36,9 +36,14 @@ public function process(string $propertyName, JsonSchema $propertySchema): Prope $property->setRequired($this->propertyMetaDataCollection->isAttributeRequired($propertyName)); - $check = $this->isImplicitNullAllowed($property) - ? '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)' - : '$value !== ' . var_export($json['const'], true); + $check = match(true) { + $property->isRequired() + => '$value !== ' . var_export($json['const'], true), + $this->isImplicitNullAllowed($property) + => '!in_array($value, ' . RenderHelper::varExportArray([$json['const'], null]) . ', true)', + default + => "array_key_exists('{$property->getName()}', \$modelData) && \$value !== " . var_export($json['const'], true), + }; $property->addValidator(new PropertyValidator( $property, From 3c8ff04cd8bf8ec8057212bfe6f254c58aa36c4e Mon Sep 17 00:00:00 2001 From: Kolodkin Valentin Date: Thu, 19 Sep 2024 12:42:15 +0300 Subject: [PATCH 8/8] Ensured the presence of the $modelData variable in the templates, added some unit tests --- .../Validator/ExtractedMethodValidator.php | 2 +- .../Validator/AdditionalProperties.phptpl | 2 +- src/Templates/Validator/ArrayItem.phptpl | 2 +- src/Templates/Validator/ArrayTuple.phptpl | 2 +- .../Validator/PatternProperties.phptpl | 2 +- src/Utils/RenderHelper.php | 2 +- tests/Objects/ConstPropertyTest.php | 71 +++++++++++++++++++ .../ConstPropertyTest/AnyOfConstProperty.json | 15 ++++ .../ArrayItemConstProperty.json | 13 ++++ 9 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 tests/Schema/ConstPropertyTest/AnyOfConstProperty.json create mode 100644 tests/Schema/ConstPropertyTest/ArrayItemConstProperty.json diff --git a/src/Model/Validator/ExtractedMethodValidator.php b/src/Model/Validator/ExtractedMethodValidator.php index c1b8cc56..6a63b616 100644 --- a/src/Model/Validator/ExtractedMethodValidator.php +++ b/src/Model/Validator/ExtractedMethodValidator.php @@ -59,7 +59,7 @@ public function __construct( public function getCode(): string { $renderHelper = new RenderHelper($this->generatorConfiguration); - return "private function {$this->validator->getExtractedMethodName()}(&\$value): void { + return "private function {$this->validator->getExtractedMethodName()}(&\$value, \$modelData): void { {$this->validator->getValidatorSetUp()} if ({$this->validator->getCheck()}) { diff --git a/src/Templates/Validator/AdditionalProperties.phptpl b/src/Templates/Validator/AdditionalProperties.phptpl index 87557485..96c93e64 100644 --- a/src/Templates/Validator/AdditionalProperties.phptpl +++ b/src/Templates/Validator/AdditionalProperties.phptpl @@ -1,4 +1,4 @@ -(function () use ($properties, &$invalidProperties) { +(function () use ($properties, &$invalidProperties, $modelData) { {% if generatorConfiguration.collectErrors() %} $originalErrorRegistry = $this->_errorRegistry; {% endif %} diff --git a/src/Templates/Validator/ArrayItem.phptpl b/src/Templates/Validator/ArrayItem.phptpl index 0c14f334..cdbea591 100644 --- a/src/Templates/Validator/ArrayItem.phptpl +++ b/src/Templates/Validator/ArrayItem.phptpl @@ -1,4 +1,4 @@ -is_array($value) && (function (&$items) use (&$invalidItems{{ suffix }}) { +is_array($value) && (function (&$items) use (&$invalidItems{{ suffix }}, $modelData) { {% if generatorConfiguration.collectErrors() %} $originalErrorRegistry = $this->_errorRegistry; {% endif %} diff --git a/src/Templates/Validator/ArrayTuple.phptpl b/src/Templates/Validator/ArrayTuple.phptpl index 425e9d11..d6ce49ea 100644 --- a/src/Templates/Validator/ArrayTuple.phptpl +++ b/src/Templates/Validator/ArrayTuple.phptpl @@ -1,4 +1,4 @@ -is_array($value) && (function (&$items) use (&$invalidTuples) { +is_array($value) && (function (&$items) use (&$invalidTuples, $modelData) { {% if generatorConfiguration.collectErrors() %} $originalErrorRegistry = $this->_errorRegistry; {% endif %} diff --git a/src/Templates/Validator/PatternProperties.phptpl b/src/Templates/Validator/PatternProperties.phptpl index b69d4c13..42bb0094 100644 --- a/src/Templates/Validator/PatternProperties.phptpl +++ b/src/Templates/Validator/PatternProperties.phptpl @@ -1,4 +1,4 @@ -(function () use ($properties, &$invalidProperties) { +(function () use ($properties, &$invalidProperties, $modelData) { {% if generatorConfiguration.collectErrors() %} $originalErrorRegistry = $this->_errorRegistry; {% endif %} diff --git a/src/Utils/RenderHelper.php b/src/Utils/RenderHelper.php index 4d249350..c69daaad 100644 --- a/src/Utils/RenderHelper.php +++ b/src/Utils/RenderHelper.php @@ -182,7 +182,7 @@ public function renderValidator(PropertyValidatorInterface $validator, Schema $s $schema->addMethod($validator->getExtractedMethodName(), $validator->getMethod()); } - return "\$this->{$validator->getExtractedMethodName()}(\$value);"; + return "\$this->{$validator->getExtractedMethodName()}(\$value, \$modelData);"; } public function renderMethods(Schema $schema): string diff --git a/tests/Objects/ConstPropertyTest.php b/tests/Objects/ConstPropertyTest.php index 12253559..e4a225ae 100644 --- a/tests/Objects/ConstPropertyTest.php +++ b/tests/Objects/ConstPropertyTest.php @@ -4,6 +4,8 @@ namespace PHPModelGenerator\Tests\Objects; +use PHPModelGenerator\Exception\Arrays\InvalidTupleException; +use PHPModelGenerator\Exception\ComposedValue\OneOfException; use PHPModelGenerator\Exception\ErrorRegistryException; use PHPModelGenerator\Exception\FileSystemException; use PHPModelGenerator\Exception\Object\RequiredValueException; @@ -36,6 +38,45 @@ public function testProvidedConstPropertyIsValid(): void $this->assertSame(42, $object->getIntegerProperty()); } + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedArrayItemConstPropertyIsValid(): void + { + $className = $this->generateClassFromFile('ArrayItemConstProperty.json'); + + $object = new $className(['property' => ['red', 'red']]); + + $this->assertIsArray($object->getProperty()); + $this->assertSame(['red', 'red'], $object->getProperty()); + } + + /** + * @dataProvider stringIntDataProvider + * + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testProvidedAnyOfConstPropertyIsValid(string|int $propertyValue): void + { + $className = $this->generateClassFromFile('AnyOfConstProperty.json'); + + $object = new $className(['property' => $propertyValue]); + + $this->assertSame($propertyValue, $object->getProperty()); + } + + public function stringIntDataProvider(): array + { + return [ + ['red'], + [1], + ]; + } + /** * @dataProvider invalidPropertyDataProvider * @@ -68,6 +109,36 @@ public function invalidPropertyDataProvider(): array ]; } + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testNotMatchingArrayItemConstPropertyThrowsAnException(): void + { + $this->expectException(InvalidTupleException::class); + $this->expectExceptionMessage('Invalid tuple item in array property'); + + $className = $this->generateClassFromFile('ArrayItemConstProperty.json'); + + new $className(['property' => ['green']]); + } + + /** + * @throws FileSystemException + * @throws RenderException + * @throws SchemaException + */ + public function testNotMatchingArrayItemConstPropertyThrowsAnException1(): void + { + $this->expectException(OneOfException::class); + $this->expectExceptionMessage('Invalid value for property declined by composition constraint'); + + $className = $this->generateClassFromFile('AnyOfConstProperty.json'); + + new $className(['property' => 'green']); + } + /** * @throws FileSystemException * @throws RenderException diff --git a/tests/Schema/ConstPropertyTest/AnyOfConstProperty.json b/tests/Schema/ConstPropertyTest/AnyOfConstProperty.json new file mode 100644 index 00000000..94d9539f --- /dev/null +++ b/tests/Schema/ConstPropertyTest/AnyOfConstProperty.json @@ -0,0 +1,15 @@ +{ + "type": "object", + "properties": { + "property": { + "oneOf": [ + { + "const": "red" + }, + { + "const": 1 + } + ] + } + } +} \ No newline at end of file diff --git a/tests/Schema/ConstPropertyTest/ArrayItemConstProperty.json b/tests/Schema/ConstPropertyTest/ArrayItemConstProperty.json new file mode 100644 index 00000000..c111e74b --- /dev/null +++ b/tests/Schema/ConstPropertyTest/ArrayItemConstProperty.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "property": { + "type": "array", + "items": [ + { + "const": "red" + } + ] + } + } +} \ No newline at end of file