Symfony2 provides a date validator and a range validator for integers but no range validator for dates.
We’re going to implement one in this post.
Implement the Constraint class
Acme/DemoBundle/Validator/Constraints/DateRange.php
<?php
namespace Acme\DemoBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\MissingOptionsException;
/**
* @Annotation
*/
class DateRange extends Constraint
{
public $minMessage = 'This date should be greater than {{ limit }}.';
public $maxMessage = 'This date should be less than {{ limit }}.';
public $invalidMessage = 'This value should be a valid date.';
public $min;
public $max;
public function __construct($options = null)
{
parent::__construct($options);
if (null === $this->min && null === $this->max) {
throw new MissingOptionsException('Either option "min" or "max" must be given for constraint ' . __CLASS__, array('min', 'max'));
}
if (null !== $this->min) {
$this->min = new \DateTime($this->min);
}
if (null !== $this->max) {
$this->max = new \DateTime($this->max);
}
}
}
Implement the Validator class
Acme/DemoBundle/Validator/Constraints/DateRangeValidator.php
<?php
namespace Acme\DemoBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class DateRangeValidator extends ConstraintValidator
{
/**
* {@inheritDoc}
*/
public function validate($value, Constraint $constraint)
{
if (null === $value) {
return;
}
if (!($value instanceof \DateTime)) {
$this->context->addViolation($constraint->invalidMessage, array(
'{{ value }}' => $value,
));
return;
}
if (null !== $constraint->max && $value > $constraint->max) {
$this->context->addViolation($constraint->maxMessage, array(
'{{ value }}' => $value,
'{{ limit }}' => $this->formatDate($constraint->max),
));
}
if (null !== $constraint->min && $value < $constraint->min) {
$this->context->addViolation($constraint->minMessage, array(
'{{ value }}' => $value,
'{{ limit }}' => $this->formatDate($constraint->min),
));
}
}
protected function formatDate($date)
{
$formatter = new \IntlDateFormatter(
null,
\IntlDateFormatter::SHORT,
\IntlDateFormatter::NONE,
date_default_timezone_get(),
\IntlDateFormatter::GREGORIAN
);
return $this->processDate($formatter, $date);
}
/**
* @param \IntlDateFormatter $formatter
* @param \Datetime $date
* @return string
*/
protected function processDate(\IntlDateFormatter $formatter, \Datetime $date)
{
return $formatter->format((int) $date->format('U'));
}
}
Use it
The min
and max
attributes can be set to any value the PHP DateTime
class can parse (see http://www.php.net/manual/en/datetime.formats.php)
If you use the YAML format for configuration file, here is an example of how to use the validator:
src/Acme/DemoBundle/Resources/config/validation.yml
:
Acme\DemoBundle\Entity\AnEntity:
properties:
my_date_field:
- Date: ~
- Acme\DemoBundle\Validator\Constraints\DateRange:
min: "today"
max: "2014-03-20"