Les entités

Les entités

1 mai 2021

Avoir un projet Symfony, c'est bien, mais avoir une base de données qui va avec, c'est mieux. Dans cet article, je vais aborder la création d'une base de données et de ses tables. Nous verrons aussi comment créer des requêtes personnalisées avec Doctrine, le tout en DQL (Doctrine Query Language).

Avant de se lancer dans la création de notre base de données, vous devez modifier le fichier de configuration ".env" se trouvant à la racine de votre projet.

DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7

Il suffit de modifier la ligne contenant DATABASE_URL par vos propres informations de connexion :

  • mysql : le type de SGBD (Système de Gestion de Base de Données, par défaut "mysql")
  • db_user : votre identifiant de connexion (en local, généralement "root")
  • db_password : votre mot de passe de connexion (en local, généralement pas de mot de passe)
  • 127.0.0.1:3306 : l'hôte et le port d'écoute de la base de données (par défaut en local)
  • db_name : le nom de la base de données que vous souhaitez créer
  • serverVersion=5.7 : la version du serveur SGBD (ici, MySQL 5.7)

Travaillant en local, ma configuration ressemblera à celle-ci :

DATABASE_URL=mysql://root@127.0.0.1:3306/my_database?serverVersion=5.7

Créer une base de données

Comme souvent sous Symfony, nous utiliserons le terminal de commandes pour générer la base de données.

symfony console doctrine:database:create

# Vous pouvez aussi utiliser une autre commande
# php bin/console doctrine:database:create

En réponse à cette commande, votre terminal vous retournera un message de succès.
La base de données est maintenant créée. Il ne reste plus qu'à travailler nos entités pour la remplir de tables SQL.

Créer une entité

L'entité est un fichier PHP contenant des propriétés, des getters et setters. Ce fichier est la structure de notre table SQL, c'est avec celui-ci que Doctrine va travailler.

Avant de vous lancer dans la construction d'une base de données, n'hésitez pas à prendre un papier, un crayon et à mettre à plat ce que vous voulez.

Dans mon cas, je vais créer une table SQL au nom de "agences" possédant les colonnes suivantes :

  • un nom
  • une adresse complète
  • une date de création

Vous remarquerez que je ne précise pas la clé primaire (ID). Ce n'est pas utile, car Symfony se chargera de la créer pour nous. ?

Depuis le terminal, tapez la ligne suivante :

NB :Le mot "Agences" commence par une majuscule (UpperCamelCase)
symfony console make:entity Agences

# Vous pouvez aussi utiliser une autre commande
# php bin/console make:entity Agences

J'ai pris la décision de nommer ma table au pluriel. Il existe un débat à ce niveau (un débat stérile, mais que voulez-vous...). >Je vous incite à lire cet article sur le sujet : https://www.primative.net/fr/blog/nommer-ses-tables-singulier-vs.-pluriel/

Suite à cette commande, une série de questions va vous être posée.
Prenez le temps de bien les lires et de ne pas y répondre trop vite !

Dans un premier temps, Symfony va créer deux fichiers au nom de votre entité. Le premier sera dans le dossier "src/Entity/Agences.php" et le second dans le dossier "src/Repository/AgencesRepository" ; il est relié au premier. L'entité sera mise à jour à chaque nouvelle colonne.

La dernière question vous propose de continuer ou de vous arrêter de créer des colonnes. Si jamais vous avez fini la création de votre table, ne répondez rien à cette question et appuyez sur la touche "Entrée" de votre clavier. Ayant encore deux colonnes à ajouter, je poursuis ma création :

L'entité "Agences.php" est maintenant à jour. Ouvrez le fichier pour voir sa structure :

<?php

namespace App\Entity;

use App\Repository\AgencesRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=AgencesRepository::class)
 */
class Agences
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=80)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $address;

    /**
     * @ORM\Column(type="datetime")
     */
    private $created_at;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    public function getAddress(): ?string
    {
        return $this->address;
    }

    public function setAddress(string $address): self
    {
        $this->address = $address;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->created_at;
    }

    public function setCreatedAt(\DateTimeInterface $created_at): self
    {
        $this->created_at = $created_at;

        return $this;
    }
}

C'est tout pour cette partie ! Nul besoin de modifier ce fichier, il servira à la création de notre table. Ne cherchez pas dans votre base de données non plus, la table n'est toujours pas créée. ?

Maintenant, nous allons générer un fichier de migration. Il contiendra la requête SQL nécessaire à la création de la table.

symfony console make:migration

# Vous pouvez aussi utiliser une autre commande
# php bin/console make:migration

Un message de succès vous sera retourné.

Dans ce retour, on peut voir qu'a été généré un fichier dans le dossier "migrations" et que l'on nous propose une commande pour créer notre table.

symfony console doctrine:migrations:migrate

# Vous pouvez aussi utiliser une autre commande
# php bin/console doctrine:migrations:migrate

Répondez "yes" à la question et on pourra exécuter la migration.
Votre table est maintenant créée ! ?

Mettre à jour une entité

Vous avez besoin d'ajouter une ou plusieurs colonnes à votre entité ?
C'est très simple, tapez la même commande qui a servi à la génération de votre entité.

symfony console make:entity Agences

# Vous pouvez aussi utiliser une autre commande
# php bin/console make:entity Agences

Symfony détectera la présence du fichier et vous proposera d'ajouter de nouvelles colonnes.
Pratique !

À contrario, si vous voulez supprimer des colonnes, la technique est totalement différente. Il n'existe pas de ligne de commande pour le faire. Rassurez-vous, la manipulation reste quand même simple. Pour cela, ouvrez l'entité à modifier. Supprimez-la ou les propriétés dont vous ne voulez plus ainsi que les getters et setters associés.

À chaque fois que vous mettez à jour une ou plusieurs entités, tapez la commande suivante pour actualiser vos tables en base de données :

symfony console doctrine:schema:update --force

# Vous pouvez aussi utiliser une autre commande
# php bin/console doctrine:update:schema --force

Cette commande actualisera vos tables sans toucher aux données déjà présentes. ?

Les relations entre entités

En SQL, on peut relier deux tables entre elles grâce aux clés étrangères ; on peut aussi le faire avec nos entités.
Sans faire un cours sur SQL, je rappelle tout de même qu'il existe quatre cardinalités :

  • N:1 : ManyToOne
  • 1:N : OneToMany
  • 1:1 : OneToOne
  • N:N : ManyToMany

Avant de relier vos deux tables, réfléchissez bien au type de relation que vous voulez.
Dans mon exemple, je vais relier mon entité "Agences" à une autre entité nommée "Villes", la relation sera de type ManyToOne.

Je ne vais pas vous montrer comment construire une nouvelle entité, le principe ne change pas. Dans tous les cas, ne créez pas de colonne de relation, dans aucune des deux tables.

Ma clé étrangère se situera dans l'entité "Agences", qui sera reliée à "Villes".
Modifions notre entité "Agences" :

symfony console make:entity Agences

# Vous pouvez aussi utiliser une autre commande
# php bin/console make:entity Agences

New property name (press to stop adding fields) :
Ma clé étrangère se nommera "ville_id". Écrivez simplement le mot "ville" et non "ville_id", Symfony se chargera par la suite de rajouter "_id". ? Si jamais vous écriviez "ville_id", au moment de la génération, la colonne prendrait alors pour nom "ville_id_id".

Pour rappel, ne mettez pas "_id" dans une colonne de relation !

Field type (enter ? to see all types) [string] :
Dans le type de champ, j'ai écrit "relation" pour spécifier que je souhaite... une relation ?. Si vous souhaitez connaître les autres types, mettez un point d'interrogation et validez. Le terminal affichera alors tous les types existants.

What class should this entity be related to? :
La question ici est de savoir à quelle entité je souhaite relier cette nouvelle colonne. Vous devez donc entrer le nom de l'autre entité ! Respectez la casse, c'est très important, sinon gare aux erreurs par la suite. Dans mon cas, mon autre entité se nomme "Villes".

Relation type? [ManyToOne, OneToMany, ManyToMany, OneToOne] :
Ensuite, précisez le type de relation que vous souhaitez avoir. Recopiez l'une des quatre phrases proposées. Pour ma part, le type de relation adéquat sera "ManyToOne".

A new property will also be added to the Villes class so that you can access and set the related Agences object from it.
New field name inside Villes [agences] :

On nous propose de créer une relation inverse, c’est-à-dire de pouvoir retrouver toutes les agences depuis une ville. Ce n'est pas pour autant qu'une clé étrangère sera créée dans l'entité "Villes". Doctrine gère très bien ce système de double relation.

Is the Villes.agences property allowed to be null (nullable)? (yes/no) [yes] :
On nous demande si l'on veut que la colonne soit nullable, donc qu'elle puisse être vide. J'ai répondu "no", car je tiens à ce qu'une agence soit toujours reliée à une ville.

Do you want to automatically delete orphaned App\Entity\Villes objects (orphanRemoval)? (yes/no) [no] :
La question est de savoir si l'on veut supprimer les données présentes dans l'entité "Agences" qui sont reliées à "Villes" lorsqu'une ville est supprimée. J'ai répondu "yes". Cela évite d'avoir des données orphelines dans ma table "agences", c'est-à-dire des agences n'étant reliées à aucune ville ; de plus, ceci irait à l'encontre de mon désir d'avoir une clé étrangère qui ne soit pas nullable.


Prenez le temps de répondre aux questions sans vous précipiter !
Une fois votre entité mise à jour, mettez votre base de données elle aussi à jour, et votre nouvelle colonne sera créée et prête à l'emploi.

symfony console doctrine:schema:update --force

# Vous pouvez aussi utiliser une autre commande
# php bin/console doctrine:update:schema --force

Ma table a correctement été mise à jour avec ma clé étrangère.

Mon entité "Agences" possède une nouvelle propriété, de nouveaux getter et setter. Il en va de même pour mon entité "Villes" : rappelez-vous que j'ai répondu "yes" à la double relation.

<?php

// ...

/**
 * @ORM\ManyToOne(targetEntity=Villes::class, inversedBy="agences")
 * @ORM\JoinColumn(nullable=false)
 */
private $ville;

// ...

public function getVille(): ?Villes
{
    return $this->ville;
}

public function setVille(?Villes $ville): self
{
    $this->ville = $ville;

    return $this;
}

Reconstruire la base de données

Symfony a beau être sympa, comme dans tout projet en développement, on peut se retrouver avec des problèmes, notamment avec la base de données. L'idée est alors de supprimer totalement la base de données du projet et de la reconstruire. Évidemment, vous pouvez passer directement par votre logiciel SGBD ou alors, par le terminal. ?

symfony console doctrine:database:drop --force

# Vous pouvez aussi utiliser une autre commande
# php bin/console doctrine:database:drop --force

Cette commande a pour effet de supprimer la totalité de votre base de données ! Donc à utiliser avec précaution !

Je vous conseille fortement de supprimer tous les fichiers contenus dans le dossier "migrations" avant de continuer. Ensuite seulement, retapez les commandes précédentes nécessaires à la création de vos tables.

symfony console doctrine:database:create
symfony console make:migration
symfony console doctrine:migrations:migrate

# Vous pouvez aussi utiliser ces commandes
# php bin/console doctrine:database:create
# php bin/console make:migration
# php bin/console doctrine:migrations:migrate

Lister toutes les commandes

Symfony propose plusieurs commandes liées à Doctrine. Si vous souhaitez les voir, et pourquoi pas les essayer, tapez ceci dans votre terminal.

symfony console list doctrine

# Vous pouvez aussi utiliser une autre commande
# php bin/console list doctrine