Files
ext.jeremy.guillot@maxicoffee.domains dae215dd3d
All checks were successful
Build and Deploy / deploy (push) Successful in 9m36s
feat: ajout de claude + correction des tests
2026-03-09 17:09:31 +01:00

4.0 KiB

name, description, allowed-tools
name description allowed-tools
ddd-core Règles DDD du projet Mangarr — Aggregates, Value Objects immutables, Domain Events, invariants. Utiliser quand on crée ou modifie un Model, Value Object, Event ou Exception dans src/Domain/*/Domain/. Read, Grep, Glob

Règles DDD — Couche Domain

Emplacement

src/Domain/{DomainName}/Domain/
  Model/
    {AggregateName}.php
    ValueObject/
      {VoName}.php
  Event/
    {SomethingHappened}.php
  Exception/
    {Something}Exception.php
  Contract/
    Repository/
      {Name}RepositoryInterface.php
    Service/
      {Name}Interface.php
    Client/
      {Name}ClientInterface.php

Aggregates

  • Classe normale (pas readonly), propriétés private.
  • Le constructeur prend des Value Objects, jamais des scalaires bruts pour les identifiants et concepts métier.
  • Aucune annotation Doctrine dans le Model — c'est la responsabilité du Repository (Infrastructure).
  • Les méthodes métier protègent les invariants et lèvent des Domain Exceptions (jamais des exceptions génériques).
  • Les setters publics sont interdits. Exposer des méthodes métier explicites (updateImageUrls(), enableMonitoring(), etc.).
// ✅ Correct
class Manga
{
    public function __construct(
        private MangaId $id,
        private MangaTitle $title,
        private MangaSlug $slug,
        // ...
    ) {}

    public function updateImageUrls(ImageUrls $imageUrls): void
    {
        $this->imageUrls = $imageUrls;
    }
}

// ❌ Interdit
class Manga
{
    public string $title; // propriété publique
    #[ORM\Column] // annotation Doctrine dans le Domain
    private string $title;
    public function setTitle(string $title): void {} // setter générique
}

Value Objects

  • Toujours readonly class.
  • Valider dans le constructeur, lever une Domain Exception si invalide.
  • Exposer getValue() pour récupérer la valeur primitive.
  • Jamais de dépendance externe (pas de Symfony, pas de Doctrine).
readonly class MangaTitle
{
    public function __construct(public readonly string $value)
    {
        if (empty(trim($value))) {
            throw new InvalidMangaTitleException('Title cannot be empty');
        }
    }

    public function getValue(): string
    {
        return $this->value;
    }
}

Valeurs composées (ex: chemins d'images) → Value Object avec plusieurs propriétés :

readonly class ImageUrls
{
    public function __construct(
        private string $full,
        private string $thumbnail,
    ) {}

    public function getFull(): string { return $this->full; }
    public function getThumbnail(): string { return $this->thumbnail; }
}

Domain Events

  • Nommés au passé : MangaCreated, ChapterImported, MonitoringEnabled.
  • readonly class, transportent uniquement des scalaires (pas d'objets du Domain).
  • Placés dans Domain/Event/.
  • Dispatchés depuis le CommandHandler (Application), jamais depuis le Domain lui-même.
  • Le bus utilisé est MessageBusInterface de Symfony Messenger (autorisé dans Application, pas dans Domain).
readonly class MangaCreated
{
    public function __construct(
        public string $mangaId,
        public string $externalId,
    ) {}
}

Domain Exceptions

  • Étendent DomainException ou \RuntimeException selon le cas.
  • Nommées avec le suffixe Exception ou NotFoundException.
  • Localisées dans Domain/Exception/.
class MangaNotFoundException extends \DomainException
{
    public function __construct()
    {
        parent::__construct('Manga not found');
    }
}

Règles d'invariants PHPArkitect (enforced automatiquement)

  • App\Domain\{X}\Domainaucune dépendance en dehors de son propre namespace.
  • Exceptions autorisées : DateTimeImmutable, RuntimeException, Exception, DomainException, InvalidArgumentException, Throwable, Symfony\Component\HttpKernel\Exception.
  • Ramsey\Uuid et Symfony\Component\Messenger : autorisés uniquement en Application, pas en Domain.

Vérification : make phparkitect