Utiliser des UUID dans ses entités Symfony

Tanguy Dechiron

Pour rappel, un UUID (Universally Unique Identifier) est un identifiant unique de 128 bits de longueur, généralement représenté par une chaîne de 32 nombres hexadécimaux séparés en 5 groupes par des tirets, comme par exemple:

8af1176b-a6c1-11ec-9940-80b655969ef7


On utilise généralement des entiers en tant que clé primaire d'une table dans une base de données, mais il est tout à fait possible d'utiliser des UUIDs, ce qui présente certains avantages :

  • Les identifiants sont moins prévisibles que des entiers, par exemple au lieu d'avoir une url /user/1234 on aura /user/8af1176b-a6c1-11ec-9940-80b655969ef7 soit un gain en sécurité
  • Il est possible de générer les identifiants hors de la base de données directement dans le code, ce qui peut soulager le SGBD
  • les identifiants sont réellement uniques entre différentes bases de données, et facilite les merges entre base de données / serveurs

Mais également des inconvénients :

  • il nécessitent 16 octets pour être stockés en base de données, contre généralement 4 octets à 8 octets pour des entiers
  • moins lisible que des entiers pour les requêtes
  • perte d'intérêt de classer par identifiant


Il y a certainement un impact sur les performances, qui est néanmoins négligeable dans la plupart des cas.



Les UUIDs avec Symfony

Depuis 5.2, le type UUID a été introduit dans Symfony via le composant Uid, pour l'installer:

composer require symfony/uid


Si on prend une entité Doctrine avec un identifiant entier par défaut :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id;

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

Il faut changer l'attribut pour le passer en UUID :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;

class Product
{
    #[ORM\Id]
    #[ORM\Column(type: UuidType::NAME, unique: true)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
    private ?Uuid $id;

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


Il est également possible de générer l'UUID avec le composant de Symfony depuis le constructeur de l'entité :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;

class Product
{
    #[ORM\Id]
    #[ORM\Column(type: UuidType::NAME, unique: true)]
    private ?Uuid $id;

    public function __construct()
    {
        $this->id = Uuid::v4();
    }


Je mets également le lien vers la documentation officielle du composant Uid de Symfony.


Les UUIDs dans les bases de données

Nous allons voir comment sont stockés ces identifiants dans MySQL et PostgreSQL.

PostgreSQL

PostgreSQL dispose d'un type natif UUID, et les différentes requêtes se font sous la forme chaîne de caractères des UUIDs ce qui facilite grandement le travail. Par contre il n'y a pas nativement de fonction pour générer un UUID, il faudra donc passer par une extension tierce comme uuid-ossp.

select * from user where id = '84ebc22f-6c3c-482a-8d74-4b9133bf903e';

-- avec uuid-ossp installé
insert info user (id) values (uuid_generate_v4());

MySQL

MySQL stocke les identifiants UUID sous le type binary(16), ce qui fait que les données ne sont pas lisibles ni insérables sous leur forme usuelle. Par contre il existe plusieurs fonctions pour créer et faire des transformations d'UUIDs : UUID(), UUID_TO_BIN(), BIN_TO_UUID().

select * from user where id = UUID_TO_BIN('84ebc22f-6c3c-482a-8d74-4b9133bf903e');

insert info user (id) values (UUID_TO_BIN(uuid()));



Voilà c'est tout pour aujourd'hui, j'espère vous avoir donné envie d'expérimenter voire d'utiliser des UUIDs pour votre projet. En ce qui me concerne j'ai tendance à ne plus utiliser que ce type dans mes projets, les inconvénients étant minimes face aux gains en sécurité et scalabilité apportés.



A propos de l'auteur

Tanguy Dechiron

Tanguy Dechiron

Développeur web fullstack (Symfony++).
Passionné de littérature fantasy, jeux de société.
Cycliste du dimanche.


Blog Comments powered by Disqus.