Skip to content

Commit

Permalink
Fix wrong detection of OA min/max for symfony contraints with datetim…
Browse files Browse the repository at this point in the history
…e strings (#2148)

* Fix symfony range and comparison constraints can compare datetime strings

If the constraints contain a comparison value that is not int (e.g. datetime string), we cannot infer a OpenAPI value for it. This falsely casted those to int resulting in nonesense like minimum=0 and maximum=0 for string values.

* add tests for comparison constraints on date

---------

Co-authored-by: DjordyKoert <djordy.koert@yoursurprise.com>
  • Loading branch information
Tobion and DjordyKoert committed Jan 2, 2024
1 parent 0dae4c0 commit bef8b65
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 10 deletions.
28 changes: 18 additions & 10 deletions ModelDescriber/Annotations/SymfonyConstraintAnnotationReader.php
Expand Up @@ -107,22 +107,30 @@ private function processPropertyAnnotations($reflection, OA\Property $property,
} elseif ($annotation instanceof Assert\Choice) {
$this->applyEnumFromChoiceConstraint($property, $annotation, $reflection);
} elseif ($annotation instanceof Assert\Range) {
if (isset($annotation->min)) {
$property->minimum = (int) $annotation->min;
if (\is_int($annotation->min)) {
$property->minimum = $annotation->min;
}
if (isset($annotation->max)) {
$property->maximum = (int) $annotation->max;
if (\is_int($annotation->max)) {
$property->maximum = $annotation->max;
}
} elseif ($annotation instanceof Assert\LessThan) {
$property->exclusiveMaximum = true;
$property->maximum = (int) $annotation->value;
if (\is_int($annotation->value)) {
$property->exclusiveMaximum = true;
$property->maximum = $annotation->value;
}
} elseif ($annotation instanceof Assert\LessThanOrEqual) {
$property->maximum = (int) $annotation->value;
if (\is_int($annotation->value)) {
$property->maximum = $annotation->value;
}
} elseif ($annotation instanceof Assert\GreaterThan) {
$property->exclusiveMinimum = true;
$property->minimum = (int) $annotation->value;
if (\is_int($annotation->value)) {
$property->exclusiveMinimum = true;
$property->minimum = $annotation->value;
}
} elseif ($annotation instanceof Assert\GreaterThanOrEqual) {
$property->minimum = (int) $annotation->value;
if (\is_int($annotation->value)) {
$property->minimum = $annotation->value;
}
}
}
}
Expand Down
49 changes: 49 additions & 0 deletions Tests/Functional/Entity/SymfonyConstraints80.php
Expand Up @@ -96,20 +96,69 @@ class SymfonyConstraints80
*/
private $propertyRange;

/**
* @var \DateTimeImmutable
*
* @Assert\Range(min="now", max="+5 hours")
*/
public $propertyRangeDate;

/**
* @var int
*
* @Assert\LessThan(42)
*/
private $propertyLessThan;

/**
* @var \DateTimeImmutable
*
* @Assert\LessThan("now")
*/
public $propertyLessThanDate;

/**
* @var int
*
* @Assert\LessThanOrEqual(23)
*/
private $propertyLessThanOrEqual;

/**
* @var \DateTimeImmutable
*
* @Assert\LessThanOrEqual("now")
*/
public $propertyLessThanOrEqualDate;

/**
* @var int
*
* @Assert\GreaterThan(42)
*/
public $propertyGreaterThan;

/**
* @var \DateTimeImmutable
*
* @Assert\GreaterThan("now")
*/
public $propertyGreaterThanDate;

/**
* @var int
*
* @Assert\GreaterThanOrEqual(23)
*/
public $propertyGreaterThanOrEqual;

/**
* @var \DateTimeImmutable
*
* @Assert\GreaterThanOrEqual("now")
*/
public $propertyGreaterThanOrEqualDate;

/**
* @var int
*
Expand Down
42 changes: 42 additions & 0 deletions Tests/Functional/Entity/SymfonyConstraints81.php
Expand Up @@ -85,18 +85,60 @@ class SymfonyConstraints81
#[Assert\Range(min: 1, max: 5)]
private $propertyRange;

/**
* @var \DateTimeImmutable
*/
#[Assert\Range(min: 'now', max: '+5 hours')]
public $propertyRangeDate;

/**
* @var int
*/
#[Assert\LessThan(42)]
private $propertyLessThan;

/**
* @var \DateTimeImmutable
*/
#[Assert\LessThan('now')]
public $propertyLessThanDate;

/**
* @var int
*/
#[Assert\LessThanOrEqual(23)]
private $propertyLessThanOrEqual;

/**
* @var \DateTimeImmutable
*/
#[Assert\LessThanOrEqual('now')]
public $propertyLessThanOrEqualDate;

/**
* @var int
*/
#[Assert\GreaterThan(42)]
public $propertyGreaterThan;

/**
* @var \DateTimeImmutable
*/
#[Assert\GreaterThan('now')]
public $propertyGreaterThanDate;

/**
* @var int
*/
#[Assert\GreaterThanOrEqual(23)]
public $propertyGreaterThanOrEqual;

/**
* @var \DateTimeImmutable
*/
#[Assert\GreaterThanOrEqual('now')]
public $propertyGreaterThanOrEqualDate;

/**
* @var int
*/
Expand Down
36 changes: 36 additions & 0 deletions Tests/Functional/FunctionalTest.php
Expand Up @@ -457,8 +457,15 @@ public function testSymfonyConstraintDocumentation()
'propertyChoiceWithMultiple',
'propertyExpression',
'propertyRange',
'propertyRangeDate',
'propertyLessThan',
'propertyLessThanDate',
'propertyLessThanOrEqual',
'propertyLessThanOrEqualDate',
'propertyGreaterThan',
'propertyGreaterThanDate',
'propertyGreaterThanOrEqual',
'propertyGreaterThanOrEqualDate',
],
'properties' => [
'propertyNotBlank' => [
Expand Down Expand Up @@ -510,18 +517,47 @@ public function testSymfonyConstraintDocumentation()
'maximum' => 5,
'minimum' => 1,
],
'propertyRangeDate' => [
'type' => 'string',
'format' => 'date-time',
],
'propertyLessThan' => [
'type' => 'integer',
'exclusiveMaximum' => true,
'maximum' => 42,
],
'propertyLessThanDate' => [
'type' => 'string',
'format' => 'date-time',
],
'propertyLessThanOrEqual' => [
'type' => 'integer',
'maximum' => 23,
],
'propertyLessThanOrEqualDate' => [
'type' => 'string',
'format' => 'date-time',
],
'propertyWithCompoundValidationRule' => [
'type' => 'integer',
],
'propertyGreaterThan' => [
'type' => 'integer',
'exclusiveMinimum' => true,
'minimum' => 42,
],
'propertyGreaterThanDate' => [
'type' => 'string',
'format' => 'date-time',
],
'propertyGreaterThanOrEqual' => [
'type' => 'integer',
'minimum' => 23,
],
'propertyGreaterThanOrEqualDate' => [
'type' => 'string',
'format' => 'date-time',
],
],
'type' => 'object',
'schema' => $modelName,
Expand Down

0 comments on commit bef8b65

Please sign in to comment.