Skip to content

Commit 530548a

Browse files
committed
Merge branch 'release/0.4.0'
2 parents ef05129 + 9b48c72 commit 530548a

7 files changed

Lines changed: 262 additions & 104 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

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "c0ntax/parsley-bundle",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"type": "symfony-bundle",
55
"description": "A bridge between Symfony and Parsley.js",
66
"license": "Apache-2.0",

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: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,13 @@
44
namespace C0ntax\ParsleyBundle\Factory;
55

66
use C0ntax\ParsleyBundle\Contracts\ConstraintInterface;
7-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Email;
8-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Length;
9-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Max;
10-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\MaxLength;
11-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Min;
12-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\MinLength;
13-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Pattern;
14-
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Required;
7+
use C0ntax\ParsleyBundle\Directive\Field\Constraint as ParsleyConstraint;
158
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
169
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
1710
use Symfony\Component\Form\Extension\Core\Type\DateType;
1811
use Symfony\Component\Form\FormInterface;
1912
use Symfony\Component\Validator\Constraint;
13+
use Symfony\Component\Validator\Constraints as SymfonyConstraint;
2014
use Symfony\Component\Validator\Constraints\AbstractComparison;
2115

2216
/**
@@ -40,71 +34,80 @@ public static function createFromValidationConstraint(
4034
): ?ConstraintInterface {
4135
// TODO Change this to use the ViewInterface instead of the FormInterface as that makes a lot more sense!
4236

43-
if ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Valid) {
37+
if ($validationConstraint instanceof SymfonyConstraint\Valid) {
4438
// This case is not an error. There just isn't a 'like-for-like' replacement
4539
return null;
46-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\NotNull) {
47-
return new Required($validationConstraint->message);
48-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\NotBlank) {
49-
return new Required($validationConstraint->message);
50-
} if ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Length) {
40+
} elseif ($validationConstraint instanceof SymfonyConstraint\NotNull) {
41+
return new ParsleyConstraint\Required($validationConstraint->message);
42+
} elseif ($validationConstraint instanceof SymfonyConstraint\NotBlank) {
43+
return new ParsleyConstraint\Required($validationConstraint->message);
44+
}
45+
if ($validationConstraint instanceof SymfonyConstraint\Length) {
5146
if ($validationConstraint->min !== null && $validationConstraint->max !== null) {
5247
// TODO Pick a better message!
53-
return new Length(
48+
return new ParsleyConstraint\Length(
5449
$validationConstraint->min,
5550
$validationConstraint->max,
5651
self::convertParameters($validationConstraint->exactMessage)
5752
);
5853
} elseif ($validationConstraint->min !== null) {
59-
return new MinLength(
54+
return new ParsleyConstraint\MinLength(
6055
$validationConstraint->min,
6156
self::convertParameters($validationConstraint->minMessage)
6257
);
6358
} else {
64-
return new MaxLength(
59+
return new ParsleyConstraint\MaxLength(
6560
$validationConstraint->max,
6661
self::convertParameters($validationConstraint->maxMessage)
6762
);
6863
}
69-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Regex) {
70-
return new Pattern($validationConstraint->pattern, self::convertParameters($validationConstraint->message));
71-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Email) {
72-
return new Email(self::convertParameters($validationConstraint->message));
64+
} elseif ($validationConstraint instanceof SymfonyConstraint\Regex) {
65+
return new ParsleyConstraint\Pattern($validationConstraint->pattern, self::convertParameters($validationConstraint->message));
66+
} elseif ($validationConstraint instanceof SymfonyConstraint\Email) {
67+
return new ParsleyConstraint\Email(self::convertParameters($validationConstraint->message));
7368
} elseif ($validationConstraint instanceof AbstractComparison) {
7469
// This is an interesting case that requires the context of the form element. If any of these validations
7570
// happen to contain a value that is a string, it is assumed that the string is a dateTime. We should
7671
// only do dateTime evaluations if the field input type is 'date', otherwise Parsley just wont bother!
7772

78-
$innerType = $form->getConfig()->getType()->getInnerType();
79-
8073
if (is_string($validationConstraint->value) && !static::isFormHtml5DateType($form)) {
8174
throw new \RuntimeException('Date evaluation called on a non-DateType field: '.$form->getName());
8275
}
8376

84-
if ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\GreaterThanOrEqual) {
85-
return new Min(
77+
if ($validationConstraint instanceof SymfonyConstraint\GreaterThanOrEqual) {
78+
return new ParsleyConstraint\Min(
8679
static::convertMinMaxValue($validationConstraint->value),
8780
self::convertParameters($validationConstraint->message)
8881
);
89-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\GreaterThan) {
82+
} elseif ($validationConstraint instanceof SymfonyConstraint\GreaterThan) {
9083
// Bit of a trickey one as isn't an analogous Parsley
91-
return new Min(
84+
return new ParsleyConstraint\Min(
9285
static::convertMinMaxValue($validationConstraint->value, true, true),
9386
self::convertParameters($validationConstraint->message)
9487
);
95-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\LessThanOrEqual) {
96-
return new Max(
88+
} elseif ($validationConstraint instanceof SymfonyConstraint\LessThanOrEqual) {
89+
return new ParsleyConstraint\Max(
9790
static::convertMinMaxValue($validationConstraint->value),
9891
self::convertParameters($validationConstraint->message)
9992
);
100-
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\LessThan) {
93+
} elseif ($validationConstraint instanceof SymfonyConstraint\LessThan) {
10194
// Bit of a trickey one as isn't an analogous Parsley
102-
return new Max(
95+
return new ParsleyConstraint\Max(
10396
static::convertMinMaxValue($validationConstraint->value, true, false),
10497
self::convertParameters($validationConstraint->message)
10598
);
10699
}
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+
}
107106

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

110113
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)