Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate a property dependent on another property in Symfony 2

Is it possible to validate a property of a model class dependent on another property of the same class?

For example, I have this class:

class Conference
{
    /** $startDate datetime */
    protected $startDate;

    /** $endDate datetime */
    protected $endDate;
}

and I want that Symfony 2.0 validates, that $startDate has to be after $endDate.

Is this possible by annotations or do I have to do this manually?

like image 800
Johannes Klauß Avatar asked Sep 04 '12 09:09

Johannes Klauß


4 Answers

Starting from Symfony 2.4 you can also use Expression validation constraint to achieve what you need. I do believe, that this is the most simple way to do this. It's more convenient than Callback constraint for sure.

Here's example of how you can update your model class with validation constraints annotations:

use Symfony\Component\Validator\Constraints as Assert;


class Conference
{
    /**
     * @var \DateTime
     *
     * @Assert\Expression(
     *     "this.startDate <= this.endDate",
     *     message="Start date should be less or equal to end date!"
     * )
     */
    protected $startDate;

    /**
     * @var \DateTime
     *
     * @Assert\Expression(
     *     "this.endDate >= this.startDate",
     *     message="End date should be greater or equal to start date!"
     * )
     */
    protected $endDate;
}

Don't forget to enable annotations in your project configuration.

You can always do even more complex validations by using expression syntax.

like image 121
Slava Fomin II Avatar answered Nov 20 '22 14:11

Slava Fomin II


Yes with the callback validator: http://symfony.com/doc/current/reference/constraints/Callback.html

On symfony 2.0:

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\ExecutionContext;

/**
 * @Assert\Callback(methods={"isDateValid"})
 */
class Conference
{

    // Properties, getter, setter ...

    public function isDateValid(ExecutionContext $context)
    {
        if ($this->startDate->getTimestamp() > $this->endDate->getTimestamp()) {
                $propertyPath = $context->getPropertyPath() . '.startDate';
                $context->setPropertyPath($propertyPath);
                $context->addViolation('The starting date must be anterior than the ending date !', array(), null);
        }
    }
}

On symfony master version:

    public function isDateValid(ExecutionContext $context)
    {
        if ($this->startDate->getTimestamp() > $this->endDate->getTimestamp()) {
            $context->addViolationAtSubPath('startDate', 'The starting date must be anterior than the ending date !', array(), null);
        }
    }

Here I choose to show the error message on the startDate field.

like image 31
Sybio Avatar answered Nov 20 '22 12:11

Sybio


Another way (at least as of Symfony 2.3) is to use simple @Assert\IsTrue:

class Conference
{
    //...

    /**
     * @Assert\IsTrue(message = "Startime should be lesser than EndTime")
     */
    public function isStartBeforeEnd()
    {
        return $this->getStartDate() <= $this->getEndDate;
    }

    //...
}

As reference, documentation.

like image 10
Damaged Organic Avatar answered Nov 20 '22 12:11

Damaged Organic


It's even more simple since version 2.4. All you have to do is add this method to your class:

use Symfony\Component\Validator\Context\ExecutionContextInterface;

/**
 * @Assert\Callback
 */
public function isStartBeforeEnd(ExecutionContextInterface $context)
{
    if ($this->getStartDate() <= $this->getEndDate()) {
        $context->buildViolation('The start date must be prior to the end date.')
                ->atPath('startDate')
                ->addViolation();
    }
}

The buildViolation method returns a builder that has a couple of other methods to help you configure the constraint (like parameters and translation).

like image 9
Taz Avatar answered Nov 20 '22 12:11

Taz