Skip to content
softeg edited this page Jan 8, 2014 · 8 revisions

Validation des données :

On peut ajouter des validateurs (contraites) pour chaque objet, il y'a 02 façon de le faire soit de défnir les annotations ou un fichier yml,xml ou php.

Liste des contraites :

La documentation officielle

Contraintes de base :

Contrainte

Rôle

Options

NotBlank
Blank

La contrainte NotBlank vérifie que la valeur soumise n'est ni une chaîne de caractères vide, ni NULL.
La contrainte Blank fait l'inverse.

-

True
False

La contrainte True vérifie que la valeur vaut true, 1 ou "1".
La contrainte False vérifie que la valeur vaut false, 0 ou "0".

-

Type

La contrainte Type vérifie que la valeur est bien du type donné en argument.

type (option par défaut) : le type duquel doit être la valeur, parmi array, bool, int, object, etc.

Contraintes sur des chaînes de caractères :

Contrainte

Rôle

Options

Email

La contrainte Email vérifie que la valeur est une adresse e-mail valide.

checkMX (défaut : false) : si défini à true, Symfony2 va vérifier les MX de l'e-mail via la fonction checkdnsrr.

MinLength
MaxLength

La contrainte MinLength vérifie que la valeur donnée fait au moins X caractères de long.
MaxLength, au plus X caractères de long.

limit (option par défaut) : le seuil de longueur, en nombre de caractères.
charset (défaut : UTF-8) : le charset à utiliser pour calculer la longueur.

Url

La contrainte Url vérifie que la valeur est une adresse URL valide.

protocols (défaut : array('http', 'https')) : définit les protocoles considérés comme valides.
Si vous voulez accepter les URL en ftp://, ajoutez-le à cette option.

Regex

La contrainte Regex vérifie la valeur par rapport à une regex.

pattern (option par défaut) : la regex à faire correspondre.
match (défaut : true) : définit si la valeur doit (true) ou ne doit pas (false) correspondre à la regex.

Ip

La contrainte Ip vérifie que la valeur est une adresse IP valide.

type (défaut : 4) : version de l'IP à considérer. 4 pour IPv4, 6 pour IPv6, all pour toutes les versions, et d'autres.

Language

La contrainte Language vérifie que la valeur est un code de langage valide selon la norme.

-

Locale

La contrainte Locale vérifie que la valeur est une locale valide. Exemple : fr ou fr_FR.

-

Country

La contrainte Country vérifie que la valeur est un code pays en 2 lettres valide. Exemple : fr.

-

Contraintes sur les nombres :

Contrainte

Rôle

Options

Max
Min

La contrainte Max vérifie que la valeur ne dépasse pas X.
Min, que la valeur dépasse ce X.

limit (option par défaut) : la valeur seuil.
invalidMessage : message d'erreur lorsque la valeur n'est pas un nombre.

Contraintes sur les dates :

Contrainte

Rôle

Options

Date

La contrainte Date vérifie que la valeur est un objet de type Datetime, ou une chaîne de caractères du type YYYY-MM-DD.

-

Time

La contrainte Time vérifie que la valeur est un objet de type Datetime, ou une chaîne de caractères du type HH:MM:SS.

-

DateTime

La contrainte Datetime vérifie que la valeur est un objet de type Datetime, ou une chaîne de caractères du type YYYY-MM-DD HH:MM:SS.

-

Contraintes sur les fichiers :

Contrainte

Rôle

Options

File

La contrainte File vérifie que la valeur est un fichier valide, c'est-à-dire soit une chaîne de caractères qui point vers un fichier existant, soit une instance de la classe File (ce qui inclut UploadedFile).

maxSize : la taille maximale du fichier. Exemple : 1M ou 1k.
mimeTypes : mimeType(s) que le fichier doit avoir.

Image

La contrainte Image vérifie que la valeur est valide selon la contrainte précédente File (dont elle hérite les options), sauf que les mimeTypes acceptés sont automatiquement définis comme ceux de fichiers images. Il est également possible de mettre des contraintes sur la hauteur max ou la largeur max de l'image.

maxSize : la taille maximale du fichier. Exemple : 1M ou 1k.
minWidth / maxWidth : la largeur minimale et maximale que doit respecter l'image.
minHeight / maxHeight : la hauteur minimale et maximale que doit respecter l'image.

Le service Validator

Pour valider l'objet, on passe par un acteur externe : le service validator. Ce service s'obtient comme n'importe quel autre service :

$validator = $this->get('validator');

Ensuite, on doit demander à ce service de valider notre objet. Cela se fait grâce à la méthode validate du service. Cette méthode retourne un tableau qui est soit vide si l'objet est valide, soit rempli des différentes erreurs lorsque l'objet n'est pas valide. Pour bien comprendre, exécutez cette méthode dans un contrôleur :

  public function testAction()
  {
    $article = new Article;
        
    $article->setDate(new \Datetime());  // Champ « date » OK
    $article->setTitre('abc');           // Champ « titre » incorrect : moins de 10 caractères
    //$article->setContenu('blabla');    // Champ « contenu » incorrect : on ne le définit pas
    $article->setAuteur('A');            // Champ « auteur » incorrect : moins de 2 caractères
        
    // On récupère le service validator
    $validator = $this->get('validator');
        
    // On déclenche la validation
    $liste_erreurs = $validator->validate($article);

    // Si le tableau n'est pas vide, on affiche les erreurs
    if(count($liste_erreurs) > 0) {
      return new Response(print_r($liste_erreurs, true));
    } else {
      return new Response("L'article est valide !");
    }
  }

#####Valider depuis un getter

Mais il existe un moyen de déclencher une erreur liée à un champ en particulier, ainsi l'erreur s'affichera juste à côté de ce champ. Il suffit de nommer le getter « is + le nom d'un attribut » : par exemple isTitre si l'on veut valider le titre. Essayez par vous-mêmes le code suivant :

  /**
   * @Assert\True()
   */
  public function isTitre()
  {
    return false;
  }

#####Valider intelligemment un attribut objet

Derrière ce titre se cache une problématique toute simple : lorsque je valide un objet A, comment valider un objet B en attribut, d'après ses propres règles de validation ?

Il faut utiliser la contrainte Valid, qui va déclencher la validation du sous-objet B selon les règles de validation de cet objet B. Prenons un exemple :

<?php
class A
{
  /**
   * @Assert\MinLength(5)
   */
  private $titre;

  /**
   * @Assert\Valid()
   */
  private $b;
}

class B
{
  /**
   * @Assert\Min(10)
   */
  private $nombre;
}

#####Valider depuis un Callback L'objectif de la contrainte Callback est d'être personnalisable à souhait. En effet, vous pouvez parfois avoir besoin de valider des données selon votre propre logique, qui ne rentre pas dans un Maxlength.

L'exemple classique est la censure de mots non désirés dans un attribut texte. Reprenons notre Article, et considérons que l'attribut contenu ne peut pas contenir les mots « échec » et « abandon ». Voici comment mettre en place une règle qui va rendre invalide le contenu s'il contient l'un de ces mots :

<?php

namespace Sdz\BlogBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Sdz\BlogBundle\Entity\Tag;

// On rajoute ce use pour le context :
use Symfony\Component\Validator\ExecutionContextInterface;

/**
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Sdz\BlogBundle\Entity\ArticleRepository")
 *
 * N'oubliez pas cet Assert :
 * @Assert\Callback(methods={"contenuValide"})
 */
class Article
{
  // …
	
  public function contenuValide(ExecutionContextInterface $context)
  {
    $mots_interdits = array('échec', 'abandon');
		
    // On vérifie que le contenu ne contient pas l'un des mots
    if (preg_match('#'.implode('|', $mots_interdits).'#', $this->getContenu())) {
      // La règle est violée, on définit l'erreur et son message
      // 1er argument : on dit quel attribut l'erreur concerne, ici « contenu »
      // 2e argument : le message d'erreur
      $context->addViolationAt('contenu', 'Contenu invalide car il contient un mot interdit.', array(), null);
    }
  }
}
  • L'annotation se définit ici sur la classe, et non sur une méthode ou un attribut, faites attention.

Vous auriez même pu aller plus loin en comparant des attributs entre eux, par exemple pour interdire le pseudo dans un mot de passe. L'avantage du Callback par rapport à une simple contrainte sur un getter, c'est de pouvoir ajouter plusieurs erreurs à la fois, en définissant sur quel attribut chacun se trouve grâce au premier argument de la méthode addViolationAt (en mettant contenu ou titre, etc). Souvent la contrainte sur un getter suffira, mais pensez à ce Callback pour les fois où vous serez limités.

#####Valider un champ unique

Il existe une dernière contrainte très pratique : UniqueEntity. Cette contrainte permet de valider que la valeur d'un attribut est unique parmi toutes les entités existantes. Pratique pour vérifier qu'une adresse e-mail n'existe pas déjà dans la base de données par exemple.

Vous avez bien lu, j'ai parlé d'entité. En effet, c'est une contrainte un peu particulière, car elle ne se trouve pas dans le composant Validator, mais dans le Bridge entre Doctrine et Symfony2 (ce qui fait le lien entre ces deux bibliothèques). On n'utilisera donc pas @Assert\UniqueEntity, mais simplement @UniqueEntity. Il faut bien sûr en contrepartie faire attention de rajouter ce use à chaque fois que vous l'utilisez :

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

Voici comment on pourrait, dans notre exemple avec Article, contraindre nos titres à être tous différents les uns des autres :

<?php

namespace Sdz\BlogBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Sdz\BlogBundle\Entity\Tag;

// On rajoute ce use pour la contrainte :
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Sdz\BlogBundle\Entity\ArticleRepository")
 *
 * @UniqueEntity(fields="titre", message="Un article existe déjà avec ce titre.")
 */
class Article
{
  // … Les autres contraintes ne changent pas, pas même celle(s) sur l'attribut titre

  // Mais pour être logique, il faudrait aussi mettre la colonne titre en Unique pour Doctrine :
  /**
   * @ORM\Column(name="titre", type="string", length=255, unique=true)
   */
  private $titre;
}
  • Ici aussi, l'annotation se définit sur la classe, et non sur une méthode ou sur un attribut.

Clone this wiki locally