Formulaire et validateur

préparation

installation, paquets utiles : php composer.phar req server vardumper annotations doctrine twig asset make

le contrôleur

php bin/console make:controller EtudiantController
use Twig\Environment;                            // template TWIG
use Symfony\Bridge\Doctrine\RegistryInterface;   // ORM Doctrine
use Symfony\Component\HttpFoundation\Request;    // objet REQUEST
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;    
                                // dans les annotations @Method
/**
 * @Route("/", name="etudiant")
 */
public function index()
{
    return $this->redirectToRoute('etudiant.show');
}

/**
 * @Route("/etudiant/show", name="etudiant.show")
 */
public function showEtudiant(Request $request, Environment $twig, RegistryInterface $doctrine)
{
    $etudiant=['id'=>'1','nom'=>'stephane','age'=>'19', 'adresse'=>'Belfort','dateNaissance'=>'2010/01/01'];
    return new Response($twig->render('etudiant/showEtudiant.html.twig', ['etudiant' => $etudiant]));

}
{% extends "base.html.twig" %}
{% block body %}
    information sur un étudiant
<h1> {{ etudiant.id }}  |   {{ etudiant.nom }}  | {{ etudiant.age }}  | {{ etudiant.adresse }}  | {{ etudiant.dateNaissance }}  |</h1>
{% endblock %}

le formulaire symfony

ajouter une méthode dans le contrôleur

/**
 * @Route("/etudiant/add", name="etudiant.add")
 */
public function addEtudiant(Request $request, Environment $twig, RegistryInterface $doctrine)
{

    return new Response($twig->render('etudiant/addEtudiant.html.twig'));

}

ajouter une vue templates/etudiant/addEtudiant.html.twig

{% extends "base.html.twig" %}
{% block body %}
    formulaire étudiant
{% endblock %}

ajouter un formulaire dans la méthode addEtudiant du contrôleur

$form = $this->createFormBuilder()
    ->add('nom', TextType::class)
    ->add('age', NumberType::class)
    ->add('adresse', TextareaType::class)
    ->add('dateNaissance', dateType::class)
    ->add('submit', SubmitType::class)
    ->getForm();

http://api.symfony.com/3.4/Symfony/Component/Form/Extension/Core/Type.html

use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
return new Response($twig->render('etudiant/addEtudiant.html.twig',['form'=>$form->createView()]));
    {{ form_start(form) }}
    {{ form_errors(form) }}

    {{ form_row(form.nom) }}
    {{ form_row(form.age) }}
            <span style="color: red">{{ form_errors(form.age) }}</span>
    {{ form_row(form.adresse) }}
    {{ form_row(form.dateNaissance) }}

    {{ form_row(form.submit, { 'label': 'Ajouter un étudiant' }) }}
    {{ form_end(form) }}
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
    $data = $form->getData();
    dump($data);
    dump($data['nom']);
}

ajouter le namespace use Symfony\Component\Validator\Constraints as Assert;


exemple

$donnees = ['nom' => 'pierre'];
$form = $this->createFormBuilder()
    ->add('nom', TextType::class, ['attr' => ['value' => $donnees['nom']]])
    ->add('age', TextType::class, [
        'constraints' => [
            new Assert\NotBlank(['message' =>  'Saisir votre age ']),
            new Assert\Type(['type'=>'numeric','message' =>  'La valeur {{ value }} n\'est pas valide, le type est {{ type }} ']),
        ],
        'label' => 'age',
        'required' => false
    ])
    ->add('adresse', TextType::class, [
        'label' => 'adresse',
        'required' => false
    ])
    ->add('dateNaissance', dateType::class)
    ->add('submit', SubmitType::class)
    ->getForm();


Les formulaires servent essenciellement à ajouter ou modifier des enregistrements dans une table.
Cette méthode est compliquée, il est plus interessant de définir les contraintes directement dans l’entité si on utilise une entité. Pour hydrater les données c’est aussi compliqué avec cette méthode en écrivant tout le code. Cependant symfony a prévu des objets qui penvent directement se connecter aux entités.

créer une entité etudiant

créer une entité Etudiant

php bin/console make:entity Etudiant
    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255)
     */
    private $nom;

    /**
     * @var integer
     *
     * @ORM\Column(name="age", type="integer", nullable=true)
     */
    private $age;

    /**
     * @var string
     *
     * @ORM\Column(name="adresse", type="string", length=255, nullable=true)
     */
    private $adresse;

    /**
     * @var date
     *
     * @ORM\Column(name="dateNaissance", type="date", nullable=true)
     */
    private $dateNaissance;

documentation sur les types, les annotations et le mapping

php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate

formulaire sur cette entité

php bin/console make:Form Etudiant

ceci crée une classe EtudiantType

modifier le code source src/Form/EtudiantType.php

class EtudiantType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nom', TextType::class)
            ->add('age', NumberType::class)
            ->add('adresse', TextareaType::class)
            ->add('dateNaissance', dateType::class)
            ->add('submit', SubmitType::class)
            ->getForm()
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            // uncomment if you want to bind to a class
            'data_class' => Etudiant::class,
        ]);
    }
}

attention use App\Form\EtudiantType; en début de contrôleur, ainsi que use Symfony\Component\Form\Extension\Core\Type\...

$etudiant=$doctrine->getRepository(Etudiant::class)->find(1);

$form=$formFactory->createBuilder(EtudiantType::class,$etudiant)->getForm();

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
    $data = $form->getData();
    dump($data);
    dump($data['nom']);
}
return new Response($twig->render('etudiant/addEtudiant.html.twig',['form'=>$form->createView()]));

Pour les contraintes, il est plus facile de les mettre dans l’entité src/Entity/Etudiant.php

   /**
     * @var string
     * @Assert\NotBlank()
     * @Assert\Length(min=2, minMessage = "votre nom doit être composé de {{ limit }} caractères minimum")
     * @ORM\Column(name="nom", type="string", length=255)
     */
    private $nom;

    /**
     * @var integer
     * @Assert\NotBlank(message = "Saisir votre age ")
     * @Assert\Type(type="numeric",message =  "La valeur {{ value }} n'est pas valide, le type est {{ type }} ")
     * @ORM\Column(name="age", type="integer", nullable=true)
     */
    private $age;

Ne pas oublier le namespace en début de fichier use Symfony\Component\Validator\Constraints as Assert;

REMARQUE : Pour le champ de type entier le message d’erreur retourné pour un mauvais type n’est pas celui défini dans les contraintes => modification à trouver

    /**
     * @Route("/etudiant/add", name="etudiant.add")
     */
    public function addEtudiant(Request $request, Environment $twig, RegistryInterface $doctrine, FormFactoryInterface $formFactory)
    {
        $form=$formFactory->createBuilder(EtudiantType::class)->getForm();
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $etudiant=$form->getData();
            $doctrine->getEntityManager()->persist($etudiant);
            $doctrine->getEntityManager()->flush();
            return $this->redirectToRoute('etudiant.show');
        }
        return new Response($twig->render('etudiant/addEtudiant.html.twig',['form'=>$form->createView()]));
    }

    /**
     * @Route("/etudiant/delete", name="etudiant.delete")
     */
    public function deleteEtudiant(Request $request, Environment $twig, RegistryInterface $doctrine, FormFactoryInterface $formFactory)
    {
        $etudiant=$doctrine->getRepository(Etudiant::class)->find($request->query->get('id'));
        $doctrine->getEntityManager()->remove($etudiant);
        $doctrine->getEntityManager()->flush();
        return $this->redirectToRoute('etudiant.show');
     }

    /**
     * @Route("/etudiant/edit", name="etudiant.edit")
     */
    public function editEtudiant(Request $request, Environment $twig, RegistryInterface $doctrine, FormFactoryInterface $formFactory)
    {
        $etudiant=$doctrine->getRepository(Etudiant::class)->find($request->query->get('id'));
        $form=$formFactory->createBuilder(EtudiantType::class,$etudiant)->getForm();
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $doctrine->getEntityManager()->flush();
            return $this->redirectToRoute('etudiant.show');
        }
        return new Response($twig->render('etudiant/addEtudiant.html.twig',['form'=>$form->createView()]));
    }

et enfin la vue

    information sur les étudiants
    <a href="{{ path('etudiant.add') }}">ajouter</a><br>
    {% for etudiant in etudiants if etudiants is not empty %}
    <li> {{ etudiant.id }}  |   {{ etudiant.nom }}  | {{ etudiant.age }}  | {{ etudiant.adresse }}  | {{ etudiant.dateNaissance |date('d-m-Y')}}
        <a href="{{ path('etudiant.edit', {id: etudiant.id}) }}">modifier</a> &nbsp;
        <a href="{{ path('etudiant.delete', {id: etudiant.id}) }}">supprimer</a>
    {% endfor %}

lien avec une autre table (liste déroulante)

créer une entité groupe

php bin/console make:entity Groupe
    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255)
     */
    private $nom;
    /**
     * @ORM\ManyToOne(targetEntity="Groupe")
     * @ORM\JoinColumn(name="groupe_id", referencedColumnName="id")
     */
    private $groupeId;

    /**
     * @return mixed
     */
    public function getGroupeId()
    {
        return $this->groupeId;
    }

    /**
     * @param mixed $groupeId
     */
    public function setGroupeId($groupeId): void
    {
        $this->groupeId = $groupeId;
    }
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
insert into groupe values(null,'S3A1');
insert into groupe values(null,'S3A2');
insert into groupe values(null,'S3B1');
insert into groupe values(null,'S3B2');
->add('groupeId', EntityType::class, array(
    // query choices from this entity
    'class' => Groupe::class,

    // use the User.username property as the visible option string
    'choice_label' => 'nom',

    // used to render a select box, check boxes or radios
    // 'multiple' => true,
    // 'expanded' => true,
))
    {{ form_row(form.groupeId) }}
    <li> {{ etudiant.id }}  |   {{ etudiant.nom }}  | {{ etudiant.age }}  | {{ etudiant.adresse }}  | {{ etudiant.dateNaissance |date('d-m-Y')}}
         | {{ etudiant.groupeId.nom | default('pas de groupe')}}