Des identifiants sécurisés par type avec Symfony et Doctrine : l'utilisation de classes d’ID dédiées

· Oskar Stark · Temps de lecture: 2 minutes
type-safety-uuid

Apprenez à améliorer la sécurité des types dans Symfony et Doctrine en utilisant des classes d’ID dédiées comme BookId et UserId au lieu d’UUID bruts. Cette approche permet d'éviter la confusion des identifiants, de rendre le code plus clair et d'assurer une meilleure intégration avec Symfony Messenger et les méthodes de repository. Découvrez des exemples pratiques et les meilleures pratiques pour implémenter des identifiants sécurisés par type dans vos applications Symfony.

L'utilisation d'UUIDs comme identifiants d'entité est une approche courante avec Symfony et Doctrine. En général, les IDs sont stockés sous forme de nombres entiers simples ou d'objets UUID bruts. Cependant, cela peut entraîner une confusion des types, en particulier lors de l'utilisation de Symfony Messenger ou des méthodes de repository. Une approche plus robuste et plus sûre consiste à utiliser des classes d'ID dédiées.

Pourquoi utiliser des classes d'ID dédiées ?

L'utilisation d'une classe d'ID dédiée, comme BookId ou UserId, garantit que les identifiants ne soient pas accidentellement confondus. C'est particulièrement utile pour la gestion de messages avec Symfony Messenger, où plusieurs UUIDs peuvent être passés. Par exemple :

namespace App\Message;

final readonly class MarkBookAsRead
{
    public function __construct(
        public BookId $bookId,
        public UserId $userId,
    ) {}
}

Avec cette approche, nous nous assurons qu'un BookId ne sera jamais confondu avec un UserId. Si nous utilisions des UUIDs bruts, les paramètres pourraient être facilement inversés, ce qui entraînerait des erreurs difficiles à diagnostiquer.

Implémenter une classe d'ID dédiée

Voici comment définir une classe d'ID dédiée pour une entité Book :

namespace App\Domain;

use Symfony\Component\Uid\Ulid;

final class BookId extends Ulid
{
}

Désormais, dans votre entité Book, vous pouvez utiliser cette classe comme identifiant :

namespace App\Entity;

use App\Domain\BookId;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Book
{
    #[ORM\Id]
    #[ORM\Column(type: 'uuid', unique: true)]
    private BookId $id;

    public function __construct()
    {
        $this->id = new BookId();
    }

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

    // ...
}

Le type Doctrine nécessaire

Ce dernier exemple entraînera l’exception suivante dans le code :

Cannot assign Symfony\Component\Uid\Ulid to property App\Entity\Book::$id of type App\Entity\BookiId

Pour le corriger, un BookIdType est nécessaire :

namespace App\Doctrine\Type;

use App\Domain\BookId;
use Symfony\Bridge\Doctrine\Types\AbstractUidType;

final class BookIdType extends AbstractUidType
{
    public function getName(): string
    {
        return self::class;
    }

    protected function getUidClass(): string
    {
        return BookId::class;
    }
}

Ce type doit ensuite être enregistré et utilisé :

# config/packages/doctrine.yaml
doctrine:
    dbal:
        types:
            App\Doctrine\Type\BookIdType: App\Doctrine\Type\BookIdType

Dans l’entité Book :

namespace App\Entity;

+use App\Doctrine\Type\BookIdType;
use App\Domain\BookId;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Book
{
    #[ORM\Id]
-   #[ORM\Column(type: 'ulid', unique: true)]
+   #[ORM\Column(type: BookIdType::class, unique: true)]

    private BookId $id;

    public function __construct()
    {
        $this->id = new BookId();
    }

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

    // ...
}

Les méthodes de repository avec typage fort

Un autre avantage est l'utilisation de méthodes de repository avec typage fort. Plutôt que de récupérer des entités via un string UUID générique, vous pouvez appliquer la sécurité des types au niveau des méthodes :

namespace App\Repository;

use App\Domain\BookId;
use App\Entity\Book;

final class BookRepository
{
    public function get(BookId $id): Book
    {
        $book = $this->find($id->toString());
        if (null === $book) {
            throw BookNotFoundException::withId($id);
        }
        return $book;
    }
}

Et définir une exception explicite :

namespace App\Exception;

use App\Domain\BookId;

final class BookNotFoundException extends \RuntimeException
{
    public static function withId(BookId $id): self
    {
        return new self(sprintf('Livre avec l’ID %s introuvable.', $id->toString()));
    }
}

Conclusion

L'utilisation de classes d'ID dédiées dans Symfony avec Doctrine améliore la sécurité des types, réduit le risque de confusion des identifiants et améliore la clarté du code. C'est particulièrement utile lors de l'utilisation de Symfony Messenger et des méthodes de repository, où une mauvaise gestion des IDs peut entraîner des erreurs à l'exécution. En implémentant des classes d'ID dédiées, vous créez une base de code plus robuste et plus facile à maintenir.

Utilisez dès maintenant des classes d’ID

SensioLabs aide votre équipe à adopter les meilleures pratiques pour développer des projets maintenables et évolutifsContactez-nous dès maintenant pour en savoir plus !

Cela pourrait aussi vous intéresser

Fabien Potencier
Elise Hamimi

SymfonyCon Amsterdam 2025 : Notre bilan et les moments forts

Après une première édition emblématique en 2019, SymfonyCon a fait son grand retour à Amsterdam. Dès les premières minutes, on sentait l’énergie d’un rendez-vous très attendu : plus de 1 200 participants, 39 nationalités, les retrouvailles avec la communauté, de belles découvertes… et une ambiance de folie. Cette année, l’événement avait une saveur toute particulière puisqu’il s’agissait de l’édition spéciale anniversaire des 20 ans de Symfony. SensioLabs y était : on vous raconte tout !

En savoir plus
The SensioLabs team celebrating the 20th anniversary of Symfony with balloons
Jules Daunay

L'histoire continue : SensioLabs célèbre les 20 ans de Symfony

Le temps passe vite, surtout quand on écrit le futur du développement ! L’équipe de SensioLabs vient de souffler les 20 bougies du framework Symfony. Nous avons marqué le coup au bureau, mais la fête n'est pas terminée. Le rendez-vous est déjà pris pour une célébration XXL à SymfonyCon Amsterdam 2025 les 27 au 28 novembre.

En savoir plus
3 dog heads
Mathieu Santostefano

Venez avec votre propre client HTTP

Libérez-vous des dépendances rigides de vos SDK PHP. Dans cet article, apprenez à utiliser les normes PSR-7, PSR-17 et PSR-18, ainsi que la bibliothèque php-http/discovery, pour permettre à vos utilisateurs d'utiliser le client HTTP de leur choix, qu'il s'agisse de Guzzle, de Symfony HttpClient ou d'un autre. Un incontournable pour les développeurs PHP et Symfony.

En savoir plus
Blue sign on a building with several Now What? letters
Thibaut Chieux

Comment prioriser les messages lors du développement d'applications asynchrones avec Symfony Messenger

Le traitement asynchrone offre des avantages tels que la découplage des processus et des temps de réponse plus rapides, mais la gestion des priorités des messages peut s'avérer complexe. Pour traiter des tâches allant de la réinitialisation de mot de passe à des exports complexes, il est essentiel de garantir la livraison rapide des messages critiques. Cet article examine les problèmes fréquents liés au traitement asynchrone et propose des solutions avec Symfony Messenger pour optimiser votre application sans refonte majeure.

En savoir plus
SensioLabs University Courses Annonce La nouvelle formation Master de niveau 3 est disponible sur un fond vert
Jules Daunay

Master Symfony : Devenez un expert de Symfony avec notre nouvelle formation

Améliorez votre maîtrise de Symfony grâce à la nouvelle formation Master de niveau 3 sur Symfony ! Maîtrisez les sujets les plus complexes du framework et développez des compétences approfondies.

En savoir plus
Two images: on the left many cars stuck in a traffic jam with the sign "All directions" above, on the right a blue car moving forward alone on the highway with the sign "Service Subscriber" and a Symfony logo above
Steven Renaux

Les Lazy Services de Symfony : Boostez votre DX en utilisant les Service Subscribers

Optimisez la performance de votre application Symfony et l'expérience développeur ! Apprenez à utiliser les Service Subscribers et les attributs de chargement différé des services afin de réduire l'instanciation rapide, de simplifier les dépendances et de créer un code modulaire et maintenable.

En savoir plus
Affiche sur l'interview de Guillaume Loulier
Salsabile El-Khatouri

Dans les coulisses d’une formation SensioLabs

À quoi ressemble une formation Symfony donnée par SensioLabs ? Découvrez-le dans cette interview avec Guillaume Loulier, développeur & formateur passionné, qui nous explique tout sur le fonctionnement des formations officielles sur le framework.

En savoir plus
Toy factory production line
Silas Joisten

Boostez vos tests Symfony avec Zenstruck Foundry

Zenstruck Foundry a révolutionné notre manière d’écrire des tests dans Symfony. Dans cet article, vous apprendrez comment des fabriques expressives, des données de test isolées et une expérience développeur plus fluide nous ont permis d’optimiser nos flux de tests et d’améliorer la productivité.

En savoir plus
Image