Est-il possible de valider une propriété d'une classe de modèle dépendant d'une autre propriété de la même classe?
Par exemple, j'ai cette classe:
class Conference
{
/** $startDate datetime */
protected $startDate;
/** $endDate datetime */
protected $endDate;
}
et je veux que Symfony 2.0 valide, que $startDate
doit être après $endDate
.
Est-ce possible par des annotations ou dois-je le faire manuellement?
Oui avec le validateur de rappel: http://symfony.com/doc/current/reference/constraints/Callback.html
Sur 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);
}
}
}
Sur la version principale de symfony:
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);
}
}
Ici, j'ai choisi d'afficher le message d'erreur dans le champ startDate.
À partir de Symfony 2.4, vous pouvez également utiliser Expression contrainte de validation pour répondre à vos besoins. Je crois que c'est le moyen le plus simple de le faire. C'est plus pratique que la contrainte de rappel à coup sûr.
Voici un exemple de mise à jour de votre classe de modèle avec des annotations de contraintes de validation:
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;
}
N'oubliez pas de activer les annotations dans la configuration de votre projet.
Vous pouvez toujours faire des validations encore plus complexes en utilisant syntaxe d'expression .
Un autre moyen (au moins à partir de Symfony 2.3) consiste à utiliser le simple @Assert\IsTrue
:
class Conference
{
//...
/**
* @Assert\IsTrue(message = "Startime should be lesser than EndTime")
*/
public function isStartBeforeEnd()
{
return $this->getStartDate() <= $this->getEndDate;
}
//...
}
Comme référence, documentation .
C'est encore plus simple depuis version 2.4 . Tout ce que vous avez à faire est d’ajouter cette méthode à votre classe:
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();
}
}
La méthode buildViolation
renvoie un générateur doté de deux autres méthodes pour vous aider à configurer la contrainte (comme les paramètres et la traduction).
Une solution meilleure et plus propre https://symfony.com/doc/3.4/validation/custom_constraint.html Consiste à écrire
Pour vérifier que l'entité va bien, ajoutez-le à la contrainte personnalisée (pas au validateur).
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
Ce qui vous permet d'utiliser une instance de cette entité au lieu d'une valeur de propriété. Cela permet d'écrire dans le validateur:
public function validate($object, Constraint $constraint)
{
#Your logic, for example:
if($value1 = $object->getValue1())
{
if($value2 = $object->getValue2())
{
if($value1 === $value2)
{
# validation passed
return True;
}
else
{
# validation failed
$this->context->buildViolation($constraint->message)
->setParameter('{{ string }}', $value1.' !== '.$value2)
->addViolation();
}
La meilleure partie est ce que vous devez écrire dans la classe d'entité:
use YourBundle\Validator\Constraints as YourAssert;
/**
* Yourentity
*
* @ORM\Table(name="yourentity")
* @ORM\Entity(repositoryClass="YourBundle\Repository\YourentityRepository")
*
* @YourAssert\YourConstraintClassName # <-- as simple as this
J'espère que cela pourra aider
Pour les validations de date, nous pouvons simplement utiliser les contraintes de comparaison GreaterThan et GreaterThanOrEqual.
class Conference
{
/**
* @var \DateTime
* @Assert\GreaterThanOrEqual("today")
*/
protected $startDate;
/**
* @var \DateTime
* @Assert\GreaterThan("startDate")
*/
protected $endDate;
}
Pour plus d'informations, voir contraintes de validation