Objectifs de cette séance (1h) :
Passer à une seule méthode :
Méthode gérant le GET : affichage du formulaire HTML
#[Route('/todo/new', name: 'todo_new_get', methods: ['GET'])]
public function newFormGet(): Response
{
$todo = new Todo();
// init valeurs par défaut
$form = $this->createForm(TodoType::class, $todo);
return $this->render('todo/new.html.twig', [
'todo' => $todo,
'form' => $form->createView(),
]);
}
Méthode gérant le POST : traitement des données soumises
#[Route('/todo/new', name: 'todo_new_post', methods: ['POST'])]
public function newFormPost(Request $request, TodoRepository $todoRepository): Response
{
$todo = new Todo();
$form = $this->createForm(TodoType::class, $todo);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$todoRepository->add($todo, true);
return $this->redirectToRoute('todo_index');
}
# else {
return $this->render('todo/new.html.twig', [
'todo' => $todo,
'form' => $form->createView(),
]);
# }
}
Fusionne en une seule méthode gestion du GET et du POST
Cf. Forms dans la documentation Symfony.
#[Route('/todo/new', name: 'todo_new', methods: ['GET', 'POST'])]
public function new(Request $request, TodoRepository $todoRepository): Response
{
$todo = new Todo();
$form = $this->createForm(TodoType::class, $todo);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$todoRepository->add($todo, true);
return $this->redirectToRoute('todo_index');
}
return $this->render('todo/new.html.twig', [
'todo' => $todo,
'form' => $form->createView(),
]);
}
Symfony peut aussi générer des classes contenant le code des contrôleurs et les formulaires
symfony console make:crud
#[Route('/new', name: 'todo_new', methods: ['GET', 'POST'])]
public function new(Request $request, TodoRepository $todoRepository): Response
{
$todo = new Todo();
$form = $this->createForm(TodoType::class, $todo);
$form->handleRequest($request);
// Gestion du POST
if ($form->isSubmitted() && $form->isValid()) {
$todoRepository->add($todo, true);
return $this->redirectToRoute('todo_index', [], Response::HTTP_SEE_OTHER);
}
// Gestion du GET ou problème validation
return $this->renderForm('todo/new.html.twig', [
'todo' => $todo,
'form' => $form,
]);
}
TodoType
est vue plus loin
Gabarit todo/new.html.twig
:
{% extends 'base.html.twig' %}
{% block title %}New Todo{% endblock %}
{% block main %}
<h1>Create new Todo</h1>
{{ include('todo/_form.html.twig') }}
<a href="{{ path('todo_list') }}">back to list</a>
{% endblock %}
Gabarit
templates/todo/_form.html.twig
:
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
(aussi inclus par todo/edit.html.twig
)
TodoType
gestionnaire de formulaireclass TodoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class,
['required' => false])
->add('completed', ChoiceType::class,
['choices' => [
'Maybe' => null,
'Yes' => true,
'No' => false ]
])
->add('project');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Todo::class,
]);
}
}
Mécanisme MapEntity des contrôleurs
{id}
de l’attribut Route
: extrait du chemin de la requête HTTP$todo
, instance de Todo
Todo
(appel à
TodoRepository::find()
automagique)class TodoController extends Controller
{
#[Route('/todo/{id}', name: 'todo_show'),
requirements: ['id' => '\d+'], methods: ['GET'])]
public function showAction(Todo $todo): Response
{
return $this->render('todo/show.html.twig', array(
'todo' => $todo,
));
}
Objectifs de cette séance (1h) :
Création d’une Todo
dans le contexte d’un Project
Version /todo/new
créée via make:crud
Formulaire TodoType
:
class TodoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('project');
la référence au projet de la tâche (Todo::project
) est gérée comme
une propriété « ordinaire » de la tâche dans le formulaire
Résultat : liste de choix parmi les projets
Pas ce qu’on souhaite, si une tâche ne peut pas changer de projet
project_show
, sur /project/{id}
)/project/{id}/addtodo
id
de projet (connu) !#[Route('/project/{id}/addtodo', name: 'todo_add',
methods: ['GET', 'POST'])]
public function addTodo(Request $request, Project $project,
TodoRepository $todoRepository): Response
{
$todo = new Todo();
$todo->setProject($project);
$form = $this->createForm(TodoType::class, $todo);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$todoRepository->add($todo, true);
// ...
Contexte :
{id}
de la routetâche créée dans son projet :
$todo->setProject($project)
project
du formulaire TodoType
Éviter la modification du champ project
.
Comportement optionnel (garde fonctionnement initial formulaire nouvelle tâche isolée).
$form = $this->createForm(TodoType::class, $todo,
['display_project' => false]);
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title')
->add('created', DateType::class, [
'widget' => 'single_text'])
->add('project', null, [
'disabled' => $options['display_project'] ]);
}
Objectifs de cette séance (1h) :
Exemple : utilisation de VichUploaderBundle
pour mettre des photos
dans les Pastes
#[ORM\Entity(repositoryClass: PasteRepository::class)]
#[Vich\Uploadable]
class Paste
{
//...
#[ORM\Column(nullable: true)]
private ?string $imageName = null;
#[Vich\UploadableField(mapping: 'pastes',
fileNameProperty: 'imageName')]
private $imageFile;
// .../...
imageName
stocké en base (Doctrine)imageFile
objet « fichier téléversé » Symfony /**
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $imageFile
*/
public function setImageFile(?File $imageFile = null): void
{
$this->imageFile = $imageFile;
//...
}
}
class PasteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder,
array $options)
{
$builder
->add('content')
->add('created')
->add('content_type')
->add('imageName', TextType::class,
['disabled' => true])
->add('imageFile', VichImageType::class,
[
'required' => false,
'delete_label' => 'Delete image ?'
])
;
}
make:crud