TP2 : Serveur avec Symfony et Doctrine
BUTS PÉDAGOGIQUES
- Création de projets Symfony
- Utilisation de l'ORM Doctrine
- Mise en place d'un webservice d'API en JSON
Dans ce sujet de TP nous effleurons la création de pages web avec le framework Symfony. L'objectif principal des suivants exercices est l'utilisation du framework Symfony pour construire une application permettant d'interroger une base de données MySQL avec l'ORM Doctrine, afin de mettre en œuvre un webservice d'API délivrant ces données au format JSON.
Exercice 1 • Créer et tester un projet Symfony
Créons un projet Symfony qui s'appellera « HelloSymfony » :
- Ouvrez un terminal sur le bureau № 3, puis créez le nouveau projet HelloSymfony dans le répertoire /home/estia/devel/ :
- cd ~/devel
- composer create-project symfony/skeleton hello-symfony
- cd hello-symfony
- ls
- Ajoutez les composants suivants dans le projet :
- composer require doctrine/annotations
- composer require twig/twig
- composer require twig/extra-bundle
- composer require symfony/web-server-bundle --dev ^4.4.2
Maintenant, observons l'exécution par défaut de ce nouveau projet Symfony qui est encore intact :
- Ouvrez un terminal sur le bureau № 7, puis démarrez cette application PHP avec l'appel suivant :
- cd devel/hello-symfony/
- php bin/console server:run
- Allez sur le bureau № 2, et avec le navigateur web (Chromium ou Firefox), accédez à l'URL suivante :
- http://127.0.0.1:8000
Observez le code source de la page web :
- Faîtes un clic droit et choisissez « Code source de la page » ou encore « View page source » ;
- ou faîtes directement la combinaison de touches : +
⇝ Trouvez-vous des traces de Javascript dans le code source de la page ? (c.-à-d., des balises <script/> ou des extentions .js)
Exercice 2 • Modifier un template Twig
Même si ce n'est pas l'objectif principal de ce TP, prenons quelques minutes pour observer le système de templating Twig qui est utilisé par Symfony.
- Depuis le terminal sur le bureau № 3, dans le répertoire /home/estia/devel/hello-symfony/, installez le bundle « Maker » :
- composer require symfony/maker-bundle --dev -W
- À l'aide du « Maker », que nous venons d'installer, générez un nouveau contrôleur appelé Default :
- php bin/console make:controller Default
- Allez sur le bureau № 2, et avec le navigateur web, accédez à l'URL suivante :
- http://127.0.0.1:8000/default
- Les quatre fichiers qui nous intéressent sont les suivants :
/home/estia/devel/
|-hello-symfony/
|-config/
| |-routes.yaml
|-src/
| |-Controller/
| | |-DefaultController.php
|-templates/
|-base.html.twig
|-default/
|-index.html.twig
- Le fichier routes.yaml décrit des règles de routage.
- Le fichier DefaultController.php est le contrôleur (une classe PHP) que nous venons de créer.
- Le fichier base.html.twig définit un modèle de base utilisable par d'autres fichiers Twig.
- Le fichier index.html.twig est le template Twig qui vient d'être créé pour le nouveau contrôleur Default que nous venons de créer. Il utilise le fichier base.html.twig comme modèle.
- Ouvrez ces quatre fichiers dans un éditeur de texte ou dans un IDE. Par exemple, depuis le terminal :
- gedit config/routes.yaml src/Controller/DefaultController.php templates/base.html.twig templates/default/index.html.twig&
- Observez le code de la méthode index() de la classe DefaultController dans le fichier DefaultController.php :
- Dans le commentaire qui précède la déclaration de cette méthode, nous voyons une annotation « @Route » qui associe cette méthode au routage /default.
- Cette méthode retourne le résultat de la méthode render() qui traite le fichier de template Twig associé au contrôleur, tout en transmettant le paramètre controller_name en lui donnant une valeur.
- Modifions le nom de ce paramètre ainsi que la valeur :
- Remplacez controller_name par msg
- Remplacez DefaultController par Description de mon site web.
- Enregistrez le fichier
- Dans le fichier index.html.twig :
- Remplacez le contenu du bloc title par Accueil
- Dans le bloc body, effacez le contenu de la balise <div/> et remplacer par un titre de niveau 1 affichant « Accueil » et un paragraphe qui affiche la variable Symfony msg :
<h1>Accueil</h1>
<p>{{ msg }}</p>
- Enregistrez le fichier
- Allez sur le bureau № 2, et avec le navigateur web, et vérifiez le nouvel affichage de la page :
- http://127.0.0.1:8000/default
- Nous allons maintenant définir notre contrôleur comme celui à utiliser à la racine « / » du serveur. Pour ce faire, dans le fichier routes.yaml, retirez les croisillons « # » en début des trois lignes :
index:
path: /
controller: App\Controller\DefaultController::index
- Allez sur le bureau № 2, et avec le navigateur web, et vérifiez la page qui s'affiche avec cette URL :
- http://127.0.0.1:8000
Exercice 3 • Webservice d'API en JSON
Note : Pour la suite, les explications détaillées ne sont pas encore disponibles : seulement les grandes lignes sont données pour vous guider.
⇝ Appuyez-vous sur la documentation (abondante) et les exemples (foisonnants) à partir d'Internet : savoir se former continuellement (au fil de l'évolution des technologies) est une qualité cruciale des informaticiens.
Créer un nouveau contrôleur d'API (c.-à-d., sans template Twig) : ce contrôleur répondra en envoyant des données JSON. Voici pour le créer :
- php bin/console make:controller --no-template Bird
Testez le résultat dans un navigateur web :
- http://127.0.0.1:8000/bird
Dans Firefox, cliquez sur l'onglet « Raw Data » ou « Données brutes » pour voir le fichier brut.
Une autre façon pratique de tester le service est de le faire avec CURL depuis le terminal :
- curl -X GET http://127.0.0.1:8000/bird
Modifiez pour que ce contrôleur retourne une liste d'oiseaux, de manière identique à celle de l'exercice 7 du TP1. Ajoutez à cette liste quelques oiseaux nicheurs du Poitou.
Ajoutez le composant NelmioCorsBundle dans le projet Symfony :
- composer require nelmio/cors-bundle
Modifiez la valeur de la variable CORS_ALLOW_ORIGIN dans le fichier .env du projet :
CORS_ALLOW_ORIGIN='^http://127.0.0.1:8080$'
Redémarrez le serveur de symfony
Côté front-end : en utilisant la bibliothèque axios, chargez maintenant la liste d'oiseaux (dans la page 4) partir d'un JSON obtenu en interrogeant le webservice d'API (dans le hook created, plutôt que mounted).
Côté back-end : ajoutez maintenant, en plus du champ « nom », deux autres champs « id » et « nbr » dans le JSON. Donnez des valeurs incrémentales pour le champ id et des valeurs quelconques pour le champ « nbr ».
Côté front-end : essayez d'initialiser le props start des compteurs à partir du champ « nbr » reçu dans le JSON.
Exercice 4 • Interrogation de MySQL avec l'ORM Doctrine
Nous voulons maintenant une base de données MySQL avec une table qui contiendra la liste de nos oiseaux nicheurs du Poitou.
Ajoutez l'ORM Doctrine dans le projet avec :
- composer require symfony/orm-pack:2.3.1 -W
- Répondez "x" à la question "Do you want to include Docker configuration from recipes?"
Créez la BDD db_poitou_birds :
- mysql -uroot -p
- CREATE DATABASE db_poitou_birds CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- GRANT ALL ON db_poitou_birds.* to appbirdsuser@127.0.0.1 identified by 'cuicuipass';
- quit
Ouvrez le fichier caché .env qui se trouve dans le répertoire du projet et remplacer la ligne de la variable DATABASE_URL par la ligne suivante dans le bloc « doctrine/doctrine-bundle » qui est en fin de fichier :
DATABASE_URL="mysql://appbirdsuser:cuicuipass@127.0.0.1:3306/db_poitou_birds"
Créez une nouvelle entité Bird (id:integer, nom:string, nbr:integer) en répondant aux questions de l'utilitaire du Maker :
- php bin/console make:entity
Ouvrez le fichier src/Entity/Bird.php et vérifiez que cela correspond bien.
Faîte la migration vers la BDD pour que la table soit créée en accord avec le schéma décrit par l'entité :
- php bin/console make:migration
- php bin/console doctrine:migrations:migrate
Insérez des noms d'oiseaux dans la table (par exemple, via phpMyAdmin à l'adresse http://127.0.0.1/phpmyadmin avec l'utilisateur root et le mot de passe estia).
Modifiez le contrôleur Bird pour construire la réponse à partir de la BDD, en vous aidant des Repositories de l'ORM Doctrine :
- En vous aidant de find() et findAll() du repository de Bird
- Et en vous aidant des méthodes getId(), getNom() et getNbr() de l'entité Bird.
Vérifiez en testant avec CURL depuis le terminal :
- curl -X GET http://127.0.0.1:8000/bird
Exercice 5 • Webservice d'API avec le bundle API Platform
Nous avons maintenant compris le mécanisme, alors recommençons avec un gestionnaire d'API pour accélérer le développement de l'application :
- Commencez par supprimer les tables précédemment créés :
- mysql -uroot -p
- USE db_poitou_birds;
- SHOW TABLES;
- DROP TABLE doctrine_migration_versions;
- DROP TABLE bird;
- quit
- mysql -uroot -p
- Supprimez l'entité « Bird » :
- rm src/Entity/Bird.php
- rm src/Repository/BirdRepository.php
- rm migrations/*
- Videz le cache :
- php bin/console cache:clear
- Ajouter API Platform dans le projet :
- composer require api-platform/core:2.6
- composer require doctrine/doctrine-migrations-bundle
Créons maintenant de nouveau des entités :
- Créez de nouveau l'entité Bird (id:integer, nom:string, nbr:integer) en utlisant :
- php bin/console make:entity
- Faîtes la migration pour que la table soit créée dans la BDD :
- php bin/console make:migration
- php bin/console doctrine:migrations:migrate
- Pour mieux décrire les espèces d'oiseaux (nicheur, hivernant, migrateur …), créez une nouvelle entité Categorie (libelle:string) en utilisant aussi :
- php bin/console make:entity
⇝ vous ajouterez un deuxième champ appelé « birds » qui sera de type ManyToMany : puis, répondez qu'il sera relié à la classe « Bird », puis répondez yes pour ajouter une propriété à « Bird ». - Faîtes la migration pour que les tables soient créées dans la BDD :
- php bin/console make:migration
- php bin/console doctrine:migrations:migrate
- Remarquez qu'une table intermédiaire a été créée pour la relation N-N (c.-à-d. ManyToMany) :
Allez sur le bureau № 2, et avec le navigateur web, accédez à le centre de gestion de votre API :
- http://127.0.0.1:8000/api
Exercice 6 • Interroger le nouveau webservice d'API
Pour tester les possibilités CRUD de ce nouveau webservice RESTfull, envoyons des requêtes avec CURL en utilisant quatre des méthodes HTTP (POST, GET, PUT, DELETE) reconnues par ce webservice :
- [CREATE] Insérez un nouvel oiseau :
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{"nom":"Héron Cendré", "nbr":10}'
⇝ Vous pouvez aussi tout simplement faire ceci depuis un terminal (c'est utile, car une fois déployé sur le Cloud, cela est parfois l'unique moyen d'accès depuis votre VM) :
- mysql -uroot -p
- USE db_poitou_birds;
- SELECT * FROM bird;
- [CREATE] Insérez plein de nouveaux oiseaux :
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{ "nom": "Roitelet huppé", "nbr": 0 }'
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{ "nom": "Bruant des roseaux", "nbr": 0 }'
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{ "nom": "Butor étoilé", "nbr": 0 }'
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{ "nom": "Héron pourpré", "nbr": 0 }'
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{ "nom": "Mésange noire", "nbr": 0 }'
- curl -X POST "http://127.0.0.1:8000/api/birds" -H "Content-Type: application/ld+json" -d '{ "nom": "Moineau friquet", "nbr": 0 }'
- [READ] Récupérez les informations de tous les oiseaux :
- curl -X GET "http://127.0.0.1:8000/api/birds"
- curl -X GET "http://127.0.0.1:8000/api/birds" | json_pp
- [READ] Récupérer les informations de l'oiseau avec l'id de valeur 1 :
- curl -X GET "http://127.0.0.1:8000/api/birds/1"
- curl -X GET "http://127.0.0.1:8000/api/birds/1" | json_pp
- [UPDATE] Modifiez la valeur du compteur de l'oiseau avec l'id de valeur 1 :
- curl -X PUT "http://127.0.0.1:8000/api/birds/1" -H "Content-Type: application/ld+json" -d '{ "nbr" : 11 }' | json_pp
- [DELETE] Supprimez l'oiseau avec l'id de valeur 1 :
- curl -X DELETE "http://127.0.0.1:8000/api/birds/1"