Symfony2 Validation Datetime 1 should be before Datetime 2
Solution 1
You could write a custom DateRangeValidator.
class DateRange extends Constraint {
public $message = "daterange.violation.crossing";
public $emptyStartDate = "daterange.violation.startDate";
public $emptyEndDate = "daterange.violation.endDate";
public $hasEndDate = true;
public function getTargets() {
return self::CLASS_CONSTRAINT;
}
public function validatedBy() {
return 'daterange_validator';
}
}
class DateRangeValidator extends ConstraintValidator
{
public function isValid($entity, Constraint $constraint)
{
$hasEndDate = true;
if ($constraint->hasEndDate !== null) {
$hasEndDate = $constraint->hasEndDate;
}
if ($entity->getStartDate() !== null) {
if ($hasEndDate) {
if ($entity->getEndDate() !== null) {
if ($entity->getStartDate() > $entity->getEndDate()) {
$this->setMessage($constraint->message);
return false;
}
return true;
} else {
$this->setMessage($constraint->emptyEndDate);
return false;
}
} else {
if ($entity->getEndDate() !== null) {
if ($entity->getStartDate() > $entity->getEndDate()) {
$this->setMessage($constraint->message);
return false;
}
}
return true;
}
} else {
$this->setMessage($constraint->emptyStartDate);
return false;
}
}
register it as a service:
parameters:
register.daterange.validator.class: XXX\FormExtensionsBundle\Validator\Constraints\DateRangeValidator
services:
daterange.validator:
class: %register.daterange.validator.class%
tags:
- { name: validator.constraint_validator, alias: daterange_validator }
And use it in your Entity:
use XXX\FormExtensionsBundle\Validator\Constraints as FormAssert;
/**
*
* @FormAssert\DateRange()
*/
class Contact extends Entity
{
private $startDate;
private $endDate;
}
Eventhough it seems a bit much for a simple thing like that, but experience shows, that one needs a date range validator more often than just once.
Solution 2
You could add a validation getter to the entity - Symfony2 Validation Getters
In your validation
Acme\YourBundle\Entity\Employment:
getters:
datesValid:
- "True": { message: "The start date must be before the end date" }
And then in your entity
public function isDatesValid()
{
return ($this->startDate < $this->endDate);
}
Solution 3
There is Yet Another Solution: Validation by using Expression Language:
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Column(type="date", nullable=true)
* @Assert\Date()
*/
private $startDate;
/**
* @ORM\Column(type="date", nullable=true)
* @Assert\Date()
* @Assert\Expression(
* "this.getStartDate() < this.getEndDate()",
* message="The end date must be after the start date"
* )
*/
private $endDate;
You can add this constraint to $startDate
if you want.
Related videos on Youtube
Simon
Updated on June 03, 2022Comments
-
Simon almost 2 years
I'm looking through the Symfony2 Validation Reference but I'm not finding what I need.
I have a class Employment with a StartDate and EndDate. I would like to add an \@Assert() where it verifies that StartDate is always BEFORE EndDate. Is there a standard way of comparing class attributes as a Validation Constraint or should I create a custom validation constraint?
class Employment { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") * @Expose() */ protected $id; /** * @ORM\Column(type="datetime") * @Expose() * @Assert\DateTime() */ protected $startDate; /** * @ORM\Column(type="datetime", nullable=TRUE) * @Expose() * @Assert\DateTime() */ protected $endDate; ... }
-
Simon about 11 yearsThank you for reminding me of this approach and possibility. I've accepted the other reply as the answer because of reuseability.
-
qooplmao about 11 yearsYeah, I prefer the other one too.
-
qooplmao over 9 yearsI know this is quite old but I keep getting notifications about it so this may be of some use to some people. There is now (there may have been before but I don't remember) a pre-built version of this constraint in the
PUGXExtraValidatorBundle
(github.com/PUGX/PUGXExtraValidatorBundle/blob/master/Resources/…). -
Benjamin Lucas about 9 yearsNew in dev and symfony, where $constraint->hasEndDate comes ? Is there an hasEndDate method in $constraint ? Or should I create it in my entity ? And where is the return message ? Thank you for this solution.
-
DerStoffel about 9 years@BenjaminLucas I added the missing fields in the code above. Thanks for the hint.
-
Scaramouche almost 9 yearswhat should I use to use this class u propose?
-
Cassiano almost 8 yearsless code, less maintenance. Thanks for the simple solution.
-
Adib Aroui over 7 years@Simon, please to explain to me what do you mean by reusability here, thanks a lot in advance
-
Simon over 7 years@whitelettersinblankpapers As opposed to the accepted answer this answer can only be used in this entity; If you want to use the same validator against other entities you'll have to write the same code again for your other entities. This is against the DRY principle. The accepted answer registers the validator as a service so it can be easily reused and shared between other entities.
-
Adib Aroui over 7 years@Simon, thank you very much Sir, now I understand :)
-
Rubinum almost 7 yearsthis answer is way easier and perfect for this requirements.