Cours - Api Platform - Chapitre 01 - Mise en place du projet
SOMMAIRE
Configuration de la base de données
Création de la base de données
Ajouter des données automatiquement dans la base de données
Installation du module fixtures
Installation du générateur de données
Création d’un fichier « fixtures » pour générer des utilisateurs
Introduction
Dans cette série de chapitres, nous allons découvrir API Platform, un outil qui permet de créer rapidement des API. Nous pouvons l’installer dans un projet Symfony et il utilise Doctrine pour construire des API.
Comme d’habitude, nous allons découvrir cette technologie en créant un petit projet afin de pratiquer rapidement.
L’application que nous allons construire est un forum. Des utilisateurs inscrits pourront échanger en s’envoyant des messages.
Je passerai rapidement sur certaines notions que vous pouvez retrouver dans les chapitres concernant « Symfony » ici.
Mise en place du projet
Dans le Nuage-Pédagogique, lancez le terminal et mettez-vous sur le compte de l’utilisateur login.
Exemple :
su login4400
Puis créer un nouveau projet « Symfony » avec la commande suivante :
composer create-project symfony/skeleton forum 5.3.*
Placez-vous maintenant dans le répertoire forum :
cd forum
Configuration de la base de données
Installation des packages nécessaires :
composer require symfony/orm-pack
composer require --dev symfony/maker-bundle
Consultez la version de Mysql :
mysql --version
Voici le résultat :
mysql Ver 15.1 Distrib 10.3.29-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Configuration du fichier .env :
Je peux maintenant aller dans le fichier « .env » et désactiver avec un « # » la ligne qui commence par « DATABASE_URL="postgresql: » pour activer la ligne qui commence par « DATABASE_URL="mysql: » en retirant le « # ».
Configurez maintenant la ligne en y mettant vos identifiants (voir votre profil), le nom de la nouvelle base de données (dbforum) et la bonne version de votre SGBDR (mariadb).
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
DATABASE_URL="mysql://login4400:WDroeurCrJveZMj@127.0.0.1:3306/dbforum?serverVersion=mariadb-10.3.29"
# DATABASE_URL="postgresql://symfony:ChangeMe@127.0.0.1:5432/app?serverVersion=13&charset=utf8"
Pour résumer :
Remplacez « db_user » par votre login
Remplacez « db_password » par votre mot de passe
Remplacez « db_name » par «dbforum »
Création de la base de données
php bin/console doctrine:database:create
Pour créer la table « User », nous allons utiliser la commande spéciale de Symfony qui nous mettra en place la gestion de la sécurité avec la gestion des mots de passe.
Installation du bundle security :
composer require symfony/security-bundle
Création de l’entité User
php bin/console make:user
The name of the security user class (e.g. User) [User]: User
Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]: yes
Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]: email
Does this app need to hash/check user passwords? (yes/no) [yes]: yes
Dans l’entité « User », ajoutons les propriétés suivantes :
nom |
string de 30 caractères non nul |
prenom |
string de 30 caractères non nul |
dateInscription |
datetime non nul |
avec la commande suivante :
php bin/console make:entity User
Création de l’entité Message
titre |
string 50 caractères non nul |
datePoste |
datetime non nul |
contenu |
text non nul |
Tapez la commande suivante :
php bin/console make:entity Message
Création des relations
Un message appartient à un seul utilisateur, mais un utilisateur peut envoyer plusieurs messages.
Ainsi, dans l’entité « Message », nous devons avoir une propriété qui nous permettra de connaitre l’auteur. Pour ce faire, nous créons une relation ManyToOne de « Message » vers « User ».
php bin/console make:entity Message
New property name (press <return> to stop adding fields): user
Field type (enter ? to see all types) [string]: ManyToOne
What class should this entity be related to?: User
Is the Message.user property allowed to be null (nullable)? (yes/no) [yes]: no
Do you want to add a new property to User so that you can access/update Message objects from it - e.g. $user->getMessages()? (yes/no) [yes]: yes
New field name inside User [messages]: messages
Do you want to automatically delete orphaned App\Entity\Message objects (orphanRemoval)? (yes/no) [no]: yes
Un message peut être une réponse à un autre message. Il est important de connaitre cette information. Donc un message peut avoir un « parent » (ou peut être nul) et un message peut avoir plusieurs enfants.
Dans ces conditions, il faut créer dans « Message » une relation « ManyToOne » vers « Message ».
php bin/console make:entity Message
New property name (press <return> to stop adding fields): parent
Field type (enter ? to see all types) [string]: ManyToOne
What class should this entity be related to?: Message
Is the Message.parent property allowed to be null (nullable)? (yes/no) [yes]: yes
Do you want to add a new property to Message so that you can access/update Message objects from it - e.g. $message->getMessages()? (yes/no) [yes]: yes
New field name inside Message [messages]: messages
Nous pouvons maintenant créer les entités dans Mariadb :
php bin/console make:migration
php bin/console doctrine:migrations:migrate
Voici ce que nous pouvons voir dans le concepteur de PhpMyAdmin, accessible à partir de votre profil :
Commentaires :
Nous voyons que nous avons une relation de « User » vers « Message » et une relation de « Message » vers « Message ».
Ajouter des données automatiquement dans la base de données
Pour nos tests, nous allons alimenter automatiquement notre base de données à l’aide des fixtures et du module « faker ».
Les « fixtures » permettent d’alimenter une base de données avec un jeu d’essai pour tester rapidement une application avec de vraies données.
Le module « faker »permet de générer aléatoirement des données afin qu’elles paraissent réalistes.
Voir la documentation ici pour plus de détails. https://fakerphp.github.io/
Installation du module fixtures
composer require orm-fixtures --dev
Si vous rafraichissez l’arborescence du projet, vous verrez le répertoire « DataFixtures » dans « src ».
Installation du générateur de données
composer require fakerphp/faker
Création d’un fichier « fixtures » pour générer des utilisateurs
Créez le fichier « UserFixtures.php » dans le répertoire « DataFixtures » et mettez-y le contenu suivant :
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory;
use App\Entity\User;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserFixtures extends Fixture
{
private $faker;
private $passwordHasher;
public function __construct(UserPasswordHasherInterface $passwordHasher){
$this->faker=Factory::create("fr_FR");
$this->passwordHasher= $passwordHasher;
}
public function load(ObjectManager $manager): void
{
for($i=0;$i<10;$i++){
$user = new User();
$user->setNom($this->faker->lastName())
->setPrenom($this->faker->firstName())
->setRoles(array('ROlE_USER'))
->setEmail(strtolower($user->getPrenom()).'.'.strtolower($user->getNom()).'@'.$this->faker->freeEmailDomain())
->setPassword($this->passwordHasher->hashPassword($user, strtolower($user->getPrenom())))
->setDateInscription($this->faker->dateTimeThisYear());
$this->addReference('user'.$i, $user);
$manager->persist($user);
}
$manager->flush();
}
}
Commentaires :
use Faker\Factory; // Importation du module « Faker »
use App\Entity\User; // Importation de l’entité User afin de créer des utilisateurs
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; // Importation de la classe permettant le hachage des mots de passe.
$this->faker=Factory::create("fr_FR"); // paramétrage du faker pour la langue française
public function load(ObjectManager $manager) // Il s’agit de la méthode appelée lorsque nous souhaitons charger des fixtures.
for($i=0;$i<10;$i++){ // Nous créons une boucle pour créer 10 utilisateurs.
$user = new User(); // Création d’un nouvel utilisateur
$user->setNom($this->faker->lastName()) // Nous demandons à Faker de générer un nom de famille puis nous le stockons dans le nom de l’utilisateur.
->setPrenom($this->faker->firstName()) // Nous demandons à Faker de générer un prénom, puis nous le stockons dans le prénom de l’utilisateur.
->setRoles(array('ROlE_USER')) // Nous donnons le rôle « ROLE_USER » à chaque utilisateur.
>setEmail(strtolower($user->getPrenom()).'.'.strtolower($user->getNom()).'@'.$this->faker->freeEmailDomain()) // Nous construisons une adresse email avec le prénom et le nom de la personne. Le serveur de l’email est généré aléatoirement. Le code est perfectible car il peut y avoir des accents dans le prénom.
->setPassword($this->passwordHasher->hashPassword($user, strtolower($user->getPrenom()))) // pour tester facilement notre application, le mot de passe sera le prénom de la personne. Nous le hachons avant de le stocker dans user.
->setDateInscription($this->faker->dateTimeThisYear()); // Nous demandons à Faker de générer une date aléatoire de l’année courante.
$this->addReference('user'.$i, $user); // nous donnons un nom à notre objet afin de le récupérer dans d’autres fixtures. Ici, il aura le nom ‘user ‘suivi d’un numéro de 0 à 9.
$manager->persist($user); // Nous préparons l’enregistrement de l’utilisateur dans la base de données
$manager->flush(); // Nous validons nos ajouts
Par défaut, il existe le fichier « AppFixtures.php », vous pouvez le supprimer, il ne nous servira pas.
Vous pouvez lancer la création des « fixtures « avec la commande :
php bin/console doctrine:fixtures:load
Voici un exemple du chargement des fixtures créées aléatoirement :
Création du fichier permettant la création de messages
Dans « src\DataFixtures », créer le fichier « MessageFixtures.php ».
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory;
use App\Entity\User;
use App\Entity\Message;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
class MessageFixtures extends Fixture implements DependentFixtureInterface
{
private $faker;
public function __construct(){
$this->faker=Factory::create("fr_FR");
}
public function load(ObjectManager $manager): void
{
for($i=0;$i<10;$i++){
$message = new Message();
$message->setTitre($this->faker->sentence(3));
$message->setDatePoste($this->faker->dateTimeThisYear());
$message->setContenu($this->faker->paragraph());
$message->setUser($this->getReference('user'.mt_rand(0,9)));
$manager->persist($message);
}
$manager->flush();
}
public function getDependencies()
{
return [
UserFixtures::class,
];
}
}
Commentaires :
use Doctrine\Common\DataFixtures\DependentFixtureInterface; // Importation de la classe permettant de donner un ordre au chargement des fixtures
implements DependentFixtureInterface // la classe va utiliser l’interface qui permettra de donner des dépendences
public function getDependencies() // cette méthode renvoie un tableau de « fixtures » devant s’exécuter avant
$message->setTitre($this->faker->sentence(3)); // demande à Faker de créer une phrase de 3 mots
$message->setContenu($this->faker->paragraph()); // demande Faker de générer un paragraphe
$message->setUser($this->getReference('user'.mt_rand(0,9))); // donne un utilisateur créé précédemment afin d’indiquer qu’il est le propriétaire du message.
Lancez la commande :
php bin/console doctrine:fixtures:load
Pour l’instant, les messages n’ont pas de parent, cela veut dire qu’ils ne sont pas des réponses à d’autres messages.
Nous allons maintenant créer des messages qui auront un parent. Nous allons modifier notre code comme ceci :
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory;
use App\Entity\User;
use App\Entity\Message;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
class MessageFixtures extends Fixture implements DependentFixtureInterface
{
private $faker;
public function __construct(){
$this->faker=Factory::create("fr_FR");
}
public function load(ObjectManager $manager): void
{
for($i=0;$i<10;$i++){
$message = new Message();
$message->setTitre($this->faker->sentence(3));
$message->setDatePoste($this->faker->dateTimeThisYear());
$message->setContenu($this->faker->paragraph());
$message->setUser($this->getReference('user'.mt_rand(0,9)));
$manager->persist($message);
$this->addReference('message'.$i, $message);
}
for($i=0;$i<20;$i++){
$message = new Message();
$message->setTitre($this->faker->sentence(3));
$message->setDatePoste($this->faker->dateTimeThisYear());
$message->setContenu($this->faker->paragraph());
$message->setUser($this->getReference('user'.mt_rand(0,9)));
$message->setParent($this->getReference('message'.mt_rand(0,9)));
$manager->persist($message);
}
$manager->flush();
}
public function getDependencies()
{
return [
UserFixtures::class,
];
}
}
Commentaires :
$this->addReference('message'.$i, $message); // Nous donnons aux messages un identifiant afin de les appeler par la suite.
$message->setParent($this->getReference('message'.mt_rand(0,9))); // Nous appelons au hasard un des 10 parents.
Lancez la commande :
php bin/console doctrine:fixtures:load
Commentaire :
Vous remarquez qu’à partir du 11e, les messages ont un parent.
Nous avons maintenant un projet opérationnel pour créer des « API ». Cela se passera dans le prochain chapitre.