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' }) }}