From 6a72c6e4fb30062e040771db59903f621fee7687 Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 16 Apr 2021 15:26:52 +0300 Subject: [PATCH] Add support for generating property schema with numeric constraint restrictions --- CHANGELOG.md | 1 + .../Bundle/Resources/config/validator.xml | 16 ++++ ...rtySchemaGreaterThanOrEqualRestriction.php | 45 ++++++++++ .../PropertySchemaGreaterThanRestriction.php | 46 ++++++++++ ...opertySchemaLessThanOrEqualRestriction.php | 45 ++++++++++ .../PropertySchemaLessThanRestriction.php | 46 ++++++++++ .../ApiPlatformExtensionTest.php | 4 + ...chemaGreaterThanOrEqualRestrictionTest.php | 61 +++++++++++++ ...opertySchemaGreaterThanRestrictionTest.php | 65 ++++++++++++++ ...tySchemaLessThanOrEqualRestrictionTest.php | 61 +++++++++++++ .../PropertySchemaLessThanRestrictionTest.php | 64 +++++++++++++ .../ValidatorPropertyMetadataFactoryTest.php | 89 +++++++++++++++++++ .../Fixtures/DummyNumericValidatedEntity.php | 75 ++++++++++++++++ 13 files changed, 618 insertions(+) create mode 100644 src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestriction.php create mode 100644 src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestriction.php create mode 100644 src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestriction.php create mode 100644 src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestriction.php create mode 100644 tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestrictionTest.php create mode 100644 tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestrictionTest.php create mode 100644 tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestrictionTest.php create mode 100644 tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestrictionTest.php create mode 100644 tests/Fixtures/DummyNumericValidatedEntity.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ea73b393bdc..c6be371153e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2.7.0 +* JSON Schema: Add support for generating property schema with numeric constraint restrictions (#4225) * JSON Schema: Add support for generating property schema with Collection restriction (#4182) * JSON Schema: Add support for generating property schema format for Url and Hostname (#4185) * JSON Schema: Add support for generating property schema with Count restriction (#4186) diff --git a/src/Bridge/Symfony/Bundle/Resources/config/validator.xml b/src/Bridge/Symfony/Bundle/Resources/config/validator.xml index d05525f5e6c..8e0a2c3f22b 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/validator.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/validator.xml @@ -30,10 +30,26 @@ + + + + + + + + + + + + + + + + diff --git a/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestriction.php b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestriction.php new file mode 100644 index 00000000000..4380b8c140b --- /dev/null +++ b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestriction.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaGreaterThanOrEqualRestriction implements PropertySchemaRestrictionMetadataInterface +{ + /** + * {@inheritdoc} + * + * @param GreaterThanOrEqual $constraint + */ + public function create(Constraint $constraint, PropertyMetadata $propertyMetadata): array + { + return [ + 'minimum' => $constraint->value, + ]; + } + + /** + * {@inheritdoc} + */ + public function supports(Constraint $constraint, PropertyMetadata $propertyMetadata): bool + { + return $constraint instanceof GreaterThanOrEqual && is_numeric($constraint->value) && null !== ($type = $propertyMetadata->getType()) && \in_array($type->getBuiltinType(), [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_FLOAT], true); + } +} diff --git a/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestriction.php b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestriction.php new file mode 100644 index 00000000000..044df1cf7ce --- /dev/null +++ b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestriction.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\GreaterThan; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaGreaterThanRestriction implements PropertySchemaRestrictionMetadataInterface +{ + /** + * {@inheritdoc} + * + * @param GreaterThan $constraint + */ + public function create(Constraint $constraint, PropertyMetadata $propertyMetadata): array + { + return [ + 'minimum' => $constraint->value, + 'exclusiveMinimum' => true, + ]; + } + + /** + * {@inheritdoc} + */ + public function supports(Constraint $constraint, PropertyMetadata $propertyMetadata): bool + { + return $constraint instanceof GreaterThan && is_numeric($constraint->value) && null !== ($type = $propertyMetadata->getType()) && \in_array($type->getBuiltinType(), [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_FLOAT], true); + } +} diff --git a/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestriction.php b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestriction.php new file mode 100644 index 00000000000..592eb8b479e --- /dev/null +++ b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestriction.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\LessThanOrEqual; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaLessThanOrEqualRestriction implements PropertySchemaRestrictionMetadataInterface +{ + /** + * {@inheritdoc} + * + * @param LessThanOrEqual $constraint + */ + public function create(Constraint $constraint, PropertyMetadata $propertyMetadata): array + { + return [ + 'maximum' => $constraint->value, + ]; + } + + /** + * {@inheritdoc} + */ + public function supports(Constraint $constraint, PropertyMetadata $propertyMetadata): bool + { + return $constraint instanceof LessThanOrEqual && is_numeric($constraint->value) && null !== ($type = $propertyMetadata->getType()) && \in_array($type->getBuiltinType(), [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_FLOAT], true); + } +} diff --git a/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestriction.php b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestriction.php new file mode 100644 index 00000000000..cf5c8cca153 --- /dev/null +++ b/src/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestriction.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\LessThan; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaLessThanRestriction implements PropertySchemaRestrictionMetadataInterface +{ + /** + * {@inheritdoc} + * + * @param LessThan $constraint + */ + public function create(Constraint $constraint, PropertyMetadata $propertyMetadata): array + { + return [ + 'maximum' => $constraint->value, + 'exclusiveMaximum' => true, + ]; + } + + /** + * {@inheritdoc} + */ + public function supports(Constraint $constraint, PropertyMetadata $propertyMetadata): bool + { + return $constraint instanceof LessThan && is_numeric($constraint->value) && null !== ($type = $propertyMetadata->getType()) && \in_array($type->getBuiltinType(), [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_FLOAT], true); + } +} diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php index 1f5b861ee64..2d9e3f85ec2 100644 --- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php +++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php @@ -1360,7 +1360,11 @@ private function getBaseContainerBuilderProphecyWithoutDefaultMetadataLoading(ar 'api_platform.metadata.property_schema.choice_restriction', 'api_platform.metadata.property_schema.collection_restriction', 'api_platform.metadata.property_schema.count_restriction', + 'api_platform.metadata.property_schema.greater_than_or_equal_restriction', + 'api_platform.metadata.property_schema.greater_than_restriction', 'api_platform.metadata.property_schema.length_restriction', + 'api_platform.metadata.property_schema.less_than_or_equal_restriction', + 'api_platform.metadata.property_schema.less_than_restriction', 'api_platform.metadata.property_schema.one_of_restriction', 'api_platform.metadata.property_schema.range_restriction', 'api_platform.metadata.property_schema.regex_restriction', diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestrictionTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestrictionTest.php new file mode 100644 index 00000000000..517155ffd4b --- /dev/null +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanOrEqualRestrictionTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaGreaterThanOrEqualRestriction; +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use ApiPlatform\Core\Tests\ProphecyTrait; +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; +use Symfony\Component\Validator\Constraints\Positive; +use Symfony\Component\Validator\Constraints\PositiveOrZero; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaGreaterThanOrEqualRestrictionTest extends TestCase +{ + use ProphecyTrait; + + private $propertySchemaGreaterThanOrEqualRestriction; + + protected function setUp(): void + { + $this->propertySchemaGreaterThanOrEqualRestriction = new PropertySchemaGreaterThanOrEqualRestriction(); + } + + /** + * @dataProvider supportsProvider + */ + public function testSupports(Constraint $constraint, PropertyMetadata $propertyMetadata, bool $expectedResult): void + { + self::assertSame($expectedResult, $this->propertySchemaGreaterThanOrEqualRestriction->supports($constraint, $propertyMetadata)); + } + + public function supportsProvider(): \Generator + { + yield 'supported int' => [new GreaterThanOrEqual(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'supported float' => [new GreaterThanOrEqual(['value' => 10.99]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_FLOAT)), true]; + yield 'supported positive or zero' => [new PositiveOrZero(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'not supported positive' => [new Positive(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + yield 'not supported property path' => [new GreaterThanOrEqual(['propertyPath' => 'greaterThanMe']), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + } + + public function testCreate(): void + { + self::assertSame(['minimum' => 10], $this->propertySchemaGreaterThanOrEqualRestriction->create(new GreaterThanOrEqual(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)))); + } +} diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestrictionTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestrictionTest.php new file mode 100644 index 00000000000..e19669ef2aa --- /dev/null +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaGreaterThanRestrictionTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaGreaterThanRestriction; +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use ApiPlatform\Core\Tests\ProphecyTrait; +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\GreaterThan; +use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; +use Symfony\Component\Validator\Constraints\Positive; +use Symfony\Component\Validator\Constraints\PositiveOrZero; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaGreaterThanRestrictionTest extends TestCase +{ + use ProphecyTrait; + + private $propertySchemaGreaterThanRestriction; + + protected function setUp(): void + { + $this->propertySchemaGreaterThanRestriction = new PropertySchemaGreaterThanRestriction(); + } + + /** + * @dataProvider supportsProvider + */ + public function testSupports(Constraint $constraint, PropertyMetadata $propertyMetadata, bool $expectedResult): void + { + self::assertSame($expectedResult, $this->propertySchemaGreaterThanRestriction->supports($constraint, $propertyMetadata)); + } + + public function supportsProvider(): \Generator + { + yield 'supported int' => [new GreaterThan(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'supported float' => [new GreaterThan(['value' => 10.99]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_FLOAT)), true]; + yield 'supported positive' => [new Positive(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'not supported positive or zero' => [new PositiveOrZero(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + yield 'not supported property path' => [new GreaterThan(['propertyPath' => 'greaterThanMe']), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + } + + public function testCreate(): void + { + self::assertSame([ + 'minimum' => 10, + 'exclusiveMinimum' => true, + ], $this->propertySchemaGreaterThanRestriction->create(new GreaterThanOrEqual(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)))); + } +} diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestrictionTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestrictionTest.php new file mode 100644 index 00000000000..ea97bb04587 --- /dev/null +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanOrEqualRestrictionTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLessThanOrEqualRestriction; +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use ApiPlatform\Core\Tests\ProphecyTrait; +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\LessThanOrEqual; +use Symfony\Component\Validator\Constraints\Negative; +use Symfony\Component\Validator\Constraints\NegativeOrZero; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaLessThanOrEqualRestrictionTest extends TestCase +{ + use ProphecyTrait; + + private $propertySchemaLessThanOrEqualRestriction; + + protected function setUp(): void + { + $this->propertySchemaLessThanOrEqualRestriction = new PropertySchemaLessThanOrEqualRestriction(); + } + + /** + * @dataProvider supportsProvider + */ + public function testSupports(Constraint $constraint, PropertyMetadata $propertyMetadata, bool $expectedResult): void + { + self::assertSame($expectedResult, $this->propertySchemaLessThanOrEqualRestriction->supports($constraint, $propertyMetadata)); + } + + public function supportsProvider(): \Generator + { + yield 'supported int' => [new LessThanOrEqual(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'supported float' => [new LessThanOrEqual(['value' => 10.99]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_FLOAT)), true]; + yield 'supported negative or zero' => [new NegativeOrZero(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'not supported negative' => [new Negative(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + yield 'not supported property path' => [new LessThanOrEqual(['propertyPath' => 'greaterThanMe']), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + } + + public function testCreate(): void + { + self::assertSame(['maximum' => 10], $this->propertySchemaLessThanOrEqualRestriction->create(new LessThanOrEqual(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)))); + } +} diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestrictionTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestrictionTest.php new file mode 100644 index 00000000000..c65d855e3f9 --- /dev/null +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/Restriction/PropertySchemaLessThanRestrictionTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Bridge\Symfony\Validator\Metadata\Property\Restriction; + +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLessThanRestriction; +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; +use ApiPlatform\Core\Tests\ProphecyTrait; +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\LessThan; +use Symfony\Component\Validator\Constraints\Negative; +use Symfony\Component\Validator\Constraints\NegativeOrZero; + +/** + * @author Tomas Norkūnas + */ +final class PropertySchemaLessThanRestrictionTest extends TestCase +{ + use ProphecyTrait; + + private $propertySchemaLessThanRestriction; + + protected function setUp(): void + { + $this->propertySchemaLessThanRestriction = new PropertySchemaLessThanRestriction(); + } + + /** + * @dataProvider supportsProvider + */ + public function testSupports(Constraint $constraint, PropertyMetadata $propertyMetadata, bool $expectedResult): void + { + self::assertSame($expectedResult, $this->propertySchemaLessThanRestriction->supports($constraint, $propertyMetadata)); + } + + public function supportsProvider(): \Generator + { + yield 'supported int' => [new LessThan(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'supported float' => [new LessThan(['value' => 10.99]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_FLOAT)), true]; + yield 'supported negative' => [new Negative(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), true]; + yield 'not supported negative or zero' => [new NegativeOrZero(), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + yield 'not supported property path' => [new LessThan(['propertyPath' => 'greaterThanMe']), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), false]; + } + + public function testCreate(): void + { + self::assertSame([ + 'maximum' => 10, + 'exclusiveMaximum' => true, + ], $this->propertySchemaLessThanRestriction->create(new LessThan(['value' => 10]), new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)))); + } +} diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php index 769b8b523ab..95622b7d699 100644 --- a/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php @@ -17,7 +17,11 @@ use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaCollectionRestriction; use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaCountRestriction; use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaFormat; +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaGreaterThanOrEqualRestriction; +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaGreaterThanRestriction; use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLengthRestriction; +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLessThanOrEqualRestriction; +use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLessThanRestriction; use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaOneOfRestriction; use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRangeRestriction; use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRegexRestriction; @@ -30,6 +34,7 @@ use ApiPlatform\Core\Tests\Fixtures\DummyCompoundValidatedEntity; use ApiPlatform\Core\Tests\Fixtures\DummyCountValidatedEntity; use ApiPlatform\Core\Tests\Fixtures\DummyIriWithValidationEntity; +use ApiPlatform\Core\Tests\Fixtures\DummyNumericValidatedEntity; use ApiPlatform\Core\Tests\Fixtures\DummyRangeValidatedEntity; use ApiPlatform\Core\Tests\Fixtures\DummySequentiallyValidatedEntity; use ApiPlatform\Core\Tests\Fixtures\DummyUniqueValidatedEntity; @@ -646,4 +651,88 @@ public function testCreateWithPropertyCollectionRestriction(): void 'required' => ['name', 'email', 'social'], ], $schema); } + + /** + * @dataProvider provideNumericConstraintCases + */ + public function testCreateWithPropertyNumericRestriction(PropertyMetadata $propertyMetadata, string $property, array $expectedSchema): void + { + $validatorClassMetadata = new ClassMetadata(DummyNumericValidatedEntity::class); + (new AnnotationLoader(new AnnotationReader()))->loadClassMetadata($validatorClassMetadata); + + $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class); + $validatorMetadataFactory->getMetadataFor(DummyNumericValidatedEntity::class) + ->willReturn($validatorClassMetadata) + ->shouldBeCalled(); + + $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); + $decoratedPropertyMetadataFactory->create(DummyNumericValidatedEntity::class, $property, [])->willReturn( + $propertyMetadata + )->shouldBeCalled(); + + $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( + $validatorMetadataFactory->reveal(), $decoratedPropertyMetadataFactory->reveal(), + [ + new PropertySchemaGreaterThanOrEqualRestriction(), + new PropertySchemaGreaterThanRestriction(), + new PropertySchemaLessThanOrEqualRestriction(), + new PropertySchemaLessThanRestriction(), + ] + ); + + $schema = $validationPropertyMetadataFactory->create(DummyNumericValidatedEntity::class, $property)->getSchema(); + + $this->assertSame($expectedSchema, $schema); + } + + public function provideNumericConstraintCases(): \Generator + { + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), + 'property' => 'greaterThanMe', + 'expectedSchema' => ['minimum' => 10, 'exclusiveMinimum' => true], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_FLOAT)), + 'property' => 'greaterThanOrEqualToMe', + 'expectedSchema' => ['minimum' => 10.99], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), + 'property' => 'lessThanMe', + 'expectedSchema' => ['maximum' => 99, 'exclusiveMaximum' => true], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_FLOAT)), + 'property' => 'lessThanOrEqualToMe', + 'expectedSchema' => ['maximum' => 99.33], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), + 'property' => 'positive', + 'expectedSchema' => ['minimum' => 0, 'exclusiveMinimum' => true], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), + 'property' => 'positiveOrZero', + 'expectedSchema' => ['minimum' => 0], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), + 'property' => 'negative', + 'expectedSchema' => ['maximum' => 0, 'exclusiveMaximum' => true], + ]; + + yield [ + 'propertyMetadata' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT)), + 'property' => 'negativeOrZero', + 'expectedSchema' => ['maximum' => 0], + ]; + } } diff --git a/tests/Fixtures/DummyNumericValidatedEntity.php b/tests/Fixtures/DummyNumericValidatedEntity.php new file mode 100644 index 00000000000..83e09ff4dbc --- /dev/null +++ b/tests/Fixtures/DummyNumericValidatedEntity.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Fixtures; + +use Symfony\Component\Validator\Constraints as Assert; + +class DummyNumericValidatedEntity +{ + /** + * @var int + * + * @Assert\GreaterThan(value=10) + */ + public $greaterThanMe; + + /** + * @var float + * + * @Assert\GreaterThanOrEqual(value=10.99) + */ + public $greaterThanOrEqualToMe; + + /** + * @var int + * + * @Assert\LessThan(value=99) + */ + public $lessThanMe; + + /** + * @var float + * + * @Assert\LessThanOrEqual(value=99.33) + */ + public $lessThanOrEqualToMe; + + /** + * @var int + * + * @Assert\Positive + */ + public $positive; + + /** + * @var int + * + * @Assert\PositiveOrZero + */ + public $positiveOrZero; + + /** + * @var int + * + * @Assert\Negative + */ + public $negative; + + /** + * @var int + * + * @Assert\NegativeOrZero + */ + public $negativeOrZero; +}