Bonjour, bienvenue dans ce tutoriel. Dans la dernière partie, nous avons créé notre formulaire pour ajouter un article et nous l'avons afficher dans une vue twig. Dans cette partie, nous allons pouvoir enfin enregistrer notre article dans la base de données. Mais avant, nous allons un peu parler de la validation des formulaires.
Valider nos formulaires
Avant d'enregistrer un article dans la base de données, nous devons d'abord nous rassurer que le titre de l'article n'est pas null
ou vide. C'est le champ à vérifier dans notre cas, nous voulons permettre la création de brouillon, donc tout les autres champs peuvent être vides sauf le titre tant que l'article n'est pas publier.
Maintenant il faut définir cette règle dans notre classe PHP qui contient l'entité Article.php
, nous allons pour cela utiliser les annotations:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="App\Repository\ArticleRepository")
*/
class Article
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
// …
/**
* @Assert\NotBlank
* @ORM\Column(type="string", length=255)
*/
private $title;
// …
}
Tout ce que j'ai ajouter ici c'est l'annotation @Assert\NotBlank
pour l'attribut $title
, n'oublier pas le use
en haut pour inclure la Constraints
. Cette annotation va juste permettre de dire que ce champ ne peut pas être blank
, pas vide quoi. Et il y a plein d'autres contraintes qui existent et que vous pourrez trouver sur la documentation de Symfony.
Avant de continuer, il faut d'abord s'assurer que le validator est activer dans le fichier framework.yaml
:
# config/packages/frameyork.yaml
framework:
secret: '%env(APP_SECRET)%'
validation: { enable_annotations: true }
# …
Pour un début, par défaut, nous allons mettre tous les champs dans ArticleType.php
à required = false
comme ceci:
<?php
namespace App\Form;
// …
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('picture', FileType::class, ['required' => false])
->add('title', TextType::class, ['required' => false])
->add('content', TextareaType::class, ['required' => false])
->add('isPublished', CheckboxType::class, ['required' => false])
->add('categories', EntityType::class, [
'class' => Category::class,
'choice_label' => 'label',
'multiple' => true,
'expanded' => false,
'required' => false
])
;
}
// …
}
Rendez-vous maintenant sur 127.0.0.1:8000/add , actualisez la page puis cliquer sur le bouton Enregistrer sans rien remplir, il n'y a rien qui se passe.
Ce que nous allons faire, c'est d'abord de traiter le formulaire à chaque fois que l'utilisateur clique sur le bouton Enregistrer. Au fait nous allons dire au contrôleur, si l'utilisateur a soumis le formulaire (s'il a cliquer sur le bouton Enregistrer), il faut traiter le formulaire. Nous allons donc ajouter ce code dans le contrôleur (la methode add()
dans BlogController.php
):
<?php
namespace App\Controller;
use App\Entity\Article;
use App\Form\ArticleType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class BlogController extends AbstractController
{
public function index()
{
return $this->render('blog/index.html.twig');
}
public function add(Request $request)
{
$article = new Article();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return new Response('Le formulaire a été soumis…');
}
return $this->render('blog/add.html.twig', [
'form' => $form->createView()
]);
}
// …
}
Si vous actualisez la page et cliquez à nouveau sur le bouton Enregistrer
, on a l'impression que rien ne se passe, mais si vous regardez bien la debug toolbar (profiler) de Symfony, qui est cette barre tout en bas, vous verrez des liens en rouges, on va se concentrer sur les deux premiers qui se suivent.
Le profiler de Symfony
Cliquez dessus, pour voir un peu ce qui se passe.
Sur cette page il nous dit que le validator a trouver une erreur sur un champ title
Ici nous avons le formulaire qui contient l'erreur, ce qui serait pratique si on avait plusieurs formulaire sur la même page.
Nous arrivons à voir ces erreurs parce que nous sommes les développeurs et que nous sommes en mode développement. Quand nous serons en production, le profiler ne sera pas afficher, il faut donc trouver un moyen pour dire à l'utilisateur de remplir le champ title
.
Une idée? Allez un cadeau pour celui qui trouve.
Bon, j'espère que tu as pu le trouver, si c'est le cas laisse moi un commentaire ci-dessous. Indice, il faut utiliser une fonction twig.
Bref, vous vous rappelez de nos fonctions twig form_…()
, il y avait une fonction form_errors()
qui permet d'afficher les erreurs relatives à un champ, eh bien c'est lui que nous allons utiliser.
Dans le fichier article_form.html.twig
(celui qui contient notre formulaire), nous allons le modifier:
{# templates/includes/article_form.html.twig #}
{{ form_start(form, {'attr': {'class': 'row'}}) }}
<div class="input-field col s12 m12 l12">
{{ form_widget(form.picture) }}
</div>
<div class="input-field col s12 m6 l6">
{{ form_widget(form.title, {'attr': {'placeholder': 'Titre de l\'article'}}) }}
{{ form_label(form.title, 'Le titre de votre article') }}
<span class="error">{{ form_errors(form.title) }}</span>
</div>
{# … #}
<div class="input-field col s12 m12 l12">
<input type="submit" name="" value="Enregistrer" class="btn btn-primary">
</div>
{{ form_end(form) }}
Je rajoute donc juste la ligne:
<span class="error">{{ form_errors(form.title) }}</span>
Pour me permettre d'afficher un message d'erreur si le champ title
est vide.
Nous allons encore essayer d'envoyer notre formulaire avec un titre vide et:
Nous avons le message "This value should not be blank." qui s'affiche. Pour l'avoir avec ce style, j'ai du rajouter un peu de CSS dans mon fichier app.css
:
/* public/assets/css/app.css */
.input-field span.error {
color: #e04447;
font-size: 12px;
}
Main un instant, nous voulons afficher le message en français. Pour cela, nous allons retourner dans la classe Article.php
et modifier la ligne du @Assert\NotBlank
pour ajouter un message comme ceci:
// src/Entity/Article.php
// …
/**
* @Assert\NotBlank(message="Ce champ ne peut pas etre vide.")
* @ORM\Column(type="string", length=255)
*/
private $title;
// …
Et voilà, c'est tout.
Vous pouvez voir toutes les assertions possibles sur la documentation officielle de Symfony.
Enregistrer un article
Maintenant que nous avons notre formulaire, remplissons les champs et enregistrons notre article dans la base de données.
Vous avez le message "Le formulaire a été soumis…":
Regarder maintenant dans la base de données, la table article… Y a rien, aucun enregistrement.
En même temps le message afficher c'est "Le formulaire a été soumis…" et pas "L'article a été enregistrer". Haha, je vous ai eu là.
Bon, cela est dû au fait que nous n'avons pas encore explicitement enregistrer l'article lorsque l'utilisateur a soumis le formulaire. Ce que nous avons fait c'est juste afficher la réponse "Le formulaire a été soumis…". Pour enregistrer notre article, nous allons utiliser l'entity manager.
L'entity manager va nous permettre d'enregistrer une entité en base de données, modifier l'entité et aussi le supprimer, bref il va nous permettre de gérer toutes nos entités d'où son nom Entity Manager (Gestionnaire d'entités). C'est un service de doctrine. Pour le récupérer dans un contrôleur, on fait:
$em = $this->getDoctrine()->getManager();
Nous allons utiliser l'objet $em
pour enregistrer nos entités, les modifier et aussi les supprimer.
Pour enregistrer un nouvel article, nous allons utiliser le code ci-dessous:
<?php
namespace App\Controller;
// …
class BlogController extends AbstractController
{
// …
public function add(Request $request)
{
$article = new Article();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$article->setLastUpdateDate(new \DateTime());
if ($article->getIsPublished()) {
$article->setPublicationDate(new \DateTime());
}
$em = $this->getDoctrine()->getManager(); // On récupère l'entity manager
$em->persist($article); // On confie notre entité à l'entity manager (on persist l'entité)
$em->flush(); // On execute la requete
return new Response('L\'article a bien été enregistrer.');
}
return $this->render('blog/add.html.twig', [
'form' => $form->createView()
]);
}
// …
}
Nous initialisons la date de dernière modification, puis nous vérifions si l'article est publié et nous initialisons aussi la date de publication. Ce qui nous intéresse le plus ici, c'est l'entity manager, sur la ligne 24 nous récupérons l'entity manager, puis sur la ligne 25, nous disons à l'entity manager de gérer l'objet article, on persist l'objet article, mais jusqu'ici rien n'est fait, aucune requête. Sur la ligne 26, nous appelons la methode flush()
de l'entity manager, à partir de là, l'entity manager va regarder toutes les entités que nous lui avons confié avec persist()
et ajouter l'entité si celui-ci n'existe pas en base de données, ou le modifier s'il existe. Dans notre cas l'entité sera ajoutée en base de données.
Remplissez et validez le formulaire, vous devez avoir le message "L'article a bien été enregistrer". Si c'est le cas, regardez dans la table article de votre base de données, notre article a bien été ajouter, EUREKA!!! Nous avons réussi.
Maintenant, si vous regarder le champ picture dans la table article, la valeur enregistrée est un peu bizarre. Au fait l'image que nous avons choisi n'a pas vraiment été uploader. Pour ce faire, nous allons modifier le contrôleur comme ceci:
<?php
namespace App\Controller;
// …
class BlogController extends AbstractController
{
// …
public function add(Request $request)
{
$article = new Article();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$article->setLastUpdateDate(new \DateTime());
if ($article->getPicture() !== null) {
$file = $form->get('picture')->getData();
$fileName = uniqid(). '.' .$file->guessExtension();
try {
$file->move(
$this->getParameter('images_directory'), // Le dossier dans lequel le fichier va être charger
$fileName
);
} catch (FileException $e) {
return new Response($e->getMessage());
}
$article->setPicture($fileName);
}
if ($article->getIsPublished()) {
$article->setPublicationDate(new \DateTime());
}
$em = $this->getDoctrine()->getManager(); // On récupère l'entity manager
$em->persist($article); // On confie notre entité à l'entity manager (on persist l'entité)
$em->flush(); // On execute la requete
return new Response('L\'article a bien été enregistrer.');
}
return $this->render('blog/add.html.twig', [
'form' => $form->createView()
]);
}
// …
}
Le traitement de l'upload de l'image commence à la ligne 19, nous vérifions d'abord si l'utilisateur a bien essayé de charger une image, si c'est le cas, on récupère l'image, on la renomme et on l'enregistre dans le dossier /public/uploads/
, j'ai ici utilisé un paramètres pour mentionner ce dossier, vous allez faire de même dans le fichier config/services.yaml
, ajouter cette ligne en dessous de parameters
:
# …
parameters:
locale: 'en'
images_directory: '%kernel.project_dir%/public/uploads'
services:
# …
NB: Oublier pas de créer le dossier /public/uploads/
avant.
Et essayer maintenant de créer un nouvel article en chargeant une image, si tout va bien, vous trouverez votre image dans le dossier public/uploads
de votre projet, et dans la table article de la base de données, le champ picture contient maintenant le nom de l'image.
Modifier un article
Nous avons pu ajouter des articles, maintenant il faut pouvoir les modifier.
On avait deja créer une route pour pouvoir modifier nos articles et cette route prenait en paramètres l'id de l'article, la route c'est http://127.0.0.1:8000/edit/$id.
Ce que nous allons maintenant faire, c'est de modifier l'article qui a l'id 1, pour cela nous allons sur l'url http://127.0.0.1:8000/edit/1 et là nous avons une erreur qui nous dit que la variable form
n'existe pas dans le templates article_form.html.twig
Oubliez pas que c'est ce template qui contient le formulaire HTML pour ajouter ou modifier un article. Ce que nous allons donc faire, c'est de l'enlever pour l'instant du template pour modifier un article edit.html.twig
{# templates/blog/edit.html.twig #}
{% extends "base.html.twig" %}
{% block title %}Modifier{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12 m12 l12">
<h4>Modifier l'article {{ slug }}</h4>
</div>
</div>
{# {% include "includes/article_form.html.twig" %} #}
</div>
{% endblock %}
Je l'ai commenter ici. Si vous actualiser la page http://127.0.0.1:8000/edit/1 tout marche bien.
Nous allons maintenant remplacer le 1 dans "Modifier l'article 1" par le titre de l'article.
Récupérer une entité
Maintenant que nous avons enregistré notre en article dans la base de données, il faut le récupérer pour pouvoir le modifier. Pour cela, nous allons utiliser ce qu'on appelle un repository.
Le repository va tout simplement nous permettre de récupérer nos entités.
Si vous regardez dans le dossier src
de votre projet, vous allez trouver un dossier Repository
qui contient des fichiers PHP ArticleRepository.php
et CategoryRepository.php
. L'idée c'est qu'en Symfony nous n'allons pas écrire des requêtes SQL pour récupérer nos entités, nous allons plutôt créer des fonctions dans le repository (ArticleRepository.php
pour les articles) qui vont nous permettre de récupérer nos entités.
Dans ce tutoriel, nous n'allons pas créer de nouvelles fonctions pour récupérer nos entités, je prépare déjà un article ou je parle de Symfony et Doctrine, nous allons utiliser des fonctions déjà défini par Symfony. Nous allons utiliser la méthode find()
qui va nous permettre de récupérer une entité par son id.
<?php
namespace App\Controller;
use App\Entity\Article;
use App\Form\ArticleType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class BlogController extends AbstractController
{
// …
public function edit($id)
{
$article = $this->getDoctrine()->getRepository(Article::class)->find($id);
return $this->render('blog/edit.html.twig', [
'article' => $article
]);
}
// …
}
Nous récupérons l'article avec:
$article = $this->getDoctrine()->getRepository(Article::class)->find($id);
Nous récupérons d'abord le repository de l'entité Article
, puis nous appelons la methode find()
sur celui-ci.
Ensuite, nous envoyons l'article à notre vue. Nous allons donc le modifier pour afficher le titre de l'article:
{# templates/blog/edit.html.twig #}
{% extends "base.html.twig" %}
{% block title %}Modifier{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12 m12 l12">
<h4>Modifier l'article {{ article.title }}</h4>
</div>
</div>
{# {% include "includes/article_form.html.twig" %} #}
</div>
{% endblock %}
Si vous actualisez maintenant la page http://127.0.0.1:8000/edit/1, c'est le titre de l'article qui s'affiche.
Si vous essayez d'accéder à une entité que n'existe pas, vous avez une erreur 404. Essayez par exemple de modifier l'article qui a l'id 1000 http://127.0.0.1:8000/edit/1000.
Mais ici il y a un autre moyen pour nous de récupérer notre entité sans cette ligne en plus que nous avons écrite, en utilisant les ParamConverter.
C'est simple, nous disons à notre contrôleur que nous recevons une entité en paramètre, nous lui donnons la classe de l'entité en question, et a chaque fois que le contrôleur est appelé, il s'occupe lui même d'aller récupérer l'entité en essayant non seulement avec l'id, mais aussi avec toutes les autres propriétés de l'entité, s'il le trouve pas, il renvoie aussi une erreur 404.
<?php
namespace App\Controller;
use App\Entity\Article;
use App\Form\ArticleType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class BlogController extends AbstractController
{
// …
public function edit(Article $article)
{
return $this->render('blog/edit.html.twig', [
'article' => $article
]);
}
// …
}
Et voilà, si vous essayez ça marche bien.
Nous allons maintenant créer le formulaire comme nous l'avons déjà fait pour l'ajout d'un article et l'envoyer à la vue:
public function edit(Article $article)
{
$form = $this->createForm(ArticleType::class, $article);
return $this->render('blog/edit.html.twig', [
'article' => $article,
'form' => $form->createView()
]);
}
Et nous allons retirer le commentaire dans le fichier edit.html.twig
:
{% extends "base.html.twig" %}
{% block title %}Modifier{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12 m12 l12">
<h4>Modifier l'article {{ article.title }}</h4>
</div>
</div>
{% include "includes/article_form.html.twig" %}
</div>
{% endblock %}
Et actualiser la page, nous avons une erreur, au fait l'erreur dit juste que l'attribut picture
est un fichier, c'est comme tel que nous l'avons défini dans le formulaire, mais quand on enregistre notre entité en base de données, nous enregistrons une chaîne de caractères. Il faut savoir que quand nous créons un formulaire avec une entité qui contient des données, Symfony pré-rempli déjà le formulaire avec les informations de l'entité.
Alors ici, nous avons le champ picture
est un fichier dans le formulaire, et l'attribut picture
de l'entité $article
est un string
, Symfony a donc un problème avec cela et ça lui fait mal à la tête, ce que nous allons donc faire, c'est de rajouter une option dans la définition du champ picture
du formulaire et lui dire d'être indulgent avec le type de données qu'il reçoit. Bref nous allons lui dire, tient pas compte du type de données et cette option c'est data_class
que nous allons mettre à null
:
<?php
namespace App\Form;
// …
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('picture', FileType::class, [
'required' => false,
'data_class' => null
])
->add('title', TextType::class, ['required' => false])
->add('content', TextareaType::class, ['required' => false])
->add('isPublished', CheckboxType::class, ['required' => false])
->add('categories', EntityType::class, [
'class' => Category::class,
'choice_label' => 'label',
'multiple' => true,
'expanded' => false,
'required' => false
])
;
}
// …
}
Et on est bien.
Ce qui est encore plus cool, c'est que le formulaire est pré-rempli avec les informations que nous avons déjà enregistrer.
Nous allons donc pratiquement faire la même chose, traiter le formulaire, le valider puis l'enregistrer.
La seule différence que nous allons traiter, c'est comment prendre en compte l'image?
Ce que nous allons faire, c'est prévoir une section sur la vue pour afficher l'ancienne image si l'utilisateur avait déjà choisi une image avant (je viens d'avoir cette idée, même sur ce site je ne l'ai pas encore gérer). Dans le contrôleur, nous allons récupérer l'ancienne image avant de créer le formulaire, et à chaque fois que l'utilisateur soumet le formulaire, on vérifie s'il a charger une nouvelle image, si c'est le cas on charge alors la nouvelle image et on remplace l'ancienne, sinon on garde l'ancienne image.
D'abord la vue:
{# templates/blog/edit.html.twig #}
{% extends "base.html.twig" %}
{% block title %}Modifier{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12 m12 l12">
<h4>Modifier l'article {{ article.title }}</h4>
{% if article.picture is not null %}
<img width="300" src="{{ asset('uploads/' ~ article.picture) }}">
{% endif %}
</div>
</div>
{% include "includes/article_form.html.twig" %}
</div>
{% endblock %}
Sur la ligne 10, je vérifie bien si le champ picture
n'est pas null, alors j'affiche l'image.
Maintenant le contrôleur:
<?php
namespace App\Controller;
// …
class BlogController extends AbstractController
{
// …
public function edit(Article $article, Request $request)
{
$oldPicture = $article->getPicture();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$article->setLastUpdateDate(new \DateTime());
if ($article->getIsPublished()) {
$article->setPublicationDate(new \DateTime());
}
if ($article->getPicture() !== null && $article->getPicture() !== $oldPicture) {
$file = $form->get('picture')->getData();
$fileName = uniqid(). '.' .$file->guessExtension();
try {
$file->move(
$this->getParameter('images_directory'),
$fileName
);
} catch (FileException $e) {
return new Response($e->getMessage());
}
$article->setPicture($fileName);
} else {
$article->setPicture($oldPicture);
}
$em = $this->getDoctrine()->getManager();
$em->persist($article);
$em->flush();
return new Response('L\'article a bien été modifier.');
}
return $this->render('blog/edit.html.twig', [
'article' => $article,
'form' => $form->createView()
]);
}
// …
}
Et vous pouvez maintenant essayer, charger une image, ne chargez pas d'image, … Tout marche nickel. Si vous avez une erreur, n'hésitez pas à aller dans les commentaires.
Lister les articles
Nous allons maintenant lister les articles publier sur la page d'accueil. Pour cela, nous allons aussi utiliser une fonction déjà défini Symfony findBy()
qui prend 4 parametres:
- Un tableau des critères, c'est dans ce tableau nous allons mentionner que nous voulons juste les articles publier par exemple, ou les articles d'un auteur spécifique
- Un tableau pour définir l'ordre dans lequel les éléments sont arranger. Vous vous rappelez de ORDER BY en SQL? Eh bien c'est lui ici
- Un entier qui représente le nombre d'éléments à récupérer, 10 articles par exemple pour une pagination
- Un entier qui représente le début de la selection, on prend à partir du 10ème article par exemple
Les trois derniers paramètres ne sont pas obligatoires. Dans notre cas, nous allons récupérer tous les articles qui ont été publiés par ordre décroissant de la date de publication.
<?php
namespace App\Controller;
use App\Entity\Article;
use App\Form\ArticleType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class BlogController extends AbstractController
{
public function index()
{
$articles = $this->getDoctrine()->getRepository(Article::class)->findBy(
['isPublished' => true],
['publicationDate' => 'desc']
);
return $this->render('blog/index.html.twig', ['articles' => $articles]);
}
// …
}
Ici je récupère les articles (un tableau d'articles) toujours en passant par le Repository, dans le contrôleur index()
puis je les envoie à la vue. Il faut maintenant les afficher:
{# templates/blog/index.html.twig #}
{% extends "base.html.twig" %}
{% block title %}Accueil | {{ parent() }}{% endblock %}
{% block content %}
<div class="container">
<div class="row">
{% for article in articles %}
<div class="col s12 m4 l3">
<div class="article-card">
<img src="{{ asset('uploads/' ~ article.picture) }}" class="responsive-img">
<h2><a href="{{ path('article_show', {'id': article.id}) }}">{{ article.title }}</a></h2>
<span class="date">{{ article.publicationDate|date('d/m/Y') }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
Et voila, ajouter quelques articles et publier les, puis rendez vous à la page d'accueil
Nous avons utiliser la boucle for
de twig pour parcourir le tableau d'articles et afficher chaque article au passage.
Si vous cliquez maintenant sur le titre d'un article pour l'afficher, l'article s'ouvre bien, petit problème c'est l'id de l'article qui s'affiche à la place du titre, et ce n'est pas vraiment le contenu de l'article, ni son image, …
Nous allons donc regler cela, en commençant par le contrôleur, mais avant nous allons juste modifier notre route pour l'instant:
# …
article_show:
path: /show/{id}
controller: App\Controller\BlogController::show
# …
Au lieu de url
, nous allons le remplacer par id
pour l'instant.
Maintenant pour le contrôleur c'est les ParamConverter comme on le connait déjà:
<?php
namespace App\Controller;
// …
class BlogController extends AbstractController
{
// …
public function show(Article $article)
{
return $this->render('blog/show.html.twig', [
'article' => $article
]);
}
// …
}
Et la vue:
{# templates/blog/show.html.twig #}
{% extends "base.html.twig" %}
{% block title %}{{ article.title }}{% endblock %}
{% block content %}
<article class="container">
<div class="row">
<div class="col s12 m12 l8 offset-l2">
<h2>{{ article.title }}</h2>
<span>{{ article.publicationDate|date('d/m/Y') }}</span>
<p>
<img src="{{ asset('uploads/' ~ article.picture) }}" class="responsive-img">
</p>
<span class="categories">{% for category in article.categories %} {{ category.label }}{{ loop.last ? '' : ',' }} {% endfor %}</span>
</div>
</div>
<div class="row">
<div class="col s12 m12 l8 offset-l2">
<p>
{{ article.content }}
</p>
</div>
</article>
{% endblock %}
Maintenant, nous pouvons lire tous les articles publiés en juste cliquant dessus.
La documentation sur la boucle for en twig.
Ça y est, on a bien fait le tour la. Nous allons donc nous limiter ici pour l'instant. Next time, nous allons parler de l'authentification, nous allons donc pouvoir nous connecter et tout. Merci à bientôt.