5.5 KiB
5.5 KiB
name, description, allowed-tools
| name | description | allowed-tools |
|---|---|---|
| hexagonal-arch | Architecture hexagonale du projet Mangarr — structure exacte des dossiers, règles d'import strictes par couche, nommage ports (interfaces) vs adapters (implémentations). Utiliser quand on crée un nouveau domaine, un nouveau fichier, ou qu'on vérifie les dépendances entre couches. | Read, Grep, Glob, Bash |
Architecture Hexagonale — Mangarr
Structure canonique d'un domaine
src/Domain/{DomainName}/
Domain/ ← NOYAU pur, 0 dépendance framework
Model/
{Aggregate}.php
ValueObject/
{VoName}.php
Event/
{SomethingHappened}.php
Exception/
{Something}Exception.php
Contract/ ← PORTS (interfaces only)
Repository/
{Name}RepositoryInterface.php
Service/
{Name}Interface.php
Client/
{Name}ClientInterface.php
Application/ ← Use cases, orchestre le Domain
Command/
{DoSomething}.php
CommandHandler/
{DoSomething}Handler.php
Query/
{GetSomething}.php
QueryHandler/
{GetSomething}Handler.php
Response/
{Something}Response.php
EventListener/
{SomethingHappened}EventListener.php
Infrastructure/ ← ADAPTERS (implémentations concrètes)
Persistence/
Repository/
{Name}Repository.php ← implémente Domain/Contract/Repository/
ApiPlatform/
Resource/
{FeatureName}Resource.php
State/
Processor/
{DoSomething}Processor.php
Provider/
{GetSomething}StateProvider.php
Dto/
{Name}.php
Service/
{ServiceName}.php ← implémente Domain/Contract/Service/
Client/
{ClientName}.php ← implémente Domain/Contract/Client/
CommandHandler/ ← handlers Symfony Messenger (wrappent l'Application)
Symfony{DoSomething}Handler.php
Domaines du projet
| Domaine | Responsabilité |
|---|---|
Manga |
Catalogue mangas, chapitres, métadonnées |
Scraping |
Téléchargement de chapitres depuis les sources |
Conversion |
Conversion de formats (CBR→CBZ, génération CBZ) |
Reader |
Lecture de chapitres |
Setting |
Configuration applicative |
Shared |
Contrats transverses (EventDispatcherInterface, MangaPathManagerInterface, etc.) |
Règles d'import strictes
Domain (noyau)
✅ Peut importer : son propre namespace uniquement
+ exceptions PHP standard
❌ Interdit : Symfony\*, Doctrine\*, Ramsey\Uuid, tout autre domaine
Application
✅ Peut importer : son propre Domain (App\Domain\{X}\Domain\*)
App\Domain\Shared\Domain\Contract\*
Symfony\Component\Messenger\*
Ramsey\Uuid\*
❌ Interdit : son propre Infrastructure (App\Domain\{X}\Infrastructure\*)
Doctrine\*, tout autre domaine
Infrastructure
✅ Peut importer : tout (Symfony, Doctrine, API Platform, etc.)
son Application et son Domain
❌ Convention : ne pas contenir de logique métier (déléguer à Application)
Ports vs Adapters — nommage
| Concept | Localisation | Suffixe | Exemple |
|---|---|---|---|
| Port | Domain/Contract/Repository/ |
Interface |
MangaRepositoryInterface |
| Port | Domain/Contract/Service/ |
Interface |
ImageProcessorInterface |
| Port | Domain/Contract/Client/ |
Interface |
MangadexClientInterface |
| Adapter | Infrastructure/Persistence/ |
Repository |
LegacyChapterRepository |
| Adapter | Infrastructure/Service/ |
(nom libre) | ImageProcessor |
| Adapter | Infrastructure/Client/ |
Client |
MangadexClient |
Le binding port → adapter se déclare dans config/services.yaml :
App\Domain\Manga\Domain\Contract\Repository\MangaRepositoryInterface:
alias: App\Domain\Manga\Infrastructure\Persistence\Repository\LegacyMangaRepository
Shared Domain
Les contrats transverses vivent dans src/Domain/Shared/Domain/Contract/ :
CommandInterface,QueryInterface,ResponseInterface— marqueursCommandHandlerInterface,QueryHandlerInterface— handlers génériquesEventDispatcherInterface— dispatch d'événements domainMangaPathManagerInterface— gestion des chemins de fichiersFileUploadInterface,NotificationInterface— services transverses
App\Domain\Shared ne dépend de personne (règle PHPArkitect).
Checklist avant de créer un fichier
- Dans quelle couche va ce fichier ? (Domain / Application / Infrastructure)
- Ce fichier va-t-il importer quelque chose d'interdit pour cette couche ?
- Si c'est une implémentation concrète → existe-t-il déjà une interface (port) dans
Domain/Contract/? - Si c'est une nouvelle interface → est-elle dans
Domain/Contract/et non dans Infrastructure ? - Le binding alias est-il déclaré dans
config/services.yaml?
Vérification automatique : make phparkitect