Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intégrer les formulaires et la validation Symfony dans vos applications PHP.

Hugo Hamon
April 05, 2013

Intégrer les formulaires et la validation Symfony dans vos applications PHP.

Les formulaires sont partout et sont aussi des composants importants d'une application. Ils permettent en effet aux utilisateurs d'interagir avec votre système d'informations. Cependant, la conception et la validation des formulaires ne sont pas des tâches si aisées qu'elles n'y paraissent. Le but de cette conférence est de vous aider à tirer profit des composants de formulaire et de validation du framework Symfony. Nous aborderons les aspects d'architecture des formulaires, les concepts fondamentaux ainsi que quelques usages avancés comme les formulaires imbriqués et les collections. Nous passerons aussi en revue les différentes manières de valider des données avec le composant de validation. Vous serez ainsi en mesure d'intégrer ces deux composants majeurs du framework Symfony dans vos propres applications PHP.

Hugo Hamon

April 05, 2013
Tweet

More Decks by Hugo Hamon

Other Decks in Technology

Transcript

  1. Intégrer les formulaires et
    la validation Symfony
    dans vos applications PHP
    .
    Hugo HAMON – SymfonyLive - Paris 2013

    View full-size slide

  2. Biographie…
    Hugo HAMON
    Responsable des formations SensioLabs
    Auteur chez Eyrolles
    Conférencier
    Contributeur à Symfony
    @hhamon

    View full-size slide

  3. SensioLabs
    A la recherche
    d’un job ?

    View full-size slide

  4. Introduction
    Formulaires & Validation

    View full-size slide

  5. Pourquoi la
    gestion des
    formulaires
    est-elle si
    compliquée ?

    View full-size slide

  6. Formulaires
    Architecture

    View full-size slide

  7. Cœur du système de formulaire
    Core CSRF DI
    Doctrine Propel
    Twig PHP Smarty …
    Zend …
    Rendu
    Extensions
    Fondation

    View full-size slide

  8. Démarrage
    {
    "require": {
    "doctrine/common": "2.*",
    "symfony/form": "2.2.*",
    "symfony/yaml": "2.2.*",
    "symfony/http-foundation": "2.2.*",
    "symfony/validator": "2.2.*",
    "symfony/config": "2.2.*",
    "symfony/translation": "2.2.*",
    "symfony/twig-bridge": "2.2.*"
    }
    }

    View full-size slide

  9. use Symfony\Bridge\Twig\Form\TwigRendererEngine;
    use Symfony\Component\Form\Forms;
    use Symfony\Bridge\Twig\Extension\FormExtension;
    use Symfony\Bridge\Twig\Form\TwigRenderer;
    // Define some constants to the main resources
    define('VENDOR_DIR', realpath(__DIR__ . '/../vendor'));
    define('DEFAULT_FORM_THEME', 'form_div_layout.html.twig');
    define('VENDOR_TWIG_BRIDGE_DIR', VENDOR_DIR . '/symfony/twig-bridge/Symfony/Bridge/Twig');
    define('VIEWS_DIR', realpath(__DIR__ . '/../views'));
    // Initialize a Twig compatible rendering engine
    $twig = new Twig_Environment(new Twig_Loader_Filesystem(array(
    VIEWS_DIR,
    VENDOR_TWIG_BRIDGE_DIR . '/Resources/views/Form',
    )));
    $formEngine = new TwigRendererEngine(array(DEFAULT_FORM_THEME));
    $formEngine->setEnvironment($twig);
    // Register the Twig Form extension
    $twig->addExtension(new FormExtension(new TwigRenderer($formEngine)));
    // Set up the Form component
    $formFactoryBuilder = Forms::createFormFactoryBuilder();
    $formFactory = $formFactoryBuilder->getFormFactory();

    View full-size slide

  10. Formulaires
    Les fondamentaux

    View full-size slide

  11. Créer un formulaire simple
    $form = $formFactory
    ->createBuilder()
    ->add('name')
    ->add('bio', 'textarea')
    ->add('gender', 'choice', array(
    'choices' => array(
    'm' => 'Male',
    'f' => 'Female'
    ),
    ))
    ->getForm();

    View full-size slide

  12. Créer un formulaire simple

    View full-size slide

  13. Vue arborescente du formulaire
    form   form bio   textarea
    name   text
    gender   choice
    Nom du champ   Type de champ  

    View full-size slide

  14. Traitement du formulaire
    $name = $form->getName();
    if (!empty($_POST[$name])) {
    $form->bind($_POST[$name]);
    $data = $form->getData();
    print_r($data);
    }

    View full-size slide

  15. Association avec un tableau
    $data['name']
    $data['bio']
    $data['gender']

    View full-size slide

  16. Préremplissage du formulaire
    $form->setData(array(
    'name' => 'Jane Smith',
    'bio' => 'I do great things!',
    'gender' => 'f',
    ));

    View full-size slide

  17. Préremplissage du formulaire
    Jane Smith
    I do great things!
    Female

    View full-size slide

  18. Formulaires
    Types de champ natifs

    View full-size slide

  19. Types de champ natifs
    §  Birthday
    §  Checkbox
    §  Choice
    §  Collection*
    §  Country
    §  Date
    §  DateTime
    §  File
    §  Hidden
    §  Integer
    §  Language
    §  Locale
    §  Money
    §  Number
    §  Password
    §  Percent
    §  Radio
    §  Repeated*
    §  Search
    §  Textarea
    §  Text
    §  Time
    §  Timezone
    §  Url

    View full-size slide

  20. Types de champ natifs
    Text Choice Password File
    Form
    Date
    Country Language Timezone Birthday DateTime

    View full-size slide

  21. Le champ répété
    $builder
    ->add('name')
    ->add('password', 'repeated', array(
    'type' => 'password',
    'invalid_message' => 'Passwords do not match.',
    'first_options' => array('label' => 'Password'),
    'second_options' => array('label' => 'Confirmation'),
    ))
    ->add('bio', 'textarea')
    // [...]
    ->getForm()
    ;
     

    View full-size slide

  22. Le type « répété » est
    rendu sous la forme de
    deux champs de saisie de
    mot de passe.

    View full-size slide

  23. Formulaires
    Rendu des formulaires

    View full-size slide

  24. Afficher un formulaire
    // PHP rendering
    echo $engine->render('profile.php', array(
    'form' => $form->createView(),
    ));
    // Twig rendering
    echo $twig->render('profile.twig', array(
    'form' => $form->createView(),
    ));

    View full-size slide

  25. Prototypage du rendu (PHP)


    Your profile
    widget($form) ?>


    Save changes
    Cancel


    View full-size slide

  26. Prototypage du rendu (Twig)


    Your profile
    {{ form_widget(form) }}


    Save changes
    Cancel


    View full-size slide


  27. class="required">Name
    name="form[name]"
    required="required"
    value="Jane Smith" />

    Prototypage du rendu

    View full-size slide

  28. // Form rendering
    enctype($form) ?>
    widget($form) ?>
    errors($form) ?>
    rest($form) ?>
    // Field rendering
    row($form['bio']) ?>
    errors($form['bio']) ?>
    label($form['bio']) ?>
    widget($form['bio'], array(
    'attr' => array('class' => 'editor'),
    )) ?>
    Rendu personnalisé (PHP)

    View full-size slide

  29. {# General rendering #}
    {{ form_enctype(form) }}
    {{ form_widget(form) }}
    {{ form_errors(form) }}
    {{ form_rest(form) }}
    {# Field rendering #}
    {{ form_row(form.bio) }}
    {{ form_errors(form.bio) }}
    {{ form_label(form.bio, 'Biography') }}
    {{ form_widget(form.bio, { 'attr': { 'class': 'editor' }}) }}
    Rendu personnalisé (Twig)

    View full-size slide

  30. Formulaires
    Association avec des objets

    View full-size slide

  31. Association des propriétés publiques
    class Person
    {
    public $name;
    public $password;
    public $bio;
    public $gender;
    }

    View full-size slide

  32. Association des propriétés publiques
    $person = new Person();
    $person->name = 'John Doe';
    $person->password = 'S3cR3T$1337';
    $person->bio = 'Born in 1970...';
    $person->gender = 'm';
    $person->active = true;
    // The form reads & writes
    // the person object
    $form->setData($person);

    View full-size slide

  33. Association des propriétés privées
    class Person
    {
    private $name;
    // ...
    function setName($name) { $this->name = $name; }
    function getName() { return $this->name; }
    }

    View full-size slide

  34. Association des propriétés privées
    class Person
    {
    private $active;
    // ...
    public function isActive()
    {
    return $this->active;
    }
    }

    View full-size slide

  35. Association des propriétés privées
    $person = new Person();
    $person->setName('John Doe');
    $person->setPassword('S3cR3T$1337');
    $person->setBio('Born in 1970...');
    $person->setGender('m');
    $person->setActive(true);
    // The form reads & writes
    // the person object
    $form->setData($person);

    View full-size slide

  36. Association du type de données
    $form = $formFactory
    ->createBuilder('form', $person, array(
    'data_class' => 'Person',
    ))
    // ...
    ->getForm()
    ;

    View full-size slide

  37. Formulaires
    Protection CSRF

    View full-size slide

  38. Activer la protection CSRF
    # bootstrap.php
    // ...
    use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
    use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
    use Symfony\Bridge\Twig\Form\TwigRenderer;
    define('CSRF_SECRET', 'c2ioeEU1n48QF2WsHGWd2HmiuUUT6dxr');
    // Set up the CSRF provider
    $csrfProvider = new DefaultCsrfProvider(CSRF_SECRET);
    $renderer = new TwigRenderer($formEngine, $csrfProvider);
    // ...
    $formFactory = $formFactoryBuilder
    ->addExtension(new CsrfExtension($csrfProvider))
    ->getFormFactory();

    View full-size slide

  39. Activer la protection CSRF


    Your profile






    Save changes
    Cancel


    View full-size slide

  40. Formulaires
    Type de formulaire
    personnalisé

    View full-size slide

  41. Créer un type personnalisé
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    class PersonType extends AbstractType
    {
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array('data_class' => 'Person'));
    }
    public function getName()
    {
    return 'person';
    }
    }

    View full-size slide

  42. // ...
    use Symfony\Component\Form\FormBuilderInterface;
    class PersonType extends AbstractType
    {
    public function buildForm(
    FormBuilderInterface $builder,
    array $options
    )
    {
    $builder
    ->add('name')
    ->add('password', 'repeated', array(...))
    ->add('bio', 'textarea')
    ->add('gender', 'choice', array(...))
    ->add('active', 'checkbox')
    ;
    }
    }

    View full-size slide

  43. Créer un type personnalisé
    $person = new Person();
    $person->setName('John Doe');
    // ...
    $options = array('trim' => true);
    $form = $formFactory
    ->create(new PersonType(), $person, $options)
    ;

    View full-size slide

  44. Enregistrer un nouveau type
    # in your code...
    $form = $formFactory->create('person', $person);
    # bootstrap.php
    $formFactory = Forms::createFormFactoryBuilder()
    // [...]
    ->addType(new PersonType(), 'person')
    ->getFormFactory()
    ;

    View full-size slide

  45. Formulaires
    Gestion des fichiers

    View full-size slide

  46. Gérer l’envoi de fichiers
    # bootstrap.php
    // ...
    use Symfony\…\HttpFoundation\HttpFoundationExtension;
    $formFactoryBuilder = Forms::createFormFactoryBuilder()
    $formFactory = $formFactoryBuilder
    ->addExtension(new HttpFoundationExtension())
    // [...]
    ->getFormFactory()
    ;

    View full-size slide

  47. Gérer l’envoi de fichiers
    class PersonType extends AbstractType
    {
    function buildForm(FormBuilderInterface $builder, …)
    {
    $builder
    // […]
    ->add('picture', 'file', array(
    'required' => false,
    ))
    ->add('active', 'checkbox')
    ;
    }
    }

    View full-size slide

  48. Générer l’attribut « enctype »



    View full-size slide

  49. Traiter le formulaire
    use Symfony\Component\HttpFoundation\Request;
    $request = Request::createFromGlobals()
    $request->overrideGlobals();
    if ($request->isMethod('POST')) {
    $form->bind($request);
    var_dump($form->getData());
    }

    View full-size slide

  50. Traiter le formulaire
    object(Person)
    private 'name' => 'John Doe'
    private 'picture' =>
    object(Symfony\Component\HttpFoundation\File\UploadedFile)
    private 'test' => false
    private 'originalName' => '445.jpg'
    private 'mimeType' => 'image/jpeg'
    private 'size' => 21645
    private 'error' => 0
    private 'password' => 'secret'
    private 'bio' => 'Famous actor!'
    private 'gender' => 'm'
    private 'active' => true

    View full-size slide

  51. Traiter le formulaire
    $file = $form->get('picture')->getData();
    $target = __DIR__. '/uploads';
    if ($file->isValid()) {
    $new = $file->move($target, 'jdoe.jpg');
    }

    View full-size slide

  52. Formulaires
    Champs non associés

    View full-size slide

  53. Définir un champ non associé
    $builder
    ->add('rules', 'checkbox', array(
    'mapped' => false,
    ))
    ;

    View full-size slide

  54. array(
    'name' => 'John Doe'
    'password' => 'secret'
    'bio' => 'Actor!'
    'gender' => 'm'
    'picture' => null
    'active' => true
    )
    Champ non associé
    Pas de donnée
    « rules »

    View full-size slide

  55. Formulaires
    Collections de champs

    View full-size slide

  56. Définir une collection de champs
    $builder
    // ...
    ->add('hobbies', 'collection', array(
    'allow_add' => true,
    'allow_delete' => true,
    ))
    // ...
    ;

    View full-size slide

  57. Définir une collection de champs
    $person = new Person();
    $person->setName('John Doe');
    $person->addHobby('music');
    $person->addHobby('movies');
    $person->addHobby('travels');

    View full-size slide

  58. Définir une collection de champs

    View full-size slide

  59. Conventions de nommage
    class Person
    {
    public function addHobby($hobby)
    {
    $this->hobbies[] = $hobby;
    }
    public function removeHobby($hobby)
    {
    $key = array_search($hobby, $this->hobbies);
    if (false !== $key) {
    unset($this->hobbies[$key]);
    }
    }
    }

    View full-size slide

  60. Prototype HTML d’ajout de champ

    View full-size slide

  61. Formulaires
    Formulaires imbriqués

    View full-size slide

  62. Imbriquer les formulaires
    class Address
    {
    private $street;
    private $zipCode;
    private $city;
    private $state;
    private $country;
    // ...
    }

    View full-size slide

  63. class AddressType extends AbstractType
    {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
    $builder
    ->add('street', 'textarea')
    ->add('zipCode')
    ->add('city')
    ->add('state')
    ->add('country', 'country')
    ;
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array('data_class' => 'Address'));
    }
    public function getName()
    {
    return 'address';
    }
    }

    View full-size slide

  64. Imbriquer les formulaires
    class PersonType extends AbstractType
    {
    function buildForm(FormBuilderInterface $builder, …)
    {
    $builder
    // ...
    ->add('address', new AddressType())
    ;
    }
    }

    View full-size slide

  65. Imbriquer les formulaires
    class PersonType extends AbstractType
    {
    function buildForm(FormBuilderInterface $builder, …)
    {
    $builder
    // ...
    ->add('address', 'address')
    ;
    }
    }

    View full-size slide

  66. Imbriquer les formulaires
    $formBuilder = Forms::createFormFactoryBuilder();
    $formFactory = $formBuilder
    // ...
    ->addType(new AddressType(), 'address')
    ->addType(new PersonType(), 'person')
    ->getFormFactory()
    ;

    View full-size slide

  67. Vue arborescente du formulaire
    form   form bio   textarea
    name   text
    …   ...
    Champ   Type  
    address   Address
    zipCode   text
    address   textarea
    city   text
    country   country
    state   text

    View full-size slide

  68. Person Object
    (
    [name] => Hugo Hamon
    [picture] =>
    [username] => hhamon
    [password] => secret
    [address] => Address Object
    (
    [street] => 42 Sunshine Street
    [zipCode] => 12345
    [city] => Miami
    [state] => Florida
    [country] => US
    )
    [bio] => Speaker at conference
    [gender] => m
    [active] => 1
    [hobbies] => Array
    (
    [1] => movies
    [2] => travels
    [3] => conferences
    )
    )

    View full-size slide

  69. Formulaires
    I18N & L10N

    View full-size slide

  70. $builder
    ->add('birthdate', 'birthday', array('format' => 'd/M/y'))
    ->add('salary', 'money', array('currency' => 'EUR'))
    ->add('language', 'language', array(
    'preferred_choices' => array('fr'),
    )
    ->add('country', 'country', array(
    'preferred_choices' => array('FR'),
    )
    ->add('timezone', 'timezone', array(
    'preferred_choices' => array('Europe/Paris')
    )
    ;
    Types de champs régionalisés

    View full-size slide

  71. Locale: fr_FR
    Locale: en_US

    View full-size slide

  72. Formulaires
    Gestion des thèmes

    View full-size slide

  73. {% form_theme form _self %}
    {% block password_widget %}

    {{ block('field_widget') }}




    {% endblock password_widget %}
    Changer le rendu de tous les champs de
    saisie de mot de passe

    View full-size slide

  74. {% form_theme form _self %}
    {% block _person_username_widget %}

    {{ block('field_widget') }}




    {% endblock _person_username_widget %}
    Changer le rendu d’un champ précis

    View full-size slide

  75. Rendu personnalisé de champs

    View full-size slide

  76. Validation
    Le validateur

    View full-size slide

  77. // ...
    use Symfony\Component\Validator\Validation;
    use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
    $validator = Validation::createValidatorBuilder()
    ->getValidator()
    ;
    $formFactoryBuilder = Forms::createFormFactoryBuilder()
    $formFactory = $formFactoryBuilder
    // ...
    ->addExtension(new ValidatorExtension($validator))
    ->getFormFactory()
    ;
    Configurer le validateur

    View full-size slide

  78. Contraintes & Validateurs
    Pour chaque règle de validation, le composant
    embarque une classe de type Constraint et sa
    classe Validator associée.
    L’objet Constraint décrit la règle à valider et
    l’objet Validator est l’implementation de la
    logique métier associée à cette règle.

    View full-size slide

  79. // ...
    use Symfony\Component\Validator\Constraints\NotBlank as Assert;
    class PersonType extends AbstractType
    {
    public function buildForm(...)
    {
    $builder->add('name', 'text', array(
    'constraints' => array(
    new Assert\NotBlank(),
    new Assert\Length(array('min' => 5, 'max' => 40)),
    ),
    ));
    // ...
    }
    }
    Association des contraintes aux champs

    View full-size slide

  80. $genders = array('m' => 'Male', 'f' => 'Female');
    $builder->add('gender', 'choice', array(
    'choices' => $genders,
    'constraints' => array(
    new Assert\NotBlank(),
    new Assert\Choice(array(
    'choices' => array_keys($genders),
    'message' => 'Alien genders are not supported.',
    )),
    ),
    ));
    Association des contraintes aux champs

    View full-size slide

  81. Validation du formulaire
    $request = Request::createFromGlobals();
    $request->overrideGlobals();
    if ($request->isMethod('POST')) {
    $form->bind($request);
    if ($form->isValid()) {
    $data = $form->getData();
    // ... handle sanitized data
    }
    }

    View full-size slide

  82. Validation du formulaire

    View full-size slide

  83. Classes de contraintes natives
    §  All
    §  Blank
    §  Callback
    §  Choice
    §  Collection
    §  Count
    §  Country
    §  Date
    §  DateTime
    §  Email
    §  False
    §  File
    §  Image
    §  Ip
    §  Language
    §  Length
    §  Locale
    §  NotBlank
    §  NotNull
    §  Null
    §  Range
    §  Regex
    §  Time
    §  True
    §  Type
    §  Url
    §  Valid…

    View full-size slide

  84. Validation
    Formats de configuration

    View full-size slide

  85. # bootstrap.php
    // ...
    $validator = Validation::createValidatorBuilder()
    ->addMethodMapping('loadValidatorMetadata')
    ->addXmlMapping(__DIR__.'/config/validation.xml')
    ->addYamlMapping(__DIR__.'/config/validation.yml')
    ->enableAnnotationMapping()
    ->getValidator()
    ;
    Configurer le validateur

    View full-size slide

  86. use Symfony\Component\Validator\Mapping\ClassMetadata;
    use Symfony\Component\Validator\Constraints\NotBlank;
    use Symfony\Component\Validator\Constraints\Length;
    class Person
    {
    private $name;
    // ...
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
    $metadata->addPropertyConstraint('name', new NotBlank());
    $metadata->addPropertyConstraint('name', new Length(array(
    'min' => 5,
    'max' => 40,
    )));
    // ...
    }
    }
    Configuration en PHP

    View full-size slide

  87. # src/config/validation.yml
    Person:
    properties:
    name:
    - NotBlank: ~
    - Length: { 'min': 5, 'max': 40 }
    # ...
    getters:
    # ...
    constraints:
    # ...
    Configuration en YAML

    View full-size slide








  88. 5
    40




    Configuration en XML

    View full-size slide

  89. use Symfony\Component\Validator\Constraints as Assert;
    class Person
    {
    /**
    * @Assert\NotBlank()
    * @Assert\Length(min = 5, max = 40)
    */
    private $name;
    // ...
    }
    Configuration en annotations

    View full-size slide

  90. Validation
    Ajouter des contraintes

    View full-size slide

  91. Contraintes de propriétés
    use Symfony\Component\Validator\Constraints\Image;
    class Person
    {
    private $picture;
    // ...
    static function loadValidatorMetadata(ClassMetadata $metadata)
    {
    $metadata->addPropertyConstraint('picture', new Image(array(
    'minWidth' => 100,
    'maxWidth' => 150,
    'minHeight' => 100,
    'maxHeight' => 150,
    )));
    // ...
    }
    }

    View full-size slide

  92. class Person
    {
    //...
    static function loadValidatorMetadata(ClassMetadata $metadata)
    {
    $metadata->addConstraint(new Unique(array(
    'field' => 'username',
    'message' => 'This username already exist.',
    )));
    //...
    }
    }
    Contraintes de classe

    View full-size slide

  93. use Symfony\Component\Validator\Constraints\True;
    class Person
    {
    private $username;
    private $password;
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
    $metadata->addGetterConstraint('passwordValid', new True(array(
    'message' => 'Password and username cannot be same.',
    )));
    // ...
    }
    public function isPasswordValid()
    {
    return strtolower($this->username) !== strtolower($this->password);
    }
    }
    Contraintes de méthodes

    View full-size slide

  94. Contraintes de méthodes
    Le message d’erreur
    remonte comme une
    erreur globale du
    formulaire.

    View full-size slide

  95. class PersonType extends AbstractType
    {
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array(
    'data_class' => 'Person',
    'error_mapping' => array('passwordValid' => 'password'),
    ));
    }
    }
    Associer une erreur globale à un champ

    View full-size slide

  96. Associer une erreur globale à un champ
    Le message d’erreur est
    désormais réaffecté au
    champ « password ».

    View full-size slide

  97. Validation
    Traduction des messages

    View full-size slide

  98. use Symfony\Component\Translation\Translator;
    use Symfony\Component\Translation\Loader\XliffFileLoader;
    use Symfony\Bridge\Twig\Extension\TranslationExtension;
    $t = new Translator('fr');
    $t->addLoader('xlf', new XliffFileLoader());
    // Built in translations
    $t->addResource('xlf', FORM_DIR . '/Resources/translations/validators.fr.xlf', 'fr', 'validators');
    $t->addResource('xlf', VALIDATOR_DIR . '/Resources/translations/validators.fr.xlf', 'fr', 'validators');
    // Your translations
    $t->addResource('xlf', __DIR__. '/translations/validators.fr.xlf', 'fr', 'validators');
    // ...
    $twig->addExtension(new TranslationExtension($t));
    // ...
    Activer le support des traductions

    View full-size slide



  99. original="file.ext">


    Password and username cannot be same.
    Le mot de passe et le nom d'utilisateur doivent
    être différents.




    Traduire les messages d’erreur

    View full-size slide

  100. Validation
    Configuration avancée

    View full-size slide

  101. Groupes de validation
    class Person
    {
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
    $metadata->addPropertyConstraint('password', new NotBlank(array(
    'groups' => array('Signup'),
    )));
    $metadata->addGetterConstraint('passwordValid', new True(array(
    'message' => 'Password and username cannot be same.',
    'groups' => array('Signup', 'Profile'),
    )));
    // ...
    }
    }

    View full-size slide

  102. class RegistrationType extends AbstractType
    {
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array(
    // ...
    'validation_groups' => array('Signup'),
    ));
    }
    }
    class EditAccountType extends AbstractType
    {
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array(
    // ...
    'validation_groups' => array('Profile'),
    ));
    }
    }

    View full-size slide

  103. Ressources officielles
    §  http://symfony.com/doc/current/book/forms.html
    §  http://symfony.com/doc/current/reference/forms/types.html
    §  http://symfony.com/doc/current/book/validation.html
    §  http://symfony.com/doc/current/reference/constraints.html
    §  http://symfony.com/doc/current/reference/forms/twig_reference.html
    §  https://github.com/bschussek/standalone-forms
    Ressources utiles

    View full-size slide

  104. Merci !
    Hugo Hamon
    [email protected]
    @hhamon

    View full-size slide