mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 23:59:26 +03:00
Added support for constraint attributes
This commit is contained in:
parent
8f646b8484
commit
16221de418
@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\ModelDescriber\Annotations;
|
|||||||
use Doctrine\Common\Annotations\Reader;
|
use Doctrine\Common\Annotations\Reader;
|
||||||
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
|
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,16 +39,12 @@ class SymfonyConstraintAnnotationReader
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the given property and schema with defined Symfony constraints.
|
* Update the given property and schema with defined Symfony constraints.
|
||||||
|
*
|
||||||
|
* @param \ReflectionProperty|\ReflectionMethod $reflection
|
||||||
*/
|
*/
|
||||||
public function updateProperty($reflection, OA\Property $property): void
|
public function updateProperty($reflection, OA\Property $property): void
|
||||||
{
|
{
|
||||||
if ($reflection instanceof \ReflectionProperty) {
|
foreach ($this->getAnnotations($reflection) as $annotation) {
|
||||||
$annotations = $this->annotationsReader->getPropertyAnnotations($reflection);
|
|
||||||
} else {
|
|
||||||
$annotations = $this->annotationsReader->getMethodAnnotations($reflection);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($annotations as $annotation) {
|
|
||||||
if ($annotation instanceof Assert\NotBlank || $annotation instanceof Assert\NotNull) {
|
if ($annotation instanceof Assert\NotBlank || $annotation instanceof Assert\NotNull) {
|
||||||
// To support symfony/validator < 4.3
|
// To support symfony/validator < 4.3
|
||||||
if ($annotation instanceof Assert\NotBlank && \property_exists($annotation, 'allowNull') && $annotation->allowNull) {
|
if ($annotation instanceof Assert\NotBlank && \property_exists($annotation, 'allowNull') && $annotation->allowNull) {
|
||||||
@ -133,7 +130,7 @@ class SymfonyConstraintAnnotationReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ReflectionProperty|ReflectionClass
|
* @param \ReflectionProperty|\ReflectionMethod $reflection
|
||||||
*/
|
*/
|
||||||
private function applyEnumFromChoiceConstraint(OA\Schema $property, Assert\Choice $choice, $reflection): void
|
private function applyEnumFromChoiceConstraint(OA\Schema $property, Assert\Choice $choice, $reflection): void
|
||||||
{
|
{
|
||||||
@ -150,4 +147,22 @@ class SymfonyConstraintAnnotationReader
|
|||||||
|
|
||||||
$setEnumOnThis->enum = array_values($enumValues);
|
$setEnumOnThis->enum = array_values($enumValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \ReflectionProperty|\ReflectionMethod $reflection
|
||||||
|
*/
|
||||||
|
private function getAnnotations($reflection): \Traversable
|
||||||
|
{
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
foreach ($reflection->getAttributes(Constraint::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
|
||||||
|
yield $attribute->newInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reflection instanceof \ReflectionProperty) {
|
||||||
|
yield from $this->annotationsReader->getPropertyAnnotations($reflection);
|
||||||
|
} elseif ($reflection instanceof \ReflectionMethod) {
|
||||||
|
yield from $this->annotationsReader->getMethodAnnotations($reflection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,24 +47,16 @@ class SymfonyConstraintAnnotationReaderTest extends TestCase
|
|||||||
$this->assertEquals($schema->required, ['property1', 'property2']);
|
$this->assertEquals($schema->required, ['property1', 'property2']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testOptionalProperty()
|
/**
|
||||||
|
* @param object $entity
|
||||||
|
* @dataProvider provideOptionalProperty
|
||||||
|
*/
|
||||||
|
public function testOptionalProperty($entity)
|
||||||
{
|
{
|
||||||
if (!\property_exists(Assert\NotBlank::class, 'allowNull')) {
|
if (!\property_exists(Assert\NotBlank::class, 'allowNull')) {
|
||||||
$this->markTestSkipped('NotBlank::allowNull was added in symfony/validator 4.3.');
|
$this->markTestSkipped('NotBlank::allowNull was added in symfony/validator 4.3.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$entity = new class() {
|
|
||||||
/**
|
|
||||||
* @Assert\NotBlank(allowNull = true)
|
|
||||||
* @Assert\Length(min = 1)
|
|
||||||
*/
|
|
||||||
private $property1;
|
|
||||||
/**
|
|
||||||
* @Assert\NotBlank()
|
|
||||||
*/
|
|
||||||
private $property2;
|
|
||||||
};
|
|
||||||
|
|
||||||
$schema = new OA\Schema([]);
|
$schema = new OA\Schema([]);
|
||||||
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
||||||
$schema->merge([new OA\Property(['property' => 'property2'])]);
|
$schema->merge([new OA\Property(['property' => 'property2'])]);
|
||||||
@ -79,21 +71,37 @@ class SymfonyConstraintAnnotationReaderTest extends TestCase
|
|||||||
$this->assertEquals($schema->required, ['property2']);
|
$this->assertEquals($schema->required, ['property2']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAssertChoiceResultsInNumericArray()
|
public function provideOptionalProperty(): iterable
|
||||||
{
|
{
|
||||||
define('TEST_ASSERT_CHOICE_STATUSES', [
|
yield 'Annotations' => [new class() {
|
||||||
1 => 'active',
|
|
||||||
2 => 'blocked',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$entity = new class() {
|
|
||||||
/**
|
/**
|
||||||
|
* @Assert\NotBlank(allowNull = true)
|
||||||
* @Assert\Length(min = 1)
|
* @Assert\Length(min = 1)
|
||||||
* @Assert\Choice(choices=TEST_ASSERT_CHOICE_STATUSES)
|
|
||||||
*/
|
*/
|
||||||
private $property1;
|
private $property1;
|
||||||
};
|
/**
|
||||||
|
* @Assert\NotBlank()
|
||||||
|
*/
|
||||||
|
private $property2;
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
yield 'Attributes' => [new class() {
|
||||||
|
#[Assert\NotBlank(allowNull: true)]
|
||||||
|
#[Assert\Length(min: 1)]
|
||||||
|
private $property1;
|
||||||
|
#[Assert\NotBlank]
|
||||||
|
private $property2;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $entity
|
||||||
|
* @dataProvider provideAssertChoiceResultsInNumericArray
|
||||||
|
*/
|
||||||
|
public function testAssertChoiceResultsInNumericArray($entity)
|
||||||
|
{
|
||||||
$schema = new OA\Schema([]);
|
$schema = new OA\Schema([]);
|
||||||
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
||||||
|
|
||||||
@ -106,15 +114,36 @@ class SymfonyConstraintAnnotationReaderTest extends TestCase
|
|||||||
$this->assertEquals($schema->properties[0]->enum, ['active', 'blocked']);
|
$this->assertEquals($schema->properties[0]->enum, ['active', 'blocked']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMultipleChoiceConstraintsApplyEnumToItems()
|
public function provideAssertChoiceResultsInNumericArray(): iterable
|
||||||
{
|
{
|
||||||
$entity = new class() {
|
define('TEST_ASSERT_CHOICE_STATUSES', [
|
||||||
|
1 => 'active',
|
||||||
|
2 => 'blocked',
|
||||||
|
]);
|
||||||
|
|
||||||
|
yield 'Annotations' => [new class() {
|
||||||
/**
|
/**
|
||||||
* @Assert\Choice(choices={"one", "two"}, multiple=true)
|
* @Assert\Length(min = 1)
|
||||||
|
* @Assert\Choice(choices=TEST_ASSERT_CHOICE_STATUSES)
|
||||||
*/
|
*/
|
||||||
private $property1;
|
private $property1;
|
||||||
};
|
}];
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
yield 'Attributes' => [new class() {
|
||||||
|
#[Assert\Length(min: 1)]
|
||||||
|
#[Assert\Choice(choices: TEST_ASSERT_CHOICE_STATUSES)]
|
||||||
|
private $property1;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $entity
|
||||||
|
* @dataProvider provideMultipleChoiceConstraintsApplyEnumToItems
|
||||||
|
*/
|
||||||
|
public function testMultipleChoiceConstraintsApplyEnumToItems($entity)
|
||||||
|
{
|
||||||
$schema = new OA\Schema([]);
|
$schema = new OA\Schema([]);
|
||||||
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
||||||
|
|
||||||
@ -127,18 +156,30 @@ class SymfonyConstraintAnnotationReaderTest extends TestCase
|
|||||||
$this->assertEquals($schema->properties[0]->items->enum, ['one', 'two']);
|
$this->assertEquals($schema->properties[0]->items->enum, ['one', 'two']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function provideMultipleChoiceConstraintsApplyEnumToItems(): iterable
|
||||||
* @group https://github.com/nelmio/NelmioApiDocBundle/issues/1780
|
|
||||||
*/
|
|
||||||
public function testLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet()
|
|
||||||
{
|
{
|
||||||
$entity = new class() {
|
yield 'Annotations' => [new class() {
|
||||||
/**
|
/**
|
||||||
* @Assert\Length(min = 1)
|
* @Assert\Choice(choices={"one", "two"}, multiple=true)
|
||||||
*/
|
*/
|
||||||
private $property1;
|
private $property1;
|
||||||
};
|
}];
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
yield 'Attributes' => [new class() {
|
||||||
|
#[Assert\Choice(choices: ['one', 'two'], multiple: true)]
|
||||||
|
private $property1;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $entity
|
||||||
|
* @group https://github.com/nelmio/NelmioApiDocBundle/issues/1780
|
||||||
|
* @dataProvider provideLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet
|
||||||
|
*/
|
||||||
|
public function testLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet($entity)
|
||||||
|
{
|
||||||
$schema = new OA\Schema([]);
|
$schema = new OA\Schema([]);
|
||||||
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
||||||
|
|
||||||
@ -151,18 +192,30 @@ class SymfonyConstraintAnnotationReaderTest extends TestCase
|
|||||||
$this->assertSame(1, $schema->properties[0]->minLength);
|
$this->assertSame(1, $schema->properties[0]->minLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function provideLengthConstraintDoesNotSetMaxLengthIfMaxIsNotSet(): iterable
|
||||||
* @group https://github.com/nelmio/NelmioApiDocBundle/issues/1780
|
|
||||||
*/
|
|
||||||
public function testLengthConstraintDoesNotSetMinLengthIfMinIsNotSet()
|
|
||||||
{
|
{
|
||||||
$entity = new class() {
|
yield 'Annotations' => [new class() {
|
||||||
/**
|
/**
|
||||||
* @Assert\Length(max = 100)
|
* @Assert\Length(min = 1)
|
||||||
*/
|
*/
|
||||||
private $property1;
|
private $property1;
|
||||||
};
|
}];
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
yield 'Attributes' => [new class() {
|
||||||
|
#[Assert\Length(min: 1)]
|
||||||
|
private $property1;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $entity
|
||||||
|
* @group https://github.com/nelmio/NelmioApiDocBundle/issues/1780
|
||||||
|
* @dataProvider provideLengthConstraintDoesNotSetMinLengthIfMinIsNotSet
|
||||||
|
*/
|
||||||
|
public function testLengthConstraintDoesNotSetMinLengthIfMinIsNotSet($entity)
|
||||||
|
{
|
||||||
$schema = new OA\Schema([]);
|
$schema = new OA\Schema([]);
|
||||||
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
$schema->merge([new OA\Property(['property' => 'property1'])]);
|
||||||
|
|
||||||
@ -174,4 +227,21 @@ class SymfonyConstraintAnnotationReaderTest extends TestCase
|
|||||||
$this->assertSame(OA\UNDEFINED, $schema->properties[0]->minLength);
|
$this->assertSame(OA\UNDEFINED, $schema->properties[0]->minLength);
|
||||||
$this->assertSame(100, $schema->properties[0]->maxLength);
|
$this->assertSame(100, $schema->properties[0]->maxLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideLengthConstraintDoesNotSetMinLengthIfMinIsNotSet(): iterable
|
||||||
|
{
|
||||||
|
yield 'Annotations' => [new class() {
|
||||||
|
/**
|
||||||
|
* @Assert\Length(max = 100)
|
||||||
|
*/
|
||||||
|
private $property1;
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 80000) {
|
||||||
|
yield 'Attributes' => [new class() {
|
||||||
|
#[Assert\Length(max: 100)]
|
||||||
|
private $property1;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user