Utilisation des formulaires symfony

Mise en Route


ATTENTION à l'instruction include dans les vues pour ajouter et éditer un produit (phpStorm renomme mal les chemins)


Ajouter un lien la vue du menu templates/admin/_nav.html.twig

<a class="dropdown-item" href="{{ path('admin_produitv3_show') }}">Gestion des produits (v3)</a>



formulaire sur cette entité

"SYMFONY" prévoit dans les bonnes pratiques de programmation de sortir le code de l'objet du formulaire dans un autre fichier.

symfony console make:Form ProduitType --help
symfony console make:Form ProduitType Produit


ceci crée une classe ProduitType

mise en place

Vider le contenu des 2 méthodes addProduit et editProduit dans ce nouveau contrôleur

    /**
     * @Route("/produitv3/add", name="produitv3_add", methods={"GET","POST"})
     */
    public function addProduit(Request $request, ValidatorInterface $validator)
    {

    }


    /**
     * @Route("/produitv3/edit/{id}", name="produitv3_edit",  requirements={"<\d+>?1"}, methods={"GET","PUT"})
     */
    public function editProduit(Request $request, $id=null)
    {

    }
{% extends "admin/layout.html.twig" %}
{% block body %}
    <div class="container">
            <legend>Créer un produit (V3 : essai form)</legend>
            {{ include('admin/produitv3/_formProduit.html.twig', {action: 'Créer'}) }}
    </div>
{% endblock %}

utilisation du formulaire

Pour la suite, ce tp s'inspire de 2 tutoriaux ( ou tutoriels on devrait dire didacticiels ;-) )



Après avoir ajouter l'espace de nom use App\Form\ProduitType; pour pouvoir utiliser le formulaire :


$produit = new Produit();
$form = $this->createForm(ProduitType::class, $produit);

return $this->render('admin/produitv3/addProduit.html.twig', [
    'form' => $form->createView(),
]);
/**
* @Route("/produitv3/edit/{id}<\d+>", name="produitv3_edit",  methods={"GET","PUT"})
 */
public function editProduit(Request $request, $id=null)
{
    $produit = $this->getDoctrine()->getRepository(Produit::class)->find($id);
    if (!$produit)  throw $this->createNotFoundException('No produit found for id '.$id);
    $form = $this->createForm(ProduitType::class, $produit);

    return $this->render('admin/produitv3/editProduit.html.twig', [
        'form' => $form->createView(),
    ]);
}
<h1>{{ action }} un produit</h1>
{{ form(form) }}


<h1>{{ action }} un produit</h1>
{{ form_start(form) }}
        {{ form_row(form.nom) }}
<label for="">le prix :</label>
        {{ form_widget(form.prix) }}
<button type="submit" class="btn btn-primary">{{ action|default('Valider') }}</button>
{{ form_end(form) }}



Pour information :



traiter les données reçues

ajouter après la déclaration du formulaire, le code ci-dessous

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $data = $form->getData();
        dump($data->getNom());
        dd($data);
    }
  /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="saisir un nom")
     * @Assert\Length(min=2, minMessage = "votre nom doit être composé de {{ limit }} caractères minimum")
     */
    private $nom;

    /**
     * @ORM\Column(name="prix", type="decimal", precision=8, scale=2, nullable=true)
     * @Assert\NotBlank(message = "Saisir un prix ")                                           //***
     * @Assert\Type(type="numeric",message =  "La valeur {{ value }} n'est pas valide, le type est {{ type }} ")
     * @Assert\Regex(
     *     pattern = "/^[0-9]{1,}\,{0,1}[0-9]{0,}$/",
     *     message = "Seulement un entier positif."
     *     )
     */
    private $prix;
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}

Cette instruction désactive la validation html5 (plus de balise input de type date number ...., que des input type text)


Par défaut, un champ input généré par le formulaire a cette structure :

<input 
    type="text"
    id="produit_nom"
    name="produit[nom]"
    maxlength="30"
    pattern=".{3,}"
    class="form-control"
    value="pomme"
>



persister les données

$this->addFlash('notice', 'Version 3 : Produit ' . $Produit->getNom() . ' ajouté');
return $this->redirectToRoute('admin_produitv3_showProduits');
      $form = $this->createForm(ProduitType::class, $produit, [
            'action' => $this->generateUrl('admin_produitv3_edit',['id'=>$id]),
            'method' => 'PUT',]);

Cependant, ça fonctionnait sans faire cette manipulation avant.

mise en forme avec bootstrap des objets "formulaire" de symfony

Pour mettre en forme avec bootstrap le formulaire : documentation sur la mise en forme

{# dans le fichier  /templates/admin/produitv3/_formProduit.html.twig #}
{% form_theme form 'bootstrap_4_layout.html.twig' %}

{{ form_start(form, {'attr': {'novalidate': 'novalidate', 'class': 'col-lg-5' }}) }}

Il est plus simple d'imposer pour tous les formulaires le style boostrap_4, modifier le fichier config/packages/twig.yaml avec le code ci-dessous et retirer la balise {% form_theme form 'bootstrap_4_layout.html.twig' %} de la vue ci-dessus (_formProduit.html.twig)

# config/packages/twig.yaml
twig:
    form_themes: ['bootstrap_4_layout.html.twig']
find . -name bootstrap_4_layout.html.twig
ls ./vendor/symfony/twig-bridge/Resources/views/Form/
subl ./vendor/symfony/twig-bridge/Resources/views/Form/bootstrap_4_layout.html.twig

documentation symfony pour modifier le style d'un formulaire

Il existe tous les thèmes de formulaire en cherchant un peu, exemple de thème Materialize trouvé sur ce tuto


Modification de l'objet "Form"

        $builder
            ->add('nom', TextType::class, array(
                'constraints' => [
                    new Assert\NotBlank(['message' => 'Saisir le nom de l\'objet']),
                    new Assert\Length(['min' => 2, 'minMessage' => '2 caractères minimum pour le nom']),
                ],
                'required' => false
            ))
            ->add('stock', NumberType::class, array(
                'constraints' => [
                    new Assert\NotBlank(['message' => 'Saisir le stock de produit']),
                    new Assert\Type(['type' => 'numeric', 'message' => 'La valeur saisie n\'est pas un chiffre']),
                ],
                'required' => false
            ))
            ->add('dateLancement', DateType::class, array(
                'constraints' => [
                    new Assert\Date(['message' => 'La date doit avoir un format d/m/Y et ne peut pas être vide']),
                ],
                'widget' => 'single_text',
                'format' => 'dd/MM/yyyy',
                'required' => false,
                'placeholder' => 'jj/mm/aaaa',
                'html5' => false,
            ))
            ->add('disponible', TextType::class, array(
                'constraints' => [
                    new Assert\NotBlank(['message' => 'Saisir si le produit est disponible ou non']),
                ],
                'required' => false
            ))
            ->add('typeProduit', EntityType::class, array(
                'constraints' => [
                    new Assert\NotBlank(['message' => 'Choisir le type du produite']),
                ],
                'required' => false,
                'class' => TypeProduit::class,
                'choice_label' => 'libelle',
                'placeholder' => 'default'
            ))
            ->add('photo', TextType::class, [
                 'label' => 'photo',
                 'required' => false
               ])
            ->add('submit', SubmitType::class)

Pensez à ajouter les bons "namespace". Ci dessous, une liste des namespace à ajouter pour utiliser les objets type du formulaire

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\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;






ANNEXES

        {{ form_row(form.submit, { 'label': 'Ajouter un produit' }) }}