Créer un deuxième contrôleur ProduitV3Controller
/produit par /produitv3 dans ce contrôleur (pour les URN dans les routes)"produit_ par "produitv3_ dans ce contrôleur (pour les routes dans les annotations)admin_produit_ par admin_produitv3_ dans ce contrôleur (pour les redirections)templates/admin/produit dans le dossier templates/admin/produitv3 (utiliser le gestionnaire de fichiers pour éviter les erreurs de refactoring)templates/admin/produitv3 et remplacer admin_produit_ par admin_produitv3_produitv3_show/ de la méthode index de ce deuxième contrôleurV3 : essai form dans le texte affiché par la vue (chaque vue y compris _formProduit.html.twig)
 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>
 
"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
Form dispose d'un constructeur de formulaires (le form builder) capable de générer tout type de formulaire à partir de champs qu'il connaît déjà (champs de type texte, de type date...) ;ceci crée une classe ProduitType
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)
    {
    }
templates/admin/produitv3/_formProduit.html.twig{% 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 %}
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(),
    ]);
}
commencer par modifier le contenu du fichier templates/admin/produitv3/_formProduit.html.twig
commencer par tester
<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 :
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);
    }
handleRequest($request), elle permet l'"hydratation" de l'objet form (mettre à jour le formulaire à l'aide des informations reçues de l'utilisateur)$form->isSubmitted() && $form->isValid() vérifie si l'objet formulaire form a été soumis et si les données sont valides : pour fonctionner il faut avoir saisi les annotations dans l'entité (ce référer au tp précédent, mais pour faire un test vous pouvez faire un copier/coller du code ci-dessous dans l'entité src/Entity/Produit.php)  /**
     * @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;
templates/admin/produitv3/_formProduit.html.twig, remplacer l'instruction {{ form_start(form) }} par{{ 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"
>
$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.
Pour mettre en forme avec bootstrap le formulaire : documentation sur la mise en forme
/templates/admin/produitv3/_formProduit.html.twig, le code de la balise {{ form_start}} par le code ci-dessous :{# 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
        $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' }) }}
 