TP n°1 - Prise en main de PHP et de la boîte à outils Symfony
Application PHP en ligne de commande « gestionnaire de tâches Todo »

Table des matières

1. Introduction

Cette séance permet de familiariser les étudiants avec l’environnement de programmation PHP et de mise au point basé sur Symfony, pour l’écriture de programmes interactifs en PHP lancés en ligne de commande.

Dans cette séance, vous commencerez l’étude d’une application de gestion de tâches fournie, appelée ToDo, programmée en PHP avec le framework Symfony. Elle servira de fil rouge tout au long des TPs, pour étudier la mise en œuvre des concepts abordés dans le cours.

Un squelette d’application ToDo sera fourni pour démarrer cette première mise en œuvre. Il contient déjà de nombreuses fonctionnalités, même si nous étudierons uniquement certaines d’entre-elles dès cette première séance de TP.

Pour l’instant on va s’intéresser aux mécanismes qui permettent à l’application d’accéder en lecture à une base de données relationnelle, et d’afficher le résultat de requêtes sur la sortie standard.

Cette application sera utilisable en ligne de commande, et illustre principalement le fonctionnement de la couche d’accès aux données d’une application Symfony codée en PHP objet, via le composant Doctrine.

Les étudiants vont enchaîner une vingtaine d’opérations permettant de se familiariser avec les outils du cadriciel Symfony qui vont servir pendant toute la durée des séances.

Même si l’essentiel du travail peut être réalisé en copier/coller (pour simplifier dans cette première séance), il sera utile de rester attentif au rôle des différentes manipulations, pour être capable de les reproduire ultérieurement.

N’hésitez pas à prendre des notes dans un fichier que vous conservez d’une séance à l’autre.

La séance de travail suivante permettra d’approfondir les fonctionnalités de Doctrine, et mettre en œuvre l’accès en modification dans la base de données.

L’étude du code PHP va concerner pour l’instant seulement les fonctionnalités du cadriciel Symfony pour la ligne de commande. Le fonctionnement des composants liés au Web sera abordés dans des séances ultérieures.

1.1. Prérequis

On considère que vous avez acquis les notions de base sur la syntaxe du langage PHP, dans la séquence de Travail en Autonomie qui précède cette séance.

Du point de vue théorique, cette séance revisite principalement les acquis des cours d’informatique de l’année passée, sur le modèle objet et les bases de données relationnelles.

Vous devez disposer des outils nécessaires sur votre machine BYOD, ou travailler sur une machine DISI distante.

Vous avez dû préalablement installer et configurer ces outils, grâce au support de la séquence de travail hors-présentiel qui précède cette séance (cf. wiki « Installation de l’environnement BYOD » dans l’espace Moodle du cours).

Dans cette séance, on utilisera les outils suivants :

  • la ligne de commande dans un terminal, avec le shell bash
  • l’outil Symfony en ligne de commande
  • l’environnement d’exécution PHP 8
  • Composer
  • l’IDE Eclipse (ou un équivalent) pour PHP
  • le navigateur Web

1.2. Format de ce document

Le présent support de séance de TP est consultable via une mise en forme avec l’habillage org-html-themes, qui permet de masquer/révéler les différentes sections du support1.

Des raccourcis clavier (indiqués dans un cartouche en bas à droite) permettent de naviguer directement dans les différentes tâches (TODO) à réaliser, pour aider à se concentrer sur l’avancement pas-à-pas.

2. Étape 1 : Positionnement dans l’environnement de travail personnel

On suppose que cette séance de travail s’effectue dans l’environnement personnel (BYOD), mais elle peut également être effectuée dans l’environnement des machines de salles de TP d’informatique.

2.1. Contexte : Système d’exploitation de référence

Dans le présent support de TP, les copies d’écrans et autres spécificités reflètent autant que possible l’état des versions installées sur les machines DISI des salles de TP en environnement GNU/Linux Ubuntu.

Il est probable que sur les machines individuelles, le support de PHP et de Symfony sera parfois différent.

Même si les technologies utilisées pour les séquences d’apprentissage actif (programmation PHP avec le framework Symfony) sont théoriquement portables et utilisables sur différents systèmes d’exploitation, des différences existent qui rendent parfois difficile le support au vu des différentes variantes possibles, et pour un module enseigné en promo entière.

L’équipe pédagogique ne sera pas en mesure de garantir le support relatif aux outils pour tous les systèmes d’exploitation, mais nous ferons de notre mieux pour vous accompagner.

Pour cette séance, on supposera que vous travaillez sur la machine que vous allez utiliser pour le reste des séances de TP et de travail hors-présentiel (y compris le projet).

Vous aurez besoin d’un terminal en ligne de commande, mais aussi de l’environnement graphique pour utiliser l’IDE.

2.2. TODO Étape 1-a : Création du répertoire de travail

Nous vous suggérons de travailler, pour chaque séance, dans un répertoire spécifique.

  • $HOME/CSC4101/
    • tp-01/
    • tp-02/

Nous donnons les commandes à exécuter pour un shell bash, typiquement en environnement GNU/Linux, ou via git-bash installé sur Windows.

Adaptez ces commandes à votre environnement personnel.

  1. Configurez un répertoire de travail $HOME/CSC4101/ dans votre compte.

    mkdir $HOME/CSC4101/
    cd $HOME/CSC4101/
    
  2. Pour l’instant, on crée un nouveau répertoire spécifique à cette séance :

    mkdir -p tp-01/
    cd tp-01/
    

3. Étape 2 : Récupération du code de l’application « fil-rouge » ToDo

Cette étape consiste à récupérer une première version minimaliste du code de l’application Web « ToDo » qui est notre fil-rouge.

Cette application Symfony très simple permet pour l’instant d’effectuer la consultation d’une liste de tâches (todo list). Elle est codée en PHP avec les bibliothèques de Symfony.

Elle offre pour l’instant une interface fonctionnant principalement en ligne de commande.

3.1. TODO Étape 2-a : Récupérer le code du projet Symfony

Récupérer une première version de Todo, prête à fonctionner en ligne de commande

Exécutez les commandes suivantes :

cd $HOME/CSC4101/tp-01/
symfony composer create-project oberger/tspcsc4101-todo-skeleton todo-app "v2.*" -n

Comme vous le voyez, Composer télécharge une version spécifique (2.x) de l’application ToDo à partir du projet « oberger/tspcsc4101-todo-skeleton », qui a été préparé pour les besoins du cours.

Le code de ce projet Symfony est extrait dans le répertoire ~/CSC4101/tp-01/todo-app/.

Explications de la signification des différents éléments de cette invocation :

composer
invocation de Composer, l’outil de gestion de paquetages PHP
create-project
commande create-project de composer qui crée un projet à partir d’un squelette existant (cf. documentation composer)
oberger/tspcsc4101-todo-skeleton
référence du squelette d’application qui a été préparé pour le cours
todo-app
répertoire du projet à créer
v2.*
version particuilère à télécharger : 2.x (la dernière version de la branche 2 ayant été publiée via packagist.org)
-n
option --no-interaction de composer create-project permettant de répondre avec les valeurs par défaut en cas de confirmations demandées pour l’exécution de recettes flex (configuration et génération de fichiers utiles)

3.2. TODO Étape 2-b : Observation du contenu du projet créé

Vérifiez le contenu du répertoire todo du projet Symfony qui vient d’être créé.

ls todo-app/

Pour l’instant, repérez les éléments principaux qui vont nous intéresser :

bin  composer.json  composer.lock  config  public  src  symfony.lock  todo.sqlite  var  vendor
composer.json

descriptif du projet Composer de l’application. Il référence notamment les bibliothèques PHP utilisées dans ce projet basé sur Symfony;

Vous pouvez consulter son contenu (format JSON) dans un éditeur de texte.

Au fur et à mesure de la vie d’un projet Symfony on pourra utiliser Composer à nouveau, pour y ajouter des dépendances, les bibliothèques de développement dont on aura besoin au cours de l’ajout des fonctionnalités.

bin/console
script exécutable PHP présent dans le sous-répertoire bin/, utilisé en ligne de commande pour le développement Symfony, chaque fois qu’on va invoquer symfony console en ligne de commande;
src/
cœur du squelette d’application Symfony. Il contient le code source PHP de l’application, sur lequel vous travaillerez principalement par la suite;
templates/
sources des gabarits Twig de l’application, sur lesquels vous serez amenés à travailler également, quand vous concevrez les pages Web;
vendor/

contient le code de toutes les bibliothèques PHP du framework Symfony qui seront utilisées. Elles ont été téléchargées par Composer, et y seront mises à jour en cas d’évolutions (correction de bugs, etc.).

Interdiction de modifier manuellement le contenu de ce répertoire, sous peine de malédiction. On ne touche qu’au code qui est dans src/.

3.3. TODO Étape 2-c : Prise en main de l’outil console en ligne de commande de Symfony

Cette séquence a pour but d’examiner les fonctionnalités utilisables en ligne de commande par les développeurs, qui sont fournies par le composant console de Symfony

Le script bin/console fourni dans le projet permet d’accéder en ligne de commande (dans un terminal) à différentes fonctionnalités du cadriciel Symfony, notamment des utilitaires intéressants pour les phases de développement et de tests.

On lancera les commandes via l’invocation symfony console de l’outil Symfony en ligne de commande préalablement installé.

Cette façon de l’invoquer, mentionnée dans nos supports, devrait rendre plus portable les instructions pour les différents systèmes d’exploitation.

Au cas où la commande symfony console ne fonctionnerait pas, vous pouvez aussi lui substituer l’invocation directe du script PHP bin/console (ou un équivalent, comme php bin/console).

Essayez les commandes suivantes dans un terminal, depuis l’intérieur du répertoire du projet Symfony :

  1. Vérifiez la version de Symfony utilisée dans le projet

    cd $HOME/CSC4101/tp-01/todo-app/
    symfony console -V
    
    Symfony 6.4.23 (env: dev, debug: true) [...]
    

    Vous êtes bien en environnement de développement dev (pas encore prêts pour la production !)

    Si vous voyez l’affichage « CLI version 5.12.0 (c) 2021-2025 Fabien Potencier (2025-06-16T09:40:30Z - stable) », c’est que vous n’êtes pas dans le bon répertoire; votre shell n’est pas positionné à l’intérieur du projet.

  2. Affichez la liste des sous-commandes disponibles (avec la sous-commande list, ou directement sans argument passé à symfony console) :

    symfony console list
    
  3. Consultez l’aide en ligne avec la sous-commande help. Par exemple :

    symfony console help about
    
  4. Et consultez donc également la sortie fournie par cette sous-commande about :

    symfony console about
    

    Cette commande donne différentes informations sur l’environnement de développement et de mise au point.

Bravo, vous maîtrisez les commandes de base, et on peut passer à la découverte de l’application.

4. Étape 3 : Première exécution de l’application, en ligne de commande

Cette étape consiste à exécuter l’application en ligne de commande dans l’environnement de développement, sur une base de données de tests locale

Maintenant que l’outil Console de Symfony fonctionne en ligne de commande, il est temps de tester le code de l’application Todo prévu pour la ligne de commande.

On va tester le lancement de la première commande de requêtage de la liste des tâches contenues dans la base de données : app:list-todos.

4.1. TODO Étape 3-a : Génération de la base de données de développement dans SQLite

Cette étape a pour but de créer une base de données de tests avec les outils intégrés de Doctrine.

On va re-créer la base de données de l’application, qui nous sert à effectuer des tests en local pendant le développement et la mise au point du code.

Durant le développement de nos applications, le modèle de données évoluera progressivement. Vous serez amenés à répéter régulièrement les opérations que nous décrivons ici. Souvenez-vous-en, ou notez-les dans un fichier de notes qui vous suivra pendant les différentes séances de TP et/ou le projet.

Effectuez les opérations suivantes dans un terminal en ligne de commande :

  1. Supprimez le fichier de base de données SQLite existant :

    symfony console doctrine:database:drop --force
    
  2. Créez un fichier de base de données SQLite (vide), en exécutant la commande suivante :

    symfony console doctrine:database:create
    ls -l *.sqlite
    

    En fait, il se trouve que cette commande se contente de créer un fichier vide, ce qui correspond au comportement nécessaire pour une base de données légère comme SQLite. Mais dans le cas où on utiliserait un autre SGBD, ceci peut s’avérer nécessaire.

  3. Créez le schéma de la base SQLite (tables, index, etc.), en utilisant la sous-commande doctrine:schema:create :
    1. Commencez-donc par vérifier ce qui serait fait :

      symfony console doctrine:schema:create --dump-sql
      
      CREATE TABLE todo (
             id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
             title VARCHAR(255) DEFAULT NULL,
             completed BOOLEAN NOT NULL,
             created DATETIME DEFAULT NULL,
             updated DATETIME DEFAULT NULL
      );
      

      Le code SQL affiché devrait vous sembler assez clair, pour l’instant.

      Si ce n’est pas le cas, nous vous suggérons d’acquérir les connaissances minimales sur SQL vues en CSC3601 (vous pouvez vous appuyez sur cette ressource de remédiation)

    2. Puis créez le schéma pour de bon, avec :

      symfony console doctrine:schema:create
      

Bravo, vous êtes prêts à tester des requêtes dans cette base de données.

4.2. TODO Étape 3-b : Première requête de liste de tâches

Dans le squelette fourni, les développeurs de ToDo on codé une interface en ligne de commande.

  1. Appelez la première commande ’list-todos’ :

    symfony console app:list-todos
    
  2. Sans surprise, cette commande affiche la liste des tâches connues dans la base de données de l’application : [ERROR] no todos found!.

    Ça fonctionne nominalement… mais la base de données est vide, vu qu’on vient de la recréer dans l’étape précédente.

Heureusement pour nous, les développeurs ont aussi préparé un jeu de données de test, qu’on peut utiliser.

4.3. TODO Étape 3-c : Chargement des données de tests

Chargez les données de tests qui ont été préparées dans le squelette fourni :

  1. Utilisez la commande Symfony du module Doctrine pour charger des données de tests (fixtures) :

    symfony console doctrine:fixtures:load -n
    
       > purging database
       > loading App\DataFixtures\AppFixtures
    
    

    la base de données doit maintenant contenir ces données de tests.

  2. Vérifiez en relançant la commande app:list-todos

Cette fois, l’exécution de app:list-todos fonctionne : il y a bien des données dans la base, et on y accède en lecture !

4.4. TODO Étape 3-d : Autres fonctions de la ligne de commande de l’application ToDo

  1. Vous avez déjà découvert la première fonction de l’application, disponible en ligne de commande pour les développeurs :

    cd $HOME/CSC4101/tp-01/todo-app/
    symfony console app:list-todos
    

    Sans surprise, cette commande affiche la liste des tâches connues dans la base de données de l’application.

  2. Vérifiez les autres sous-commande app:* présentes :

    symfony console list app
    
  3. Utilisez maintenant la commande app:show-todo pour afficher les détails de la tâche n°2.

Comme vous pouvez le constater, notre application se présente, pour l’instant, de façon très rudimentaire, en ligne de commande.

Cette interface en ligne de commande permet juste de vérifier le bon fonctionnement du code gérant le modèle de données, avec le requêtage en lecture dans la base de données. Rien de très sorcier, mais c’est mieux quand ça marche.

4.5. TODO Rappel des commandes utiles pour plus tard

Certaines commandes que vous venez d’utiliser vont vous servir très souvent pendant le développement, donc autant les noter pour s’y référer par la suite :

  • symfony console doctrine:database:drop --force (suppression de la base de données)
  • symfony console doctrine:database:create (création de la base de données vide)
  • symfony console doctrine:schema:create (création du schéma dans la base de données)
  • symfony console doctrine:fixtures:load -n (chargement des donnéees de tests fixtures)

5. Étape 4 : Prise de connaissance du code de l’application ToDo

Cette étape consiste à découvrir le code de l’application, pour approfondir la présentation rapide effectuée en cours magistral.

Il est maintenant temps d’examiner le code pour comprendre comment fonctionne cette commande.

Mais pour ce faire, on doit d’abord s’assurer de configurer correctement l’IDE permettant de naviguer dans le code PHP de l’application Symfony.

5.1. Étape 4-a : Configuration initiale de l’IDE pour ce nouveau projet

Pour naviguer dans le code objet et nous faciliter la vide pendant le codage, on va utiliser un IDE (Integrated Development Environment) compatible avec PHP, composer et Symfony.

Eclipse dans une version récente (2025.06, par exemple) convient tout à fait, via sa distribution Eclipse for PHP Developers, qui inclut tous les plugins nécessaires.

Si vous avez une ancienne version d’Eclipse installée, ou uniquement le support du langage Java, assurez-vous de procéder aux étapes d’installations nécessaires pour disposer des PHP Development Tools. (les instructions d’installation ont été données dans la séquence de travail hors-présentiel précédente).

5.1.1. Utilisation d’Eclipse fortement recommandée

Nous vous indiquons ci-après les étapes correspondantes pour l’IDE Eclipse.

L’équipe enseignante recommande fortement d’utiliser Eclipse.

Si vous faites néanmoins le choix d’utiliser un autre autres IDE, vous vous exposez à des difficultés sur lesquelles il ne pourra vous être apporté l’aide nécessaire. À vos risques et périls…

5.1.2. Conseil pour l’organisation du Workspace Eclipse

Un Workspace Eclipse (espace de travail) permet de sauvegarder, entre deux séances de travail, la configuration de l’IDE, avec la liste des projets en cours, etc.

Le Workspace n’a pas vocation à contenir la copie de travail du code, mais seulement des fichiers de sauvegarde de la configuration de l’IDE, indépendants du code de l’application.

Attention à ne pas utiliser comme répertoire de stockage de ce Workspace, un répertoire interne à un projet Symfony.

On pourra par exemple conserver un Workspace unique dans $HOME/CSC4101/workspace/, qui référencera les différents projets PHP sur lesquels on travaille.

Au fur et à mesure qu’on travaillera sur nos projets dans d’autres sous-répertoires de $HOME/CSC4101/, on obtiendra la structure de répertoire suivante, avec le workspace et les différents répertoires des projets placés côte-à-côte :

  • $HOME/CSC4101/
    • workspace/
    • demo-symfony/
    • tp-01/
      • tp-01/todo-app/

Eclipse nous permet d’importer des projets existants dans l’espace de travail : cela signifie justement qu’on laisse le code dans les répertoires, et qu’on se contente juste de faire apparaître ces projets dans le workspace.

Les imports des différents projets Composer/Symfony présents dans les sous-répertoires les fera apparaître dans une seule hiérarchie dans l’espace de travail, vue ainsi dans l’interface d’Eclipse :

  • demo-symfony (présent dans demo-symfony/)
  • todo-tp-1 (présent dans tp-01/todo-app/)

Cette configuration sera sauvegardée dans ce seul Workspace stocké dans $HOME/CSC4101/workspace/, de façon séparée de l’emplacement des code source des projets.

On pourra garder différents projets ouverts simultanément dans Eclipse (pour faire du copier/coller par exemple), ou les fermer (dans le workspace) sans pour autant les supprimer du disque.

5.1.3. TODO Chargement des sources de ToDo dans Eclipse

Effectuez les opérations suivantes :

  1. Démarrez Eclipse (for PHP Developers)
  2. Dans le dialogue « Select a directory as workspace », choisissez de charger un autre Workspace que celui par défaut (Browse), et créez un nouveau répertoire dans $HOME/CSC4101/ appelé « workspace », par exemple.

    Une fois sélectionné, le chemin du champ Workspace pointe sur ce nouveau chemin /..../CSC4101/workspace.

  3. Cliquez sur Launch. Eclipse se lance. Fermez la sous-fenêtre d’accueil « Welcome »
  4. Dans le Project explorer, sélectionnez « Import… » et dépliez le contenu de l’arbre sous « PHP ».

    Si à ce stade, il n’y a pas d’entrées pour choisir PHP, c’est que la mauvaise version d’Eclipse a été lancée, ou qu’il manque l’installation des plugins de la distribution PHP Development Tools.

  5. Choisissez « Existing Composer Project », puis Next
  6. Cliquez sur Browse en face de Source path, et sélectionnez le répertoire correspondant à votre $HOME/CSC4101/tp-01/todo-app dans le sélecteur de fichiers. Validez.
  7. Le dialogue vous demande de saisir un identifiant de projet pour Eclipse (« Please enter a project name. »). Saisissez-le (par exemple « todo-tp-1 »), et cliquez sur Finish.

Le projet se charge et Eclipse indexe le contenu des sources PHP (DLTK indexing in progress…).

Maintenant que le projet a été configuré dans votre workspace Eclipse, vous pourrez l’y retrouver à chaque lancement d’Eclipse, sans avoir besoin de refaire ces étapes d’importation.

5.2. TODO Étape 4-b : Configuration du projet Symfony pour pouvoir tester l’application en contexte de développement

Il est maintenant nécessaire de vérifier la configuration du projet Symfony pour pouvoir tester le code de l’application en environnement de développement.

Symfony gère la notion d’environnements ayant différentes configurations au sein d’un même projet : développement, tests, production.

Nous sommes actuellement en phase de développement, en local sur notre machine, avec déjà pas mal d’outils pour tester notre code, fournis par le cadriciel Symfony.

Notez l’existence du fichier « .env » à la racine du projet Symfony :

ls -a
cat .env

Ce fichier .env définit les valeurs de certaines variables de configuration du projet Symfony, dans le répertoire courant. Ces valeurs définissent les spécificités de l’« environnement Symfony » dev (utilisé en phase de développement).

Ces valeurs diffèrent des valeurs cibles pour le déploiement futur de l’application une fois qu’elle sera mise en production (cf. les valeurs par défaut du fichier « .env.dist »).

5.3. TODO Étape 4-c : Vérification de la configuration du SGBD à utiliser pour les tests

Les données affichées par l’application proviennent d’une base de données relationnelle

Dans l’environnement de développement et de mise au point (dev), vous utiliserez le SGBD SQLite qui sera suffisant pour nos besoins.

SQLite stocke la base de données relationnelle dans un fichier présent dans le répertoire du projet Symfony.

Vérifiez le contenu du fichier (caché) .env présent à la racine du projet, qui définit des variables d’environnement, comme les paramètres d’accès à la base de données :

  1. Chargez le le fichier .env dans l’IDE

    Attention, c’est un fichier caché… il faut éventuellement le faire apparaître dans l’IDE.

    Pour cela, dans Eclipse :

    • cliquez sur le bouton avec trois petits points verticaux, en haut à droite de la colonne du « Project Explorer »;
    • puis sur « Filters and Customizations »;
    • dans la liste des « Pre-Set filters », dé-cochez « .* ressources », puis « OK ».

    Les fichiers cachés apparaissent dans le projet, dont le fichier .env.

  2. Ouvrez .env, et vérifiez la valeur de la variable DATABASE_URL, présente dans la section doctrine/doctrine-bundle.

    Elle doit typiquement prendre la valeur sqlite:///%kernel.project_dir%/todo.sqlite, afin d’utiliser SQLite pour les besoins du développeur qui teste en local :

    DATABASE_URL=sqlite:///%kernel.project_dir%/todo.sqlite
    

    Ainsi, la base de données SQLite utilisée pour les tests sera créée dans $HOME/CSC4101/tp-01/todo-app/todo.sqlite.

5.4. TODO Étape 4-d : Examen du contenu de la base de données

La base de données avait été peuplée pour la première exécution de l’application qu’on a faite plus haut.

Examinez son contenu via les opérations suivantes :

  1. Vérifiez que la base de données est présente

    ls -l todo.sqlite
    sqlite3 todo.sqlite ".tables"
    

    Elle doit contenir la table : todo

    Vous pouvez aussi utiliser l’outil GUI sqlitebrowser pour consulter le contenu de la base de données, s’il est installé : sqlitebrowser todo.sqlite.

  2. Consultez les détails du contenu de la table todo :

    symfony console dbal:run-sql "select * from todo"
    

    ou bien directement :

    sqlite3 todo.sqlite "select * from todo"
    
  3. Affichez le schéma de cette table :

    sqlite3 todo.sqlite ".schema todo"
    

Cette base de données semble bien correspondre au modèle de données de notre application, au vu de ce qu’on en a compris jusqu’ici.

C’est logique, puisqu’elle a été créée via l’outil Doctrine inclus dans l’environnement de développement de Symfony lors de l’appel à symfony console doctrine:schema:create.

Vérifions maintenant où est spécifié ce modèle de données, dans le code des classes PHP de notre application.

6. Étape 5 : Examen du code PHP Symfony

Cette étape va permettre d’étudier le code PHP du modèle de données de notre application Symfony, permettant de consulter des tâches.

Cette étape a pour but de rafraîchir les connaissances en objet, et bases de données.

Dans cette étape, vous allez consulter du code objet d’un projet Symfony, qui repose sur de nombreux concepts potentiellement complexes à comprendre en détail pour l’instant.
Essayez de suivre les indications données, pour vous repérer sommairement dans ce code, sans nécessairement essayer de décoder tous les détails. Nous les reverrons par la suite dans les prochaines séquences du cours.

6.1. Principes de gestion du modèle de données avec l’ORM Doctrine

On souhaite gérer des tâches (« to dos ») dans notre application.

Dans notre application Symfony, on va gérer ces éléments aussi bien :

  • en mémoire durant l’exécution du programme PHP;
  • dans la base de données relationnelle, qui stockera les données entre deux exécutions de notre programme,

On va gérer les structures de données correspondantes avec deux approches conjointes :

  • le modèle objet, pour la représentation en mémoire et les traitements à l’exécution;
  • le modèle relationnel, pour le stockage (persistence) dans la base de données.

En base de données, on aura donc la relation todo, stockée sous forme de table dans SQLite, qu’on a vue plus haut.

Du côté objets, on utilisera la bibliothèque PHP Doctrine, qui est un ORM (Object Relational Mapper). Son rôle est de permettre la gestion de collections d’objets, d’associations entre entités, et de fournir le chargement/sauvegarde des objets depuis la base de données.

Pour faire court, le principe de l’ORM est de convertir chaque instance d’une relation (chaque ligne d’une table de la base de données) en instance d’une classe PHP en mémoire, et inversement. Doctrine appelle Entités ces classes d’objets. L’ORM utilise SQL pour charger ou sauvegarder les données.

La programmeuse peut ainsi écrire des classes PHP utilisant les fonctionnalités de Doctrine, et ainsi gérer en objet des instances des entités, ou des collections d’entités.

Quand deux entités sont liées (association 1-n, par exemple), des fonctions de Doctrine permettent de gérer cette association « OneToMany » et d’accéder à la collection des entités liées facilement dans les programmes.

6.2. TODO Étape 5-a : Examen du code exécuté à l’appel de la commande app:list-todos

Le code PHP qui exécute le traitement de la commande app:list-todos se trouve dans le fichier src/Command/ListTodosCommand.php du projet.

  1. Consultez le fichier src/Command/ListTodosCommand.php dans l’IDE
  2. Consultez la déclaration de la classe avec ses attributs :

    #[AsCommand(
        name: 'app:list-todos',
        description: 'List the todos',
        )]
    class ListTodosCommand extends Command
    {
    

    Les attributs PHP 8 définissent des méta-données utiles au framework Symfony. Ici, AsCommand permet de décrire la commande, en définissant son nom, et la description qui sera affichée dans la liste des commandes (symfony console list app).

    On a donc une nouvelle commande appelable depuis la console via symfony console app:list-todos.

  1. Consultez maintenant le cœur du sujet, dans le code de la méthode execute(). Comprenez-vous le rôle de cette méthode ?

    $io = new SymfonyStyle($input, $output);
    
    // fetches all instances of class Todo from the DB
    $todos = $this->todoRepository->findAll();
    //dump($todos);
    
    if(!empty($todos)) {
        $io->title('list of todos:');
        $io->listing($todos);
    } else {
        $io->error('no todos found!');
        return Command::FAILURE;
    }
    
    return Command::SUCCESS;
    

    Quelques commentaires :

    • l’utilitaire SymfonyStyle fourni par Symfony permet de mettre en forme des affichages sur la sortie standard dans la console :
      title()
      affiche un message de titre (colorisé)
      listing()
      affiche une liste d’éléments sous forme de liste à puces
      error()
      affiche un message d’erreur (colorisé)
    • $todoRepository est une propriété de notre classe ListTodosCommand, qui est un Repository d’objets (TodoRepository) pour accéder à la base de données qui stocke les instances de tâches.

      On peut charger une collection de toutes les instances de tâches de la base de données, avec l’appel à findAll() sur ce Repository. Elle renvoie une « liste/tableau » d’instances de la classe Todo, une pour chaque ligne de la table todo de la base de données.

      Remarque : il faudrait aller voir le code de TodoRepository (présent dans src/Repository/TodoRepository.php) pour voir comment cette classe est liée à la classe Todo, qui n’apparaît pas ici par magie.

      Mais ce serait aller explorer des éléments un peu trop complexes pour le moment. On y reviendra dans les séquences du cours ultérieures.

      Pour l’instant, on peut se contenter de voir l’aide fournie par l’IDE qui montre le prototype de la méthode findAll() si on laisse le pointeur fixe sur son appel dans l’instruction $todos = $this->todoRepository->findAll(); :

      App\Repository\TodoRepository::findAll() : Todo[] 
      
      Returns:
       Todo[]
      

      Même si on ne connaît pas tous les détails du rôle d’un repository on sait désormais que cette méthode renvoie un tableau d’instances de Todo. De l’utilité d’avoir un IDE comprenant les projets Composer, le PHP objet, etc.

    Ce code suffit donc à afficher toutes les tâches présentes dans la base de données, mises en forme de façon agréable sur la sortie standard en ligne de commande.

    Regardons à présent à quoi ressemblent ces « tâches » dans le code, avec cette fameuse classe Todo.

6.3. TODO Étape 5-b : Examen du code de l’entité Todo du modèle de données

Les objets manipulés par notre application constituent le modèle de données. Ici, un ensemble de tâches codées grâce à la classe PHP Todo.

Dans un projet Symfony utilisant Doctrine, les classes des entités du modèle de données sont définies dans les fichiers source présents dans src/Entity/ (complétés par les classes de src/Repository/).

Voyons ce que les développeurs de Todo y ont codé en PHP objet :

  1. Consultez src/Entity/Todo.php dans l’IDE, pour consulter le code de la classe Todo.

    Notez la convention de structuration du projet utilisée, pour faciliter la correspondance entre les noms des classes, avec les espaces de noms (namespaces) PHP, et leur emplacement dans la structure de répertoires du code source :

    • Namespace : App\Entity
    • Classe : Todo (convention : toute classe commence par une capitale)
    • Répertoire : src/Entity
    • Fichier source : Todo.php (une seule classe par fichier source PHP)

      L’auto-loader PHP utilisé dans les projets Symfony basés sur Composer, parcourt automatiquement les répertoires de sources du projet (principalement src/ et de ses bibliothèques, en dessous de vendor/) pour charger les fichiers sources, et détecter les déclarations de namespace permettant de résoudre ultérieurement les imports via l’instruction use.

      Exemple :

      namespace App\Entity;
      
      ...
      
      class Todo {
      
          ...
      
      use App\Entity\Todo;
      
      ...
      
          $this->todoRepository = $doctrineManager->getRepository(Todo::class);
      
      ...
      
      
  2. Pouvez-vous identifier les propriétés (variables d’instances) définies dans la classe Todo ?

    Vous remarquez que chacune de ces propriétés est décorée avec un attribut ORM\Column qui permet à Doctrine de savoir comment en gérer la persistence.

    On retrouve la correspondance avec les éléments renvoyés par sqlite3 todo.sqlite ".schema todo" ou symfony console doctrine:schema:create --dump-sql :

    propriété de classe type PHP attribut Doctrine colonne en base
    Todo::id int ORM\Id, ORM\GeneratedValue INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
    Todo::title string ORM\Column(length: 255, nullable: true) VARCHAR(255) DEFAULT NULL
    Todo::completed bool ORM\Column BOOLEAN NOT NULL
    Todo::created Datetime ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true) DATETIME DEFAULT NULL
    Todo::updated Datetime ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true) DATETIME DEFAULT NULL

    Vous savez donc maintenant où et comment on peut programmer ces attributs ORM destinés à Doctrine pour la persistence en base de données, qui définissent les conversions de type, les contraintes de stockage, de valeurs non-nulles, etc. On y reviendra en détails ultérieurement.

  3. Observez la méthode __toString() qui réalise la conversion en chaîne de caractères (pour l’affichage sur la console, entre autres).

6.4. TODO Étape 5-c : Examen du code de chargement des données de tests (Fixtures)

Examinons maintenant un exemple de code de mise à jour du contenu de la base de données, celui qui s’exécute lors de l’invocation de symfony console doctrine:fixtures:load pour charger les données de tests dans la base locale.

Examinez le code dans src/DataFixtures/AppFixtures.php

Le code de la méthode AppFixtures::loadTodos() va appeler autant que nécessaire sa méthode génératrice getTodosData(), pour récupérer des couples (titre, complété), et les sauvegarder comme autant de tâches, dans la base de données.

Ce code fonctionne en deux temps :

  1. création d’une instance de tâche en mémoire, pour chaque couple [$title, $completed], en utilisant des instructions standard en PHP objets (appel au constructeur, puis aux setters):

    $todo = new Todo();
    $todo->setTitle($title);
    $todo->setCompleted($completed);
    
  2. sauvegarde des données via les appels à persist() et flush() de Doctrine, qui vont générer une requête (INSERT) en base de données pour chaque instance nouvelle présente en mémoire.

    Inutile d’en savoir beaucoup plus pour l’instant.

Voilà pour l’examen du code basique permettant la gestion des données en mémoire et leur chargement / sauvegarde dans la base de données, en utilisant Doctrine.

6.5. Étape 5-d : Examen des autres commandes de l’application (app:…) (optionnel)

Exécutez la commande :

symfony console list app

Vous voyez que des commandes sont disponibles pour modifier le contenu de la base de données.

Vous pouvez jouer avec l’ajout ou la suppression et voir si ça a l’air de fonctionner.

6.6. TODO Étape 5-e : Examen des logs d’exécution

Au fur et à mesure de l’exécution d’une application Symfony, des traces (logs) sont sauvegardées dans un fichier.

C’est le cas en particulier en environnement de développement, pour mieux identifier les problèmes à l’exécution.

Lancez la commande suivante :

cat var/log/dev.log

Vous voyez beaucoup de choses, car certains composants de Symfony affichent des infos très verbeuses.

Pour surveiller l’affichage de ces traces en temps réel, on peut ouvrir un autre terminal en parallèle et exécuter par exemple :

tail -f var/log/dev.log

Vous pouvez vérifier s’il y a des messages importants, par exemple avec :

grep -a --color=auto "ERROR\|CRITICAL" var/log/dev.log

Il se peut qu’il n’y ait rien d’affiché, ce qui serait bon signe. Essayez alors de taper :

symfony console app:null
grep -a --color=auto "ERROR\|CRITICAL" var/log/dev.log

Vous devriez maintenant voir votre erreur, tracée dans ce journal.

6.7. TODO Étape 5-f : Examen des requêtes SQL

Essayez de lancer à nouveau l’exécution des différentes commandes vues dans cette séquence, aussi bien en lecture qu’en modifications (cf. étape précédente).

Immédiatement après l’exécution de chaque commande, vérifiez le contenu du fichier de traces (logs) var/log/dev.log.

Vous pouvez par exemple exécuter :

symfony console app:list-todos
grep "doctrine.DEBUG" var/log/dev.log

La commande grep va filtrer le contenu du fichier de traces pour n’afficher que ce qui est relatif à Doctrine.

Vous devriez voir passer toutes les requêtes SQL effectuées par les commandes. Pratique pour la mise au point en cas de problèmes, si le code ne fait pas ce qu’on veut.

Nous reviendrons plus tard dans le cours sur la façon dont les requêtes SQL sont générées par Symfony avec Doctrine.

7. Étape 6 : Exécution d’une application Symfony en mode Web

Cette étape permet de se familiariser avec la façon dont on peut tester le fonctionnement d’une application Symfony, en contexte Web, grâce à un serveur HTTP local.

Quittons maintenant l’environnement en ligne de commande, pour tester rapidement le fonctionnement d’une application Symfony sur le Web.

L’application ToDo fournie dispose en effet également d’une interface Web pour HTTP. Rien que de très normal, en fait, pour une application d’un cadriciel Web comme Symfony.

Découvrons comment tester, en local, une application Web développée avec Symfony.

7.1. TODO Étape 6-a : Lancement du serveur HTTP intégré à Symfony sur l’application ToDo

Démarrer le serveur Web local intégré à l’interpréteur PHP pour pouvoir tester les interactions HTTP en local.

Depuis la ligne de commande, vous allez lancer le serveur HTTP intégré à l’outil Symfony en ligne de commande.

Le serveur rend accessible via HTTP des ressources disponibles dans le répertoire du projet Symfony d’où il a été lancé. Quand ces ressources correspondent à des programmes PHP, il les exécute pour faire interpréter les requêtes HTTP par ces programmes.

Les instructions suivantes sont données pour un environnement en ligne de commande native (GNU/Linux). Adaptez à votre environnement en cas d’autre système, notamment pour les numéros de port à utiliser, par exemple.

Lancez la commande suivante :

cd $HOME/CSC4101/tp-01/todo-app/
symfony server:start

Le serveur se lance et affiche quelque chose du genre :


 [OK] Web server listening
      The Web server is using PHP CLI 8.3.6
      http://127.0.0.1:8000
[Web Server ] Jul 10 13:15:56 |DEBUG  | PHP    Reloading PHP versions
[Web Server ] Jul 10 13:15:56 |DEBUG  | PHP    Using PHP version 8.3.6 (from default version in $PATH)
[Web Server ] Jul 10 13:15:56 |INFO   | PHP    listening path="/usr/bin/php8.2" php="8.2.7" port=38555
[PHP        ] [Mon Jul 10 13:15:56 2023] PHP 8.3.6 Development Server (http://127.0.0.1:38555) started

Vous pouvez en principe ignorer les warnings, pourvu que le message « [OK] » soit bien affiché.

7.2. TODO Étape 6-b : Accès à l’interface Web avec le navigateur

  1. Chargez l’URL http://localhost:8000/ (ou http://127.0.0.1:8000) dans un navigateur Web (lancé sur la même machine)

    Vous constatez le comportement suivant :

    • Une page Web affiche « Welcome to Symfony 6.4.x »
    • dans le terminal, le serveur Web affiche une trace du style :

      [PHP        ] [Fri Aug 26 15:55:05 2024] ::1:33926 [404]: GET /
      

    Le serveur fonctionne, et affiche les traces (logs) de fonctionnement au fur et à mesure des connexions du navigateur.

  2. Remarquez la structure des traces : cette ligne affiche différentes informations :

    [PHP        ] [Fri Aug 26 15:55:05 2024] ::1:33926 [404]: GET /
    
    Fri Aug 26 15:55:05 2024
    date de réception de la requête HTTP lors du chargement de l’URL à partir du navigateur
    ::1:33926
    source de la requête : ici, client HTTP (le navigateur Web) connecté depuis localhost (::1 en IPv6), émettant sa requête depuis le port source 33926 (ou un équivalent IPv4 du genre : 127.0.0.1:44530)
    404
    code de réponse HTTP (404 Not Found), renvoyé par le serveur
    GET
    méthode HTTP demandée dans la requête du client
    /
    chemin d’accès à la ressource demandée : le client a accédé à http://localhost:8000/, donc à la ressource racine du serveur Web : « / » .

    Pour l’instant, on n’a pas étudié le protocole HTTP, mais vous devriez probablement avoir ententu parler de cette infame erreur 404.

    On constate donc que le serveur Web répond avec un code d’erreur HTTP (404), ce qui signifie qu’il n’a pas trouvé ce qui est demandé…

  3. Comment expliquer que ce code de réponse 404 est renvoyé, alors que le navigateur affiche bien une page ?

    Le serveur Web a bien effectué un traitement, en réponse à la requête du navigateur de chargement de la ressource /.

    Il a en fait démarré l’exécution de notre application PHP Symfony, en contexte Web, cette fois-ci.

    Le serveur nous dit : « 404 : il n’y a rien à la racine du site ! »

    En effet, du fait de ce qui est présent dans le code de l’application, Symfony ne trouve pas de resource à afficher, mais nous renvoie néanmoins une page HTML, pour habiller le message d’erreur : un code de réponse 404 (Not found).

    Par exception, comme nous sommes en environnement de développement, Symfony nous accueille avec un tel message informatif en cas d’erreurs. Notez qu’on voit ce code « 404 » apparaître en rouge en bas à gauche de la page Web.

  4. Essayez sur http://localhost:8000/todo/list : est-ce mieux, maintenant ?

    OK, dans cette version très basique de l’application Todo, les développeurs ont mieux géré la présentation en ligne de commande que le look des pages Web… normal, ça viendra en temps utile dans la suite du cours.

Notez que l’application Web Symfony s’exécute en « boucle », réagissant en réponse aux requêtes transmises à travers le serveur HTTP.

Si vous mettez à jour le code PHP, ces mises à jour seront prises en compte à l’exécution des prochaines requêtes sans avoir à relancer le serveur HTTP.

Vous pouvez ainsi garder le terminal ouvert avec le serveur lancé dedans, pour pouvoir consulter les logs sur la sortie dans le terminal au fur et à mesure de la mise au point.

8. Étape 7 : Découverte du tableau de bord d’administration EasyAdmin (optionnel)

Cette étape introduit le module EasyAdmin qui permet d’ajouter, avec un minimum de code, un tableau de bord d’administration dans une application Symfony.

En plus de la page Web un peu rustique qu’on vient de consulter, qui a été codée par les développeurs, notre application Todo vous est fournie avec un tableau de bord d’administration que les développeurs ont réalisé très simplement grâce à l’outil EasyAdmin pour Symfony, à titre de démonstration.

Le tableau de bord d’administration offre une interface Web prête à l’emploi permettant de consulter et modifier le contenu de la base de données.

8.1. Étape 7-a : Prise en main de Todo avec son EasyAdmin ?

Tester l’ajout, la modification et la suppression de données dans l’application ToDo.

Connectez-vous sur la partie /admin de l’application avec votre navigateur. Par exemple sur http://localhost:8000/admin.

Testez que vous pouvez visualiser le contenu de la base de données de l’application ToDo, et modifier le contenu de la base.

A priori, cette interface Web est beaucoup plus conviviale que l’interface en ligne de commande offerte par les lancements de symfony console app:update-todo et consors.

Elle a aussi l’immense avantage d’être utilisable via une interface Web. Pas besoin de devoir être connecté dans un terminal sur le serveur Web pour pouvoir modifier le contenu de la base de données.

Est-ce qu’un tel système est suffisant pour réaliser des applications Web, sans presque écrire de code ?

Il y a des chances que les fonctionnalités ne suffisent pas (en gros on a une gestion minimale de base de donnée avec une surcouche Web).

En plus, donner les droits à tout le monde de tout modifier, ce n’est sûrement pas acceptable en production !

Même si on peut déployer en production un tableau de bord d’administration réalisé avec EasyAdmin, on veillera à le faire sur une section du site protégée par du contrôle d’accès.

On verra plus tard dans le cours comment protéger les accès aux pages.

Une fois que vous avez terminé, vous pouvez interrompre l’exécution du serveur Web de tests en tapant Ctrl+C dans le terminal.

9. Évaluation

À l’issue de cette séance vous avez travaillé sur les éléments suivants :

  • vous avez initié un projet Symfony à partir d’un squelette fourni
  • vous comprenez certaines fonctions de l’outil composer pour le téléchargement de bibliothèques, ou de squelettes de code
  • vous connaissez l’outil symfony console qui est utilisé par le développeur Symfony en ligne de commande
  • vous avez découvert le modèle de données objet codé en PHP permettant de gérer en mémoire des objets (classes objet décorées avec des annotations Doctrine)
  • vous savez recréer la base de données locale de tests
  • vous savez initialiser la base de données avec des données de test (DataFixtures)
  • vous savez où se trouvent les traces (logs) d’exécution de l’application
  • vous savez démarrer l’interface Web d’une application Symfony
  • vous savez comment modifier les données s’il y a un tableau de bord d’administration Web réalisé avec EasyAdmin

10. Pour aller plus loin (optionnel)

Nous vous proposons de façon complètement optionnelle d’aller un peu plus loin que ce qui est proposé par défaut dans la séance.

Ces opérations risquent de prendre un temps conséquent. Attention à ne pas empiéter sur les apprentissages des autres modules.

Ne vous lancez que si vous êtes conscient de maîtriser la situation.

10.1. Compréhension d’un algorithme de filtrage des tâches pas encore terminées, dans Todo

Vous pouvez examiner le fonctionnement de la commande app:list-active-todos permettant de lister les seules tâches pas encore terminées.

Consultez le code source dans src/Command/ListactiveTodosCommand.php, dont la méthode execute() propose un algorithme trivial pour filtrer les seules tâches qui ne sont pas encore terminées.

On peut se contenter d’une telle boucle testant les tâches non terminées et les ajoutant dans un tableau des tâches actives. Mais il y a d’autres façons de faire en Symfony, en faisant intervenir le composant d’ORM Doctrine.

Les commentaires proposent ainsi une autre variante que vous pouvez tester si vous le souhaitez.

10.2. Observation du contenu de vendor/

Au tout début, dans la création du projet avec Composer, on a mentionné que le sous-répertoire vendor/ du projet contient le code de toutes les bibliothèques PHP du framework Symfony.

Mais on est passé un peu vite dessus…

À quoi correspondent ces bibliothèques ? On le verra plus en détail au fil des séances.

Essayons de découvrir un peu ce dont on parle. Par exemple Doctrine, précisément, c’est où ?

Pour l’instant, on a noté par exemple que dans le code d’une commande, un simple import d’un module PHP avec use permet de faire le lien avec Doctrine :

use Doctrine\Persistence\ManagerRegistry;

Votre IDE devrait pouvoir vous dire ce qu’il en est : positionner la souris sur le terme « ManagerRegistry » dans cette ligne. Un popup apparaît avec la documentation de cette interface : « Contract covering object managers for a Doctrine persistence layer ManagerRegistry class to implement. ». Avec Eclipse, si vous appuyez alors sur F2 (focus), vous voyez apparaître le bouton « Open Declaration ».

Si vous cliquez dessus, ça ouvre le code source du fichier vendor/doctrine/persistence/src/Persistence/ManagerRegistry.php fourni par Doctrine, qui a été installé par Composer.

Vous pouvez ainsi naviguer dans le code des composants du framework Symfony.

Pour avoir une idée de l’ampleur de ce framework, voyons ce que contient vendor/, dans ce projet relativement simple :

  • liste des bibliothèques (approximation) :

    find vendor/ -maxdepth 2
    

    retourne 130 sous-répertoires, installés par Composer sur la base des déclarations de composer.json.

  • nombre de fichiers :

    find vendor/ -type f | wc -l
    
    9761
    

    tout n’est pas que du code, mais quand même;

  • nombre de fichiers source PHP (« .php ») :

    find vendor/ -type f -name "*.php" | wc -l 
    
    8240
    

    on voit qu’une grande partie est bien quand-même du code PHP.

  • espace disque occupé :

    du -sh vendor/
    
    113M	vendor/
    

    ce n’est pas énorme vu la taille d’un disque dur moderne, mais en code source, ça en fait des lignes…

  • nombre de lignes de code (approximation large)

    find vendor -type f | xargs grep -l '<\?php' | xargs cat | sed '/^\s*$/d' | wc -l
    
    1703209
    

    Ah, quand-même, 1,7 M lignes… combien de bugs au kilo ? ;-)

10.3. Re-construction de l’application en partant d’un projet Symfony vide

Au début de cette séquence de TP, on a fait installer un squelette déjà prêt à l’emploi (avec composer create-project). Le code des commandes était déjà là, ayant été préparé par l’équipe enseignante.

Vous pouvez tester le fait de repartir d’un projet Symfony vide, en suivant les étapes de l’annexe ci-dessous. Attention, cela prend du temps, et n’est pas indispensable pour la suite du cours.

Non, vraiment, ça va prendre du temps, et vous avez d’autres cours à travailler, plutôt que de faire ça, n’est-ce pas !

DONE Annexes

Cf. making-todo.html qui documente l’essentiel des étapes utilisées pour réaliser, de zéro, la version 2.x de l’application Todo telle que vue dans cette séance.

Notes de bas de page:

1

On verra plus tard dans le cours comment les technologies autour de CSS et Javascript permettent de faire fonctionner ce genre de changements d’aspect dans un document HTML.

Author: Olivier Berger (TSP)

Date: 2025-07-16 Wed 11:30

Emacs (Org mode)