Cours - Api Platform - Chapitre 01 - Mise en place du projet

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.



Voir le Chapitre 2