Symfony 4 - Créer un blog pas à pas - Afficher les données de la base

10 août 2019 - : MVC Tutoriel Symfony - : 7 commentaires - : 879 - Tutoriel Controllers Framework Base de données Models MVC Routes Views Symfony

Visualisez les fichiers de cette série sur GitHub

Maintenant que nous avons vu comment créer les entités, les contrôleurs et les vues, il est temps de connecter tous ces éléments.

Dans cet exemple, nous allons commencer à créer la page qui affichera tous les articles.

Ils seront triés du plus récent au plus ancien et affichés sur la route "/actualites"

Nous devrons suivre plusieurs étapes :

  • Identifier ou créer le contrôleur
  • Identifier l'entité qui nous permettra d'accéder aux données
  • Identifier ou créer la vue qui permettra d'afficher la liste des articles

Le contrôleur

Nous allons rassembler toutes les fonctionnalités liées aux articles dans un contrôleur unique qui n'existe pas encore et qui s'appellera "ArticlesController"

Créer le contrôleur

Afin de créer le contrôleur, nous allons utiliser la commande vue précédemment

php bin/console make:controller

A la question du nom, nous entrons "ArticlesController".

Le fichier "ArticlesController.php" est créé et contient le code suivant

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class ArticlesController extends AbstractController
{
    /**
     * @Route("/articles", name="articles")
     */
    public function index()
    {
        return $this->render('articles/index.html.twig', [
            'controller_name' => 'ArticlesController',
        ]);
    }
}

Il contient une seule méthode appelée "index" et correspondant à la route "/articles"

Modifier le contrôleur

Nous allons modifier ce contrôleur pour qu'il corresponde à ce que nous souhaitons faire, accéder par la route "/actualites".

Par extension, toutes les routes concernant les articles seront accessibles par une route commençant par "/actualites".

Les annotations nous permettent de configurer ce comportement et de donner un préfixe de route pour toutes les méthodes de notre contrôleur.

Cette annotation est à inclure juste au dessus de la déclaration de classe comme ceci

// lignes 1 à 6

/**
 * Class ArticlesController
 * @package App\Controller
 * @Route("/actualites", name="actualites_")
 */
class ArticlesController extends AbstractController
{

Cette annotation effectue deux choses. Elle définit le préfixe "/actualites" et un préfixe de nom de route "actualites_".

Nous allons adapter l'annotation de la méthode "index" afin qu'elle prenne en compte ce préfixe, elle sera comme ceci

/**
 * @Route("/", name="articles")
 */
public function index()
{

La route devient "/" afin de prendre en compte le préfixe.

Accéder aux données

Nous allons accéder à la base de données pour y récupérer la liste des articles.

Lors de la création de notre entité "Articles", un fichier appelé "ArticlesRepository.php" a été créé dans le dossier "src/Repository". Ce fichier permet d'accéder aux données de la table "articles" de la base de données par l'intermédiaire de 4 méthodes pré existantes ou toute méthode personnalisée que nous pourrions créer.

Les 4 méthodes pré existantes sont :

  • find : qui permet de trouver un enregistrement depuis son id
  • findOneBy : permet de trouver un enregistrement en indiquant des critères
  • findAll : retourne tous les enregistrements
  • findBy : permet de trouver plusieurs enregistrements en indiquant des critères

Afin d'accéder à tous nos articles mais triés du plus récent au plus ancien, nous allons utiliser la méthode "findBy".

Pour ce faire, nous utiliserons une syntaxe basée sur l'ORM "Doctrine", un système qui permet d'accéder à la base de données sans se soucier des requêtes. Nous l'avons déjà utilisé lors de la création des entités et des migrations.

Doctrine permet d'accéder au fichier "Repository" et d'exécuter les méthodes qu'il contient pour récupérer les données.

Pour accéder à la liste de nos articles, nous utiliserons la ligne suivante

// Méthode findBy qui permet de récupérer les données avec des critères de filtre et de tri
$articles = $this->getDoctrine()->getRepository(Articles::class)->findBy([],['created_at' => 'desc']);

La méthode "findBy" accepte plusieurs paramètres :

  • Un tableau (ici vide) permettant de préciser les critères de filtre (équivalent WHERE en SQL)
  • Un tableau, optionnel, contenant les critères de tri (équivalent ORDER BY en SQL), ici un tri décroissant sur "created_at"
  • Une valeur, optionnelle, permettant de limiter le nombre de résultats (équivalent LIMIT en SQL)
  • Une valeur, optionnelle, permettant de déterminer le 1er résultat (équivalent OFFSET en SQL)

Nous utilisons dans notre exemple la classe "Articles", il sera nécessaire de l'appeler par l'ajout de la ligne

use App\Entity\Articles;

Notre contrôleur ressemble maintenant à ceci

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Articles;

/**
 * Class ArticlesController
 * @package App\Controller
 * @Route("/actualites", name="actualites_")
 */
class ArticlesController extends AbstractController
{
    /**
     * @Route("/", name="articles")
     */
    public function index()
    {
        // Méthode findBy qui permet de récupérer les données avec des critères de filtre et de tri
        $articles = $this->getDoctrine()->getRepository(Articles::class)->findBy([],['created_at' => 'desc']);

        return $this->render('articles/index.html.twig', [
            'controller_name' => 'ArticlesController',
        ]);
    }
}

Envoyer les données à la vue

Les données ayant été extraites de la base de données, il faut maintenant les envoyer à la vue.

Ceci s'effectuera dans la méthode "render" qui accepte un tableau en paramètre qui contiendra les données à envoyer.

Nous allons modifier cette ligne comme ceci

return $this->render('articles/index.html.twig', [
    'articles' => $articles,
]);

A noter que le tableau peut prendre une structure plus compacte au moyen de la fonction compact de php.

return $this->render('articles/index.html.twig', compact('articles'));

Afficher les données

Il nous reste maintenant à afficher les données dans notre vue.

Nous avons envoyé la liste des articles sous le nom "articles", nous pourrons donc y accéder sous ce nom dans notre dichier "Twig".

Le contrôleur fait appel au fichier "index.html.twig" situé dans "templates/articles". Nous allons donc modifier ce fichier pour qu'il affiche nos articles.

Ces articles sont envoyés sous forme d'un tableau qu'il va falloir parcourir.

Pour ce faire, nous allons faire une boucle sur le tableau. En php, il suffirait d'utiliser le foreach, mais nous sommes dans un fichier twig, le php n'est pas utilisable.

Heureusement, nous avons accès aux boucles dans les fichiers twig au moyen du "for..in"

Nous bouclerons donc sur notre variable "articles" de cette façon

{# nous bouclons sur articles. A l'intérieur de la boucle, nous utiliserons la variable article #}
{% for article in articles %}
    {# Contenu de la boucle #}
{% endfor %}

Si nous souhaitons afficher une variable, nous utiliserons cette syntaxe

{{ variable }}

Si il s'agit d'un tableau, nous utiliserons cette syntaxe

{{ tableau.index }}

De ce fait, notre fichier twig sera le suivant

{% extends 'base.html.twig' %}

{% block title %}Liste des articles{% endblock %}

{% block body %}
    <h1>Liste des articles</h1>
    {% for article in articles %}
        <h2>{{ article.titre }}</h2>
        <div>{{ article.contenu }}</div>
    {% endfor %}
{% endblock %}

Et voilà, la liste des articles est maintenant accessible.

Dans un prochain article nous verrons comment créer les liens entre les différentes pages.

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder aux forums de Nouvelle-Techno.fr ou au serveur Discord pour une entraide par chat

Visualisez les fichiers de cette série sur GitHub

Partager

Partager sur Facebook Partager sur Twitter Partager sur LinkedIn

Commentaires

Ecrire un commentaire

Thom a écrit le 10 novembre 2019 à 19:13

Bonjour,

Un grand merci pour la reponse rapide. Et beaucoup de félicitations pour le temps que vous consacrez aux autrea afin de les permettre d'évoluer dans la compréhension du développement informatique.

j'extrais les données des deux tables que j'envoi vers la vue avec deux variables differentes, de deux controllers différents également.

cependant j'ai une erreur qui me signale que la seconde variable n'existe pas.

Merci pour votre réponse.

Répondre

Nouvelle-Techno.fr a répondu le 11 novembre 2019 à 09:31

Bonjour,

Est-il possible de voir le code de la méthode du contrôleur et du template ?

Merci

Répondre

Thom a répondu le 11 novembre 2019 à 14:35

Bonjour

Voici le controller ArticleController

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Article;
use App\Form\ArticleType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use App\Repository\ArticleRepository;

class ArticleController extends AbstractController
{
    /**
    * @var ArticleRepository
    */

    private $repository;

    public function __construct(ArticleRepository $repository, ObjectManager $em)
    {
        $this->repository = $repository;//initialisation
        $this->em = $em;//initialisation
    }


    public function indexaction()
    {
        $articles = new Article();
        $entityManager = $this->getDoctrine()->getManager();
        $articles = $entityManager->getRepository("App\Entity\Article")->findBy(
            array('section' => 'affichg1'), // Critere
            array('created_at' => 'desc'), // Tri
            2,                            // Limite
            0                            // Offset
            );

        return $this->render('article/index.html.twig', ['articles' => $articles]);     
    }

Voici le Controller Articlle

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Articlle;
use App\Form\articlleType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use App\Repository\ArticlleRepository;
use Doctrine\Common\Persistence\ObjectManager; 

class ArticlleController extends AbstractController
{
    /**
    * @var ArticlleRepository
    */

        private $repository;

        public function __construct(ArticlleRepository $repository, ObjectManager $em)
        {
            $this->repository = $repository;//initialisation
            $this->em = $em;//initialisation
        }
   
    public function myarticlle()
    {
        $articlles = new Articlle();
        $em = $this->getDoctrine()->getManager();
        $articlles = $em->getRepository("App\Entity\Articlle")->findBy(
            array('section' => 'politik'), // Critere
            array('created_at' => 'desc'), // Tri
            1,                            // Limite
            0                            // Offset
            );

        return $this->render('article/index.html.twig', ['articlles' => $articlles]);
        
    }

 voici la view pour les deux controller

{% extends 'base.html.twig' %}

{% block title %}Hello MyHomeController!{% endblock %}

{% block body %}

    <div class="container-fluid" >

        <div class="row" id="general">

            <div class="col-md-3" id="colonegauche" style="float:left; border:1px solid green; margin-left:30px;">
                {{ include('Pages/articlegauche.html.twig') }}
            </div><!--FIN DIV ID COLONE GAUCHE-->

            <div class="col-md-5" id="colonecentre" style="float:left; border:1px solid red; margin-left:20px; margin-right:20px;">
                {{ include('Pages/articlecentre.html.twig') }}
            </div><!--FIN DIV ID COLONE CENTRE-->

            <div class="col-md-3" id="colonedroite" style="float:left; border:1px solid yellow;">
                {{ include('Pages/articledroite.html.twig') }}
            </div><!--FIN DIV ID COLONE DROITE-->

           

        </div><!--FIN DIV ID GENERAL-->

    </div><!--FIN DIV CLASS CONTAINER-->

{% endblock %}

Voici la view de Pages/articlegauche.html.twig


{% for article in articles %}

<div class="mytitlle" style="width:300px;"><a class="mytitlle" href="{{ path('show', {'id': article.id }) }}">{{ article.titre }}</a></div>
<div class="myprop" style="width:300px;">
    <span class="myville" >{{ article.ville }}</span> |
    <span class="date" >{{ article.createdat|date('D M Y - H:i') }}</span>
</div>
<div class="myfoto">
    <img class="roundedImage" src="{{ asset('uploads/' ~ article.foto) }}"  style="width:30px; height:30px;"> 
</div>
<div class="myauthor" style="margin-top:-33px; margin-left:35px;">{{ article.auteur }}</div> 
<div class="mywork">{{ article.profession }}</div> 
<img src="{{ asset('uploads/' ~ article.picture) }}" class="responsive-img"
    style="width:300px; height:180px; margin-top:15px; margin-bottom:5px;">

<div class="myresum" style="margin-bottom:10px;">{{ article.resume }}</div>

    <a href="{{path('show', {id: article.id})}}" class="btn btn-primary">Lire la suite</a>

{% endfor %}


            

Voici la view de Pages/articlecentre.html.twig


{% for articlle in articlles %}

<div class="mytitlle"><a class="mytitlle" href="{{ path('show', {'id': articlle.id }) }}">{{ articlle.title }}</a></div>
<div class="myville">{{ articlle.resume }}</div> 

<img src="{{ asset('uploads/' ~ articlle.imagge) }}" class="responsive-img"
    style="width:300px; height:180px; margin-top:15px; margin-bottom:5px;">
    <br>

    <a href="{{path('show', {id: articlle.id})}}" class="btn btn-primary">Lire la suite</a>

{% endfor %}



Merci de la reponse.

Répondre

Nouvelle-Techno.fr a répondu le 11 novembre 2019 à 15:03

Re bonjour,

Je comprends mieux.

Une vue ne peut être appelée que par un seul contrôleur à la fois, il est donc nécessaire de récupérer les deux jeux de données dans un seul contrôleur.

Voici comment je le verrais

 public function indexaction()
    {
        $entityManager = $this->getDoctrine()->getManager();
        $articles = $entityManager->getRepository("App\Entity\Article")->findBy(
            array('section' => 'affichg1'), // Critere
            array('created_at' => 'desc'), // Tri
            2,                            // Limite
            0                            // Offset
            );
        $articlles = $em->getRepository("App\Entity\Articlle")->findBy(
            array('section' => 'politik'), // Critere
            array('created_at' => 'desc'), // Tri
            1,                            // Limite
            0                            // Offset
            );

        return $this->render('article/index.html.twig', ['articles' => $articles, 'articlles' => $articlles]);     
    }

 

Répondre

Thom a répondu le 11 novembre 2019 à 17:25

Re bonjour,

Merci de la reponse,

ça marche, maintenant je vais voir comment discrimer les articles à afficher afin de ne afficher que certains de la même table..

Encore merci.

Répondre

Thom a écrit le 9 novembre 2019 à 22:13

Bonjour,

Je suis débutant en symfony 4, cependant je rencontre un problème celui qui consiste à afficher des données issues de deux tables différentes sur la même vue.

Commen s'y prendre.

Merci pour votre réponse.

Répondre

Nouvelle-Techno.fr a répondu le 10 novembre 2019 à 08:59

Bonjour,

Il faut, dans ce cas, extraire les données des deux tables dans deux variables différentes et les transmettre à la vue.

Répondre

Ecrire un commentaire