Skip to content

Commit 5409bd3

Browse files
committed
Added Range support
1 parent 98983fc commit 5409bd3

6 files changed

Lines changed: 240 additions & 74 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ Since this library is very much alpha, I haven't had time to add all the [valida
5454
* Max
5555
* Min
5656
* Required
57+
* Range
58+
59+
## Specific Validaton Notes
60+
61+
Sometimes there is not a 1-2-1 mapping of Symfony error messages to Parsley. This is because with Parsley, you supply only one error message for the validator which is then displayed at runtime, whereas with Symfony constraints, they can pick a specific error message based on what didn't validate. Listed here are any Symfony validators where I've had to pick a specific error message that you should override using the ConstraintErrorMessage directive (so that if server based validations kick in, they will still have a message that makes sense)
62+
63+
* Range
5764
5865
## Usage
5966

src/Directive/Field/Constraint/AbstractComparison.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ abstract class AbstractComparison extends AbstractConstraint
1616
/**
1717
* Min constructor.
1818
*
19-
* @param \DateTime|float|int $min
19+
* @param \DateTime|float|int $value
2020
* @param string|null $errorMessage
2121
* @throws \InvalidArgumentException
2222
*/
23-
public function __construct($min, string $errorMessage = null)
23+
public function __construct($value, string $errorMessage = null)
2424
{
25-
$this->setValue($min);
25+
$this->setValue($value);
2626
parent::__construct($errorMessage);
2727
}
2828

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace C0ntax\ParsleyBundle\Directive\Field\Constraint;
5+
6+
/**
7+
* Class Range
8+
*
9+
* @package C0ntax\ParsleyBundle\Directive\Field\Constraint
10+
*/
11+
class Range extends AbstractConstraint
12+
{
13+
/** @var int|float|\DateTime|\DateTimeImmutable */
14+
private $min;
15+
16+
/** @var int|float|\DateTime|\DateTimeImmutable */
17+
private $max;
18+
19+
/**
20+
* Range constructor.
21+
*
22+
* @param int|float|\DateTime|\DateTimeImmutable $min
23+
* @param int|float|\DateTime|\DateTimeImmutable $max
24+
* @param null|string $errorMessageString
25+
* @throws \InvalidArgumentException
26+
*/
27+
public function __construct($min, $max, ?string $errorMessageString = null)
28+
{
29+
$this->setMin($min);
30+
$this->setMax($max);
31+
parent::__construct($errorMessageString);
32+
}
33+
34+
/**
35+
* @return string
36+
*/
37+
public static function getConstraintId(): string
38+
{
39+
return 'range';
40+
}
41+
42+
/**
43+
* @return array
44+
*/
45+
public function getViewAttr(): array
46+
{
47+
$minValue = $this->createStringValue($this->getMin());
48+
$maxValue = $this->createStringValue($this->getMax());
49+
50+
return $this->getMergedViewAttr('["'.$minValue.'", "'.$maxValue.'"]');
51+
}
52+
53+
/**
54+
* @param $value
55+
* @return string
56+
*/
57+
private function createStringValue($value): string
58+
{
59+
if ($value instanceof \DateTime || $value instanceof \DateTimeImmutable) {
60+
return $value->format('Y-m-d H:i:s');
61+
} else {
62+
return (string) $value;
63+
}
64+
}
65+
66+
/**
67+
* @return \DateTime|\DateTimeImmutable|float|int
68+
*/
69+
private function getMin()
70+
{
71+
return $this->min;
72+
}
73+
74+
/**
75+
* @param \DateTime|\DateTimeImmutable|float|int $min
76+
* @return Range
77+
*/
78+
private function setMin($min): Range
79+
{
80+
$this->min = $min;
81+
82+
return $this;
83+
}
84+
85+
/**
86+
* @return \DateTime|\DateTimeImmutable|float|int
87+
*/
88+
private function getMax()
89+
{
90+
return $this->max;
91+
}
92+
93+
/**
94+
* @param \DateTime|\DateTimeImmutable|float|int $max
95+
* @return Range
96+
*/
97+
private function setMax($max): Range
98+
{
99+
$this->max = $max;
100+
101+
return $this;
102+
}
103+
}

src/Factory/ConstraintFactory.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ public static function createFromValidationConstraint(
3434
): ?ConstraintInterface {
3535
// TODO Change this to use the ViewInterface instead of the FormInterface as that makes a lot more sense!
3636

37-
if ($validationConstraint instanceof SymfonyConstraint\Valid) {
37+
if ($validationConstraint instanceof SymfonyConstraint\Valid) {
3838
// This case is not an error. There just isn't a 'like-for-like' replacement
3939
return null;
4040
} elseif ($validationConstraint instanceof SymfonyConstraint\NotNull) {
4141
return new ParsleyConstraint\Required($validationConstraint->message);
4242
} elseif ($validationConstraint instanceof SymfonyConstraint\NotBlank) {
4343
return new ParsleyConstraint\Required($validationConstraint->message);
44-
} if ($validationConstraint instanceof SymfonyConstraint\Length) {
44+
}
45+
if ($validationConstraint instanceof SymfonyConstraint\Length) {
4546
if ($validationConstraint->min !== null && $validationConstraint->max !== null) {
4647
// TODO Pick a better message!
4748
return new ParsleyConstraint\Length(
@@ -96,7 +97,17 @@ public static function createFromValidationConstraint(
9697
self::convertParameters($validationConstraint->message)
9798
);
9899
}
100+
} elseif ($validationConstraint instanceof SymfonyConstraint\Range) {
101+
// No error message translation here
102+
103+
if (is_string($validationConstraint->min) && !static::isFormHtml5DateType($form)) {
104+
throw new \RuntimeException('Date evaluation called on a non-DateType field: '.$form->getName());
105+
}
99106

107+
return new ParsleyConstraint\Range(
108+
static::convertMinMaxValue($validationConstraint->min),
109+
static::convertMinMaxValue($validationConstraint->max)
110+
);
100111
}
101112

102113
throw new \RuntimeException('Unsupported Symfony Constraint: '.get_class($validationConstraint));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace C0ntax\ParsleyBundle\Tests\Directive\Field\Constraint;
4+
5+
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Range;
6+
7+
class RangeTest extends \PHPUnit_Framework_TestCase
8+
{
9+
10+
public function testGetConstraintId()
11+
{
12+
self::assertEquals('range', Range::getConstraintId());
13+
}
14+
15+
public function testGetViewAttr()
16+
{
17+
$pattern = new Range(1, 10);
18+
self::assertEquals(['data-parsley-range' => '["1", "10"]'], $pattern->getViewAttr());
19+
20+
$pattern = new Range(1, 10, 'Error message');
21+
self::assertEquals(['data-parsley-range' => '["1", "10"]', 'data-parsley-range-message' => 'Error message'], $pattern->getViewAttr());
22+
23+
$minDate = (new \DateTime('now'))->sub(new \DateInterval('P2W'));
24+
$maxDate = (new \DateTime('now'))->add(new \DateInterval('P2W'));
25+
26+
$minDateString = $minDate->format('Y-m-d H:i:s');
27+
$maxDateString = $maxDate->format('Y-m-d H:i:s');
28+
29+
$pattern = new Range($minDate, $maxDate, 'Error message');
30+
self::assertEquals(['data-parsley-range' => '["'.$minDateString.'", "'.$maxDateString.'"]', 'data-parsley-range-message' => 'Error message'], $pattern->getViewAttr());
31+
}
32+
}

0 commit comments

Comments
 (0)