Cours - Symfony - Chapitre 01

SOMMAIRE




Introduction


Dans cette série de chapitres, nous allons créer une application avec le FrameWork Symfony. Nous partirons d’une commande qui installera le strict minimum puis nous installerons au fur et à mesure les modules complémentaires suivant nos besoins.


Mise en place


Après avoir allumé votre machine, déroulez les options de votre serveur et cliquez sur « Vscode ».



Copiez votre mot de passe utilisateur et entrez dans l’environnement de développement .



Placez-vous dans le répertoire de publication du serveur Apache (/var/www/html) en utilisant le 2ème menu de gauche (Explorer).




Puis lancez le terminal :




Nous voyons que le compte par défaut est le root. Ce qui n’est pas une bonne chose pour développer. Récupérez votre login sur votre profil (login 4400 pour moi) et tapez la commande suivante :


su login4400


Vérifiez que vous êtes bien situé dans le répertoire de publication avec la commande :


pwd


Le résultat suivant doit apparaitre : /var/www/html


Création du projet 


Nous allons taper la commande qui va nous créer un projet Symfony. Elle contiendra le moins de packages possible. En effet, un site statique n’a pas besoin de grand-chose pour fonctionner.


Avec cette commande, nous installerons la dernière version de la branche 5 de Symfony (5.4). (à l’heure où j’écris ce cours, nous sommes dans la version 6.2)


composer create-project symfony/skeleton share 5.4.*


Vous pouvez vérifier la création du site en vous rendant sur votre profil et en cliquant sur « Aller sur le site Web ». À la fin de l’URL, ajoutez /share et appuyez sur la touche «entrer ».


Exemple :


 https://s3-4400.nuage-peda.fr/share/


Vous voyez tous les répertoires et les fichiers de Symfony.


Voici un tour rapide des répertoires créé par le programme d’installation :




  • Le répertoire « bin » contient le programme « console » qui va nous aider à réaliser automatiquement des tâches qui sont habituellement pénibles comme la création de contrôleurs ou d’entités.

  • Le fichier « composer.json » contient la liste des packages installés dans notre projet.

  • Le répertoire « config » qui comme son nom l’indique, permet de configurer des éléments du site comme les routes ou la sécurité.

  • Le répertoire « public » contient « index.php », le seul fichier PHP accessible depuis un navigateur et qui est le point d’entrée de notre site.

  • Le répertoire « src » est celui qui contiendra toutes les sources du site, celles que vous complèterez et écrirez.

  • Le répertoire « var »contient le cache.

  • Le répertoire « vendor » contient les packages de Symfony ou d’autres.


Le site créé est accessible dans le répertoire public par l’intermédiaire du fichier index.php.


Exemple :

https://s3-4400.nuage-peda.fr/share/public/ 
ou
https://s3-4400.nuage-peda.fr/share/public/index.php


Création de la page d’accueil du site 


Symfony utilise l’architecture MVC (Modèle Vue Contrôleur).


Nous entrerons dans le détail dans d’autres chapitres, cependant, voici une explication rapide :


  • Le « modèle » correspond aux entités de l’application qui nous permettrons, entre autres de créer, manipuler, conserver des données.

  • La « vue » permet d’afficher les pages qui seront retournées au navigateur de l’utilisateur. Elle repose sur le langage TWIG, qui permet de créer du HTML avec du contenu qui sera donné par le contrôleur.

  • Le « contrôleur » est le chef d’orchestre d’une page. Il est capable de parler au modèle afin de lui fournir ou de récupérer des données. Ensuite, il est capable d’appeler une vue tout en lui donnant les données nécessaires à la création d’une page.


Pour accéder à un contrôleur, une route est nécessaire. C’est l’URL qu’il faut saisir dans le navigateur pour se rendre sur une page.


Dans Symfony, nous pouvons regrouper des contrôleurs dans un seul fichier pour éviter d’en avoir un trop grand nombre. Généralement, nous créons un nouveau fichier par thème pour nous déplacer facilement dans le code.


Généralement, je regroupe dans un seul fichier, les fonctionnalités basiques et courantes d’un site ;

  • page d’accueil,

  • formulaire de contact,

  • mentions légales,

  • à propos


Installation des packages 


Dans le terminal, placez-vous dans le répertoire du projet :


cd share


Pour créer un contrôleur, nous devons installer des outils spécifiques en taper les commandes suivantes :


composer require symfony/maker-bundle --dev


Remarque : l’option --dev précise que cet outil sera disponible uniquement en mode développeur.


composer require annotation


Enfin, nous devons installer TWIG avec :


composer require symfony/twig-bundle


Création du contrôleur 


Nous allons créer le fichier qui contiendra nos contrôleurs de base.

Symfony nous propose un outil puissant qui nous permet de créer automatiquement certains éléments de notre site. Il s’agit de la console située dans le répertoire « bin ».


Tapez la commande suivante :


php bin/console make:controller


Puis saisissez :


Base


Dans le répertoire « src/Controller », vous trouvez maintenant le nouveau fichier « BaseController.php ».



<?php

namespace App\Controller;

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

class BaseController extends AbstractController
{
    #[Route('/base', name: 'base')]  // /base est l’URL de la page, name est le nom de la route
    public function index(): Response
    {
        return $this->render('base/index.html.twig', [ // render est la fonction qui va chercher le fichier TWIG pour l’afficher
            'controller_name' => 'BaseController', // Le contrôleur donne à la vue une variable dont le contenu est BaseController, cela nous ne servira pas, nous l’enlèverons un peu plus loin
        ]);
    }
}
      


Dans le répertoire «templates », le répertoire « base » a été créé avec le fichier TWIG « index .html.twig ». Le contenu par défaut ne nous intéresse pas du tout, nous le remplacerons avec notre propre contenu.



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


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


{% block body %}

<style>

.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }

.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }

</style>


<div class="example-wrapper">

<h1>Hello {{ controller_name }}! ✅</h1>


This friendly message is coming from:

<ul>

<li>Your controller at <code><a href="{{ '/var/www/html/share/src/Controller/BaseController.php'|file_link(0) }}">src/Controller/BaseController.php</a></code></li>

<li>Your template at <code><a href="{{ '/var/www/html/share/templates/base/index.html.twig'|file_link(0) }}">templates/base/index.html.twig</a></code></li>

</ul>

</div>

{% endblock %}   


Une nouvelle page a été créée sur le site. Vous pouvez y accéder en tapant l’URL suivante :


index.php/base


Exemple :


https://s3-4400.nuage-peda.fr/share/public/index.php/base


Vous remarquez que l’URL n’a pas une forme habituelle.


Nous allons installer la gestion des URL avec la commande suivante dans le répertoire du projet :


composer require symfony/apache-pack


Il nous pose une question à laquelle il faut répondre « y ».


Maintenant, l’URL suivante fonctionne :


/base


Nous allons maintenant mettre en forme notre page d’accueil.


Dans le répertoire « templates », nous avons le fichier « base.html.twig ». il s’agit du fichier qui contiendra la structure du site qui sera utilisé dans toutes nos pages. C’est ici que nous déclarerons les blocs qui seront modifiés par la suite.


Contenu actuel de « templates/base.html.twig » :


 
 <!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title> // déclaration du bloc pour gérer le titre et le compléter sur chaque page
        {# Run `composer require symfony/webpack-encore-bundle`
           and uncomment the following Encore helpers to start using Symfony UX #}
        {% block stylesheets %}
            {#{{ encore_entry_link_tags('app') }}#} // déclaration du bloc permettant d’appeler les fichiers css
        {% endblock %}

        {% block javascripts %}
            {#{{ encore_entry_script_tags('app') }}#} // déclaration du bloc permettant d’appeler les fichiers js
        {% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %} // déclaration du bloc qui nous permettra de modifier le corps de nos pages
    </body>
</html>  


Mise en place de Bootstrap 5


Nous allons récupérer la structure de base de Bootstrap pour remplacer le contenu notre fichier « base.html.twig ».


Code du « get started » de bootstrap 5 :

source : https://getbootstrap.com/docs/5.1/getting-started/introduction/


<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- Optional JavaScript; choose one of the two! -->

    <!-- Option 1: Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>

    <!-- Option 2: Separate Popper and Bootstrap JS -->
    <!--
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js" integrity="sha384-W8fXfP3gkOKtndU4JGtKDvXbO53Wy8SZCQHczT5FMiiqmQfUpWbYdTil/SxwZgAN" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
    -->
  </body>
</html>

 


Voici le contenu de notre fichier « base.html.twig » après modifications :


<!doctype html>
<html lang="fr">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
   {% block stylesheets %}
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
   {% endblock %}
    <title>{% block title %}Share - {% endblock %}</title>
  </head>
  <body>
   
    {% block body %}{% endblock %} 
   
    {% block javascripts %}
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
    {% endblock %}
  </body>
</html>


Commentaires :

Nous entourons les lignes qui sont susceptibles de changer sur chaque page de notre site avec la déclaration de blocs.


Nous changerons ou complèterons les éléments suivants :

  • les feuilles de style,

  • le titre,

  • le contenu,

  • les scripts JavaScript


Nous allons maintenant mettre en forme notre page d’accueil. Commençons par notre contrôleur :


« src/Controller/BaseController.php » :



class BaseController extends AbstractController
{
    #[Route('/base', name: 'base')]
    public function index(): Response
    {
        return $this->render('base/index.html.twig', [
            'controller_name' => 'BaseController', // suppression de la variable passée à la vue
        ]);

    }
}


Commentaire :

Nous supprimons la variable passée à la vue (surlignée), car le nom du contrôleur de l’intéresse pas.


Modifions maintenant la vue « templates/base/index.html.twig ».


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

{% block title %}{{parent()}}Accueil{% endblock %}

{% block body %}
    <h1 class="text-center text-primary"> Share : partagez vos fichiers </h1>
{% endblock %}


Commentaires :

{% extends 'base.html.twig' %} // Appel de la configuration de base

{% block title %}{{parent()}}Accueil{% endblock %} // Nous complétons le titre de base avec une indication supplémentaire sur la page courante ici nous ajoutons « accueil »

parent() signifie que nous appelons le contenu du block title définit dans base.html.twig

{{ }} sont utilisés pour afficher des variables ou appeler des fonctions.

{% block body %} // Nous définissons complètement le contenu de notre page.

<h1 class="text-center text-primary"> Share : partagez vos fichiers </h1> // text-center est la propriété de Bootstrap permettant de centrer le titre, text-primary donne la 1re couleur définie par Bootstrap

Si vous souhaitez une personnalisation de Bootstrap, je vous invite à vous rendre sur le site « https://bootswatch.com/ ». Il propose des thèmes assez jolis.

Vous pouvez cliquer sur la flèche « download » d’un thème, par exemple « Lumen » et sélectionnez « bootstrap.min.css » avec un clic droit. Puis faites « copier le lien ».

Allez dans votre template « templates/base.html.twig » puis remplacer le lien css bootstrap par celui que vous venez de récupérer.

https://bootswatch.com/5/lux/bootstrap.min.css

Remplacer :

 <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">

Par :

<!-- Bootstrap CSS -->
    <link href="https://bootswatch.com/5/lux/bootstrap.min.css" rel="stylesheet">


Mise en place du menu du site 


Sur le site de bootswatch, récupérez un des menus disponibles dans votre thème et mettez-le dans votre template « base.html.twig » au-dessus de votre bloc « body » afin qu’il s’affiche sur toutes les pages.

<!doctype html>
<html lang="fr">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
   {% block stylesheets %}
    <!-- Bootstrap CSS -->
    <link href="https://bootswatch.com/5/lumen/bootstrap.min.css" rel="stylesheet">
   {% endblock %}
    <title>{% block title %}Share - {% endblock %}</title>
  </head>
  <body>
   

<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarColor01">
      <ul class="navbar-nav me-auto">
        <li class="nav-item">
          <a class="nav-link active" href="#">Home
            <span class="visually-hidden">(current)</span>
          </a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Features</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Pricing</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">About</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Dropdown</a>
          <div class="dropdown-menu">
      <a class="dropdown-item" href="#">Action</a>
            <a class="dropdown-item" href="#">Another action</a>
            <a class="dropdown-item" href="#">Something else here</a>
            <div class="dropdown-divider"></div>
            <a class="dropdown-item" href="#">Separated link</a>
          </div>
        </li>
      </ul>
      <form class="d-flex">
        <input class="form-control me-sm-2" type="text" placeholder="Search">
        <button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
      </form>
    </div>
  </div>
</nav>


    {% block body %}{% endblock %} 
   
    {% block javascripts %}
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
    {% endblock %}
  </body>
</html>

Personnalisation de la barre de menu (navbar) 

Pour l’instant, nous disposons d’une seule page, par conséquent, nous allons modifier le nom du site et modifier le lien pour nous rendre sur la page d’accueil.

À ce propos, pour l’instant, notre page est accessible avec l’URL /base. Par défaut, notre site nous affiche toujours la page de Symfony.

Nous allons donc modifier cela.

Dans le fichier « routes.yaml », retirez le caractère # (uniquement et surtout pas les espaces) de chaque ligne et modifiez la configuration comme ceci :

index:
    path: /
    controller: App\Controller\BaseController::index

L’URL par défaut pointe maintenant sur votre page d’accueil.

Exemple :

http://s3-4400.nuage-peda.fr/share/public/

Changeons maintenant l’URL de la page d’accueil, au lieu de /base, nous préférons /index.

Dans « BaseController.php », modifiez l’URL de la route et son nom.

class BaseController extends AbstractController
{
    #[Route('/index', name: 'index')]
    public function index(): Response
    {
        return $this->render('base/index.html.twig', [
          
        ]);
    }
}

Appel de la page d’accueil dans le menu 

Dans «base.html.twig », modifiez :

<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
  <div class="container-fluid">
    <a class="navbar-brand" href="{{path('index')}}">Share</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarColor01">
      <ul class="navbar-nav me-auto">
        <li class="nav-item">
          <a class="nav-link active" href="{{path('index')}}">Accueil
            <span class="visually-hidden">(current)</span>
          </a>

Commentaires :

La fonction « path » de TWIG permet de générer le lien vers la route passée en paramètre. N’oubliez pas d’entourer l’appel de la fonction avec deux accolades de chaque côté.

En cliquant sur « Share » ou « Accueil », l’utilisateur pourra se rendre sur la page d’accueil.

Mise en forme de la page d’accueil 


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

{% block title %}{{parent()}}Accueil{% endblock %}

{% block body %}
    <h1 class="text-center text-primary mt-4 pt-4 display-1 fw-bold"> SHARE</h1>
     <h2 class="text-center text-secondary mb-4 pb-4 display-2"> partagez vos fichiers </h2>
 <p class="text-center m-4 p-4">   
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="currentColor" class="bi bi-cloud-arrow-up text-primary" viewBox="0 0 16 16">
  <path fill-rule="evenodd" d="M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708l2-2z"/>
  <path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383zm.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/>
</svg>
 
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="currentColor" class="bi bi-folder text-secondary" viewBox="0 0 16 16">
  <path d="M.54 3.87.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a1.99 1.99 0 0 1 .342-1.31zM2.19 4a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91h10.348a1 1 0 0 0 .995-.91l.637-7A1 1 0 0 0 13.81 4H2.19zm4.69-1.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139C1.72 3.042 1.95 3 2.19 3h5.396l-.707-.707z"></path>
</svg>

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="currentColor" class="bi bi-cloud-arrow-down-fill text-warning" viewBox="0 0 16 16">
  <path d="M8 2a5.53 5.53 0 0 0-3.594 1.342c-.766.66-1.321 1.52-1.464 2.383C1.266 6.095 0 7.555 0 9.318 0 11.366 1.708 13 3.781 13h8.906C14.502 13 16 11.57 16 9.773c0-1.636-1.242-2.969-2.834-3.194C12.923 3.999 10.69 2 8 2zm2.354 6.854-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 1 1 .708-.708L7.5 9.293V5.5a.5.5 0 0 1 1 0v3.793l1.146-1.147a.5.5 0 0 1 .708.708z"/>
</svg>

</p>

{% endblock %}

Commentaires :

Les icônes viennent du site de Bootstrap à cette adresse : https://icons.getbootstrap.com/

Elles sont au format « SVG ».

Quelques classes BOOTSTRAP 5 utilisées :

text-primary : couleur du texte, première couleur définie dans le thème.

text-secondary : couleur du texte, deuxième couleur définie dans le thème.

display1 et display2 : mise en forme du texte des titres de la balise <h1>.

mt-4 : margin top de 4.

mb-4 : margin bottom de 4.

fw-bold : mettre en gras le texte.

m-4 : margin de 4 de tous les côtés.

p-4 : padding de 4 de tous les côtés.

Voici l’écran final de ce chapitre :




Voir le Chapitre 2