Installation d'un projet Symfony. Explication de l'arborescence du framework.
ln -s public htdocs
composer require symfony/apache-pack
Utilisation de la documentation pour créer un contrôleur et la view associée.
php bin/console make:controller
Utilisation du contrôleur pour faire un traitement PHP, démonstration du système de routing.
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function index(): Response
{
$variable = 'Totoooooo';
return $this->render('home/index.html.twig', [
'controller_name' => 'HomeController',
'variable' => $variable,
]);
}
}
Syntaxe du langage twig et utilisation des variables injecté.
{% if variable is not null %}
{{ variable }}
{% else %}
Je n'existe pas !!!
{% endif %}
Pour bien prendre en main la manipulation du MVC dans Symfony, nous allons créer une "maquette" interactive.
- Installer Symfony sur Devilbox grâce à la documentation Symfony
- Faire un lien symbolique entre le dossier public et htdocs
Pour toute création de nouvelles classes PHP, on utilisera généralement la console de Symfony qui embarque une boîte à outils complète pour nous aider à aller plus vite.
Avec cette commande vous pouvez créer des controller custom :
php bin/console make:controller
- Vous l'appellerez Home (il s'appellera HomeController dans le dossier des controller) et il vous sera utile pour le routage de la page d'accueil.
- Vérifiez que le chemin du template mène à
index.html.twig
du dossierhome
.
- Récupérer les pages HTML du projet ici : payetonpote
- Copier le dossier "assets" dans le dossier Symfony
public
(c'est la racine du serveur web). - Copier toute la page
index.html
et la coller dans le fichierbase.html.twig
tout en conservant le code existant. On va en réutiliser une partie (les balises twig !) - Repérer l'endroit où termine le header et où commence le footer. Couper ce code et le
coller dans la partie "block body" du template
index.html.twig
dans le dossierhome
. - De retour dans
base.html.twig
, il nous reste à replacer les blocks "stylesheets", "title", "body", et "javascripts". ATTENTION ! pour les blocks stylesheets et javascripts, on les place après les scripts déjà existants. C'est parce qu'ils seront utilisés sur toutes les pages. De plus, rajoutez un "/" aux liens de script dans le footer et de style dans le header. - Attention à mettre
{% block stylesheets %}{% endblock %}
sous les lignes d'appel du style CSS (et à ne pas les englober) dans le head et{% block javascripts %}{% endblock %}
sous les lignes d'appel du Javascript (et à ne pas les englober) dans le footer.
La racine du projet doit mener sur la page index.html.twig
du dossier home que vous venez
d'intégrer.
- J'ai compris le chemin du code dans un environnement MVC.
- Je sais router les pages de mon projet dans un controller.
Vous allez créer un projet de paiement collaboratif. Ce sera une preuve de concept pour un site de type leetchi, mais pourquoi pas aussi pour des paris entre potes, des courses communes, etc.
Analyse des besoins :
-
En tant qu'utilisateur, je crée une campagne de financement collaborative avec les champs suivants :
- Nom de la campagne : 120 caractères maximum
- Contenu de la campagne : texte libre via éditeur markdown
- Objectif de cagnotte : nombre qui servira de simple indicateur
- Nom
-
En tant qu'utilisateur, j'accède à une campagne partagée par l'auteur de la campagne via URL sécurisée et aléatoire.
-
En tant que participant, je peux modifier le contenu de la campagne et le budget, mais pas le titre.
-
En tant que participant, je peux payer n'importe quel montant. En plus de ma carte, je suis invité à saisir mon email. Le paiement est ensuite comptabilisé dans la cagnotte et visible dans une liste.
Note importante : Il y aura une limitation majeure : le destinataire des paiements ne sera pas dynamique : ce sera une seule personne pour toute l'application. Après avoir réussi à terminer ce projet, il serait possible de le continuer avec un système qui relie les créateurs de campagnes avec leur compte bancaire. Mais nous n'irons pas jusque-là dans un premier temps.
Lexique :
-
Utilisateur : Un visiteur ayant accès à la page d'accueil.
-
Participant : Un utilisateur qui participe à une campagne. Participer à une campagne signifie avoir payé ou enregistré une dépense.
-
Campagne : Un projet de financement créé dans l'application.
-
Cagnotte : La tirelire commune calculée en fonction des paiements et dépenses de chacun.
-
Objectif de cagnotte : Nombre indicatif qui n'a aucun effet.
-
Dépenses : Liste composée de montants en € associés à des participants.
Vous avez commencé l’intégration du front-end de l’application dans le mini-tp de la maquette, nous allons maintenant développer les fonctionnalités dans le backend PHP.
Voici le code de la BDD : [SQL] payetonpote - Pastebin.com. Reliez votre bdd en modifiant le .env du projet symfony. Prenez le temps d'étudier l'architecture de la BDD. Essayez de visualiser l'interaction entre les tables ainsi que leurs contenus pour le projet.
Deux commandes vont suffire à générer les modèles du projet, appelés Entity sur Symfony. Magique ! La première commande permet de générer les classes Entity. La dernière commande permet de générer les getter et setters. Il faut les utiliser dans la console du projet en ouvrant la console directement sur VS Code, par exemple.
php bin/console doctrine:mapping:import App\Entity annotation --path=src/Entity
php bin/console make:entity --regenerate App
Vous pensez que Symfony, c'est déjà magique ? Ce n'est pas fini ! Nous allons désormais créer en une seule ligne de commande le Controller d'un Model, toutes les principales fonctions (C.R.U.D. Create, Read, Update, Delete) ainsi que les Views (templates) associés à ces méthodes !
php bin/console make:crud
La console vous demandera l’entité souhaitée, vous choisirez Campaign. Et vous nommerez le controller associé avec le même nom.
Prenez le temps d'étudier tout le code que vous avez généré... c'est bon, vous avez tout compris ? Bien, il est temps de passer à l'intégration !
Dans cette étape, nous allons profiter du CampaignController
que vous venez de créer
pour finaliser les routes et le rendu de toutes les pages. Le travail ici consiste à
remplacer le code généré de symfony par le code HTML fournis dans les 4 pages du TP.
Vous devrez ajouter une page payment.html.twig
dans le dossier templates/campaign
et le controller PaymentController
dans le dossier Controller.
Une chose importante à savoir : Les formulaires de Symfony sont eux aussi des objets à part entière !
Lors de la création du CRUD de campaign, un fichier CampaignType.php
à été créé dans le
dossier Form de src
.
Lors de l'affichage de la view new.html.twig
, une variable contenant le formulaire a été envoyé
depuis le controller !
#[Route('/new', name: 'app_campaign_new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$campaign = new Campaign();
$form = $this->createForm(CampaignType::class, $campaign); // ICI
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($campaign);
$entityManager->flush();
return $this->redirectToRoute('app_campaign_index', [], Response::HTTP_SEE_OTHER);
}
return $this->render('campaign/new.html.twig', [
'campaign' => $campaign,
'form' => $form, // ET LA
]);
}
Cette variable contient une instance de CampaignType fait avec la méthode de symfony createForm()
.
Cette variable est utilisée ici, dans _form.html.twig
{% block body %}
<h1>Create new Campaign</h1>
{{ include('campaign/_form.html.twig') }}
<a href="{{ path('app_campaign_index') }}">back to list</a>
{% endblock %}
Le formulaire ressemble à ceci pour l'instant :
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
Il va falloir y mettre celui qui est fourni dans les pages html de la maquette
CampaignType a été généré automatiquement pour remplir toutes les colonnes de votre table. il
va falloir le modifier pour enlever les champs que l'on ne souhaite pas remplir comme
updated_at
et created_at
.
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title')
->add('content')
->add('createdAt') // A RETIRER
->add('updatedAt') // A RETIRER
->add('goal')
->add('name')
;
}
Ce "Formbuilder" est la pour générer un objet à partir des champs du formulaire, ce qui nous permettra de les valider ou de spécifier des caractéristiques comme des longueurs maximales de champs À savoir que pour l'affichage dans les templates, nous ne sommes pas obligés d'utiliser la syntax {{ form_start(form) }}
Il est indispensable d'utiliser la gestion des formulaires de symfony, mais vous pouvez les écrire en html classique.
Les bases du projet sont prêtes, nous allons maintenant développer les fonctionnalités !
L'enregistrement de la campagne provoquera une erreur tant qu'on n'indique pas à Symfony que :
- On souhaite nous même assigner la propriété ID (au lieu de l'auto-increment habituellement utilisé)
- La colonne
id
ne possède pas de setter donc nous devrons le rajouter manuellement dans le fichier Entity\Campaign.php
/**
* @var string
* @ORM\Column(name="id", type="string", length=32, nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="NONE")
*/
private $id;
public function setId(string $id): self
{
$id = md5(random_bytes(50));
$this->id = $id;
return $this;
}
Dans le if de cette méthode, nous allons ajouter le setId de campaign :
if ($form->isSubmitted() && $form->isValid()) {
$campaign->setId(); //il faut définir l'id de la campagne !
$entityManager->persist($campaign);
$entityManager->flush();
return $this->redirectToRoute('app_campaign_index', [], Response::HTTP_SEE_OTHER);
}
Une chose importante à savoir : Les formulaires de symfony sont eux aussi des objets à part entière !
Le code html du formulaire de paiement d'une campagne se trouve dans les maquettes du TP.
vous devrez créer une page payment.html.twig
qui contiendra ce formulaire.
Cette fonction devra se faire en plusieurs étapes :
- Récupération du montant du paiement.
- Instanciation la campagne.
- Enregistrement du participant.
- Enregistrement du paiement.
- Redirection vers le show de la campagne.
Maintenant que vous savez enregistrer un paiement, il va falloir changer toutes les données en dure dans les templates :
- La barre de progression doit correspondre au pourcentage de complétion de l'objectif de la campagne.
- Le nombre de participants.
- Le montant total récolté pour une campagne.
- La liste des participants avec leur participation.
Les utilisateurs du projet doivent désormais avoir la possibilité de ne pas afficher leur identité ou le montant de leur paiement s'ils cochent les champs correspondants
- Ces ajouts de fonctionnalités impliquent de faire des modifications dans la base de données.
- Il n'est pas possible d'enregistrer un paiement négatif
- Si un paiement dépasse le goal de la campagne, il n'est plus possible de participer