Typensichere IDs mit Symfony und Doctrine: Verwendung dedizierter ID-Klassen

· Oskar Stark · Expertise · 2 Minuten zum Lesen
type-safety-uuid

Lerne, wie du die Typensicherheit in Symfony und Doctrine durch die Verwendung dedizierter ID-Klassen wie BookId und UserId anstelle roher UUIDs verbessern kannst. Dieser Ansatz verhindert die Verwechslung von IDs, verbessert die Codeklarheit und sorgt für eine bessere Integration mit Symfony Messenger und Repository-Methoden. Entdecke praxisnahe Beispiele und Best Practices zur Implementierung typsicherer IDs in deinen Symfony-Anwendungen.

Beim Arbeiten mit Symfony und Doctrine ist die Verwendung von UUIDs als Entitätskennungen eine gängige Vorgehensweise. Traditionell werden IDs als einfache Ganzzahlen oder als rohe Uuid-Objekte gespeichert. Dies kann jedoch zu Verwechslungen führen, insbesondere beim Arbeiten mit Symfony Messenger oder Repository-Methoden. Ein robusterer und typsicherer Ansatz besteht darin, dedizierte ID-Klassen zu verwenden.

Warum dedizierte ID-Klassen verwenden?

Durch die Verwendung einer dedizierten ID-Klasse, wie BookId oder UserId, wird sichergestellt, dass Kennungen nicht versehentlich vertauscht werden. Dies ist besonders nützlich beim Arbeiten mit Symfony Messenger-Nachrichten, in denen mehrere UUIDs übergeben werden. Zum Beispiel:

namespace App\Message;

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

Mit diesem Ansatz wird sichergestellt, dass eine BookId niemals mit einer UserId verwechselt wird. Würden wir generische UUIDs verwenden, könnten die Parameter leicht vertauscht werden, was zu schwer Fehlern führen kann.

Implementierung einer dedizierten ID-Klasse

So kann eine dedizierte ID-Klasse für ein Book-Entity definiert werden:

namespace App\Domain;

use Symfony\Component\Uid\Ulid;

final class BookId extends Ulid
{
}

Nun kann diese Klasse im Book-Entity verwendet werden:

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;
    }

    // ...
}

Der benötigte Doctrine-Typ

Das letzte Code-Beispiel liefert uns folgende Exception:

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

Um das zu beheben, benötigen wir einen BookIdType :

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;
    }
}

welcher registriert und benutzt werden muss:

# config/packages/doctrine.yaml
doctrine:
    dbal:
        types:
            App\Doctrine\Type\BookIdType: App\Doctrine\Type\BookIdType
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;
    }

    // ...
}

Typsichere Repository-Methoden

Ein weiterer Vorteil sind typsichere Repository-Methoden. Anstatt Entities mit einer generischen string-UUID abzufragen, kann die Typensicherheit auf Methodenniveau erzwungen werden:

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;
    }
}

Und eine aussagekräftige Exception definieren:

namespace App\Exception;

use App\Domain\BookId;

final class BookNotFoundException extends \RuntimeException
{
    public static function withId(BookId $id): self
    {
        return new self(sprintf('Buch mit der ID %s nicht gefunden.', $id->toString()));
    }
}

Fazit

Die Verwendung dedizierter ID-Klassen in Symfony mit Doctrine bietet Typensicherheit, reduziert das Risiko von Verwechslungen bei Kennungen und verbessert die Codeklarheit. Dies ist besonders nützlich beim Arbeiten mit Symfony Messenger und Repository-Methoden, wo eine falsche ID-Handhabung zu Laufzeitfehlern führen kann. Durch die Implementierung dedizierter ID-Klassen entsteht eine robustere und besser wartbare Codebasis.

Nutze jetzt ID Klassen!

SensioLabs hilft Teams dabei, Best Practices für wartbare und skalierbare Software umzusetzen. Kontaktiere uns noch heute, um mehr zu erfahren!

Das könnte dich auch interessieren

Symfony UX training
Elise Hamimi

Lerne Symfony UX mit dem neuen offiziellen Training von SensioLabs

In nur wenigen Jahren ist Symfony UX bei Symfony-Entwickler richtig beliebt geworden. Perfekt passend zu den heutigen Prioritäten, hilft es dir, interaktive und performante Interfaces zu bauen – ohne den Komfort des Frameworks zu verlassen. Zeit also, das Thema in unseren Schulungskatalog aufzunehmen. Genau deshalb starten wir offiziell unser neues Symfony-UX-Training.

Mehr erfahren
Fabien Potencier
Elise Hamimi

SymfonyCon Amsterdam 2025: Unser Rückblick und die Highlights

Nach einer legendären ersten Ausgabe im Jahr 2019 feierte die SymfonyCon ihr großes Comeback in Amsterdam. Von Anfang an war die Energie einer mit Spannung erwarteten Konferenz zu spüren: mehr als 1.200 Teilnehmer, 39 Nationalitäten, das größte Treffen der Symfony-Community des Jahres, großartige Entdeckungen ... und eine ausgelassene Atmosphäre. Dieses Jahr war etwas ganz Besonderes, denn es war das 20-jährige Jubiläum von Symfony. SensioLabs war dabei: Wir berichten Ihnen ausführlich über unsere Erfahrungen dort!

Mehr erfahren
The SensioLabs team celebrating the 20th anniversary of Symfony with balloons
Jules Daunay

Die Geschichte geht weiter: SensioLabs feiert 20 Jahre Symfony

Die Zeit vergeht wie im Flug – besonders, wenn man an der Zukunft der Entwicklung schreibt! Das SensioLabs-Team hat gerade die 20 Kerzen des Symfony-Frameworks ausgeblasen. Wir haben den Anlass im Büro gefeiert, doch die Party ist noch nicht vorbei. Das Datum für eine XXL-Feier steht bereits fest: die SymfonyCon Amsterdam vom 27. bis 28. November 2025.

Mehr erfahren
3 dog heads
Mathieu Santostefano

Lass die Nutzer des SDK ihren eigenen HTTP-Client nutzen

Befreie dich von starren Abhängigkeiten in deinen PHP-SDKs. Erfahre, wie du die Standards PSR-7, PSR-17 und PSR-18 zusammen mit PHP-HTTP/Discovery nutzt, um deinen Benutzern die Verwendung ihres bevorzugten HTTP-Clients zu ermöglichen – sei es Guzzle, Symfony HttpClient oder ein anderes Tool. Ein Muss für PHP- und Symfony-Entwickler.

Mehr erfahren
Blue sign on a building with several Now What? letters
Thibaut Chieux

Wie man Nachrichten beim Aufbau asynchroner Anwendungen mit dem Symfony-Messenger priorisiert

Die asynchrone Verarbeitung bietet Vorteile wie entkoppelte Prozesse und schnellere Reaktionszeiten. Die Verwaltung von Nachrichtenprioritäten kann jedoch zu einer Herausforderung werden. Bei Aufgaben, die vom Zurücksetzen von Passwörtern bis hin zu komplexen Exporten reichen, ist die rechtzeitige Zustellung kritischer Nachrichten unerlässlich. Dieser Artikel befasst sich mit häufigen Problemen bei der asynchronen Verarbeitung und zeigt Lösungen mit Symfony Messenger auf, mit denen Sie Ihre Anwendung ohne umfangreiches Refactoring optimieren können.

Mehr erfahren
SensioLabs University Courses announcing the new level 3 Master training course now available
Jules Daunay

Wir stellen vor: Mastering Symfony 7

Wenn du deine Symfony-Kenntnisse verbessern möchtest, ist der neue Level-3 Trainingskurs bei SensioLabs vielleicht das Richtige für dich! Du meisterst komplexe Themen, optimierst die Leistung und wirst zum Symfony-Experten.

Mehr erfahren
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

Symfony Lazy Services mit Stil – Steigere deine Entwicklererfahrung mit Service Subscribers

Steigere die Performance und Developer Experience (DX) deiner Symfony-App! Erfahre, wie du Service Subscribers und Traits für das verzögerte Laden von Services verwendest, um die sofortige Instanziierung zu reduzieren, Abhängigkeiten zu vereinfachen und modularen, wartbaren Code zu schreiben.

Mehr erfahren
Poster of Guillaume Loulier presentation
Salsabile El-Khatouri

Ein Symfony-Training bei SensioLabs: Hinter den Kulissen

Wie sieht die Symfony-Schulung bei SensioLabs aus? Erfahren Sie es im Interview mit Guillaume Loulier, einem leidenschaftlichen Entwickler und Trainer, der uns alles über die offiziellen Symfony-Schulungen erzählt.

Mehr erfahren
Image