Refatoring : Working state

This commit is contained in:
julien
2026-03-16 15:08:48 +01:00
parent 664d74cd69
commit 3ad3c3d0b7
50 changed files with 69 additions and 331 deletions

View File

@@ -1,12 +1,12 @@
# Architecture
> **Refactor DDD légère — lots 1 à 4**
> **Architecture cible après cleanup final**
>
> `Post/`, `Category/`, `User/`, `Media/` et `Auth/` introduisent maintenant une organisation verticale
> `Application / Infrastructure / Http / Domain` pour alléger la lecture et préparer
> un découpage plus fin par cas d'usage. Les classes historiques à la racine du domaine
> sont conservées comme **ponts de compatibilité** afin de préserver les routes, le conteneur
> DI et la suite de tests pendant la transition.
> `Post/`, `Category/`, `User/`, `Media/` et `Auth/` suivent maintenant une organisation verticale
> `Application / Infrastructure / Http / Domain`. Les anciennes classes de transition
> ont été retirées : routes, conteneur DI et tests pointent directement vers les
> implémentations finales, ce qui réduit la dette de compatibilité tout en conservant
> les mêmes fonctionnalités.
## Domaines PHP
@@ -27,13 +27,13 @@ contrôleur. Les dépendances inter-domaines sont explicites, minimales et toujo
Le projet compte deux dépendances explicites entre domaines métier :
**`Auth/ → User/`** — `AuthService` et `PasswordResetService` consomment `UserRepositoryInterface`
**`Auth/ → User/`** — `AuthApplicationService` et `PasswordResetApplicationService` consomment `UserRepositoryInterface`
pour lire les comptes lors de l'authentification et de la réinitialisation de mot de passe.
Unidirectionnelle : `User/` n'importe rien de `Auth/`.
**`Post/ → Category/`** — `PostController` injecte `CategoryServiceInterface` pour alimenter
la liste des catégories dans le formulaire de création/édition d'article. Dépendance de
présentation uniquement : `PostService` et `PostRepository` ne connaissent pas `Category/`.
présentation uniquement : `PostApplicationService` et `PdoPostRepository` ne connaissent pas `Category/`.
Unidirectionnelle : `Category/` n'importe rien de `Post/`.
### Structure d'un domaine
@@ -89,10 +89,10 @@ final class PostService
| `PasswordResetRepositoryInterface` | `PdoPasswordResetRepository` | `Auth/` |
| `PasswordResetServiceInterface` | `PasswordResetApplicationService` | `Auth/` |
| `AuthServiceInterface` | `AuthApplicationService` | `Auth/` |
| `PostRepositoryInterface` | `PostRepository` | `Post/` |
| `PostServiceInterface` | `PostService` | `Post/` |
| `CategoryRepositoryInterface` | `CategoryRepository` | `Category/`|
| `CategoryServiceInterface` | `CategoryService` | `Category/`|
| `PostRepositoryInterface` | `PdoPostRepository` | `Post/` |
| `PostServiceInterface` | `PostApplicationService` | `Post/` |
| `CategoryRepositoryInterface` | `PdoCategoryRepository` | `Category/`|
| `CategoryServiceInterface` | `CategoryApplicationService` | `Category/`|
| `MediaRepositoryInterface` | `PdoMediaRepository` | `Media/` |
| `MediaServiceInterface` | `MediaApplicationService` | `Media/` |
| `MediaStorageInterface` | `LocalMediaStorage` | `Media/` |
@@ -106,13 +106,13 @@ Les erreurs métier levées intentionnellement utilisent des exceptions dédiée
| Exception | Namespace | Levée par |
|------------------------------|------------------------|--------------------------------------------------------|
| `DuplicateUsernameException` | `App\User\Exception` | `UserService::createUser()` |
| `DuplicateEmailException` | `App\User\Exception` | `UserService::createUser()` |
| `WeakPasswordException` | `App\User\Exception` | `UserService`, `AuthService`, `PasswordResetService` |
| `NotFoundException` | `App\Shared\Exception` | `PostService`, `AuthService` |
| `FileTooLargeException` | `App\Media\Exception` | `MediaService::store()` |
| `InvalidMimeTypeException` | `App\Media\Exception` | `MediaService::store()` |
| `StorageException` | `App\Media\Exception` | `MediaService::store()` |
| `DuplicateUsernameException` | `App\User\Exception` | `UserApplicationService::createUser()` |
| `DuplicateEmailException` | `App\User\Exception` | `UserApplicationService::createUser()` |
| `WeakPasswordException` | `App\User\Exception` | `UserApplicationService`, `AuthApplicationService`, `PasswordResetApplicationService` |
| `NotFoundException` | `App\Shared\Exception` | `PostApplicationService`, `AuthApplicationService` |
| `FileTooLargeException` | `App\Media\Exception` | `MediaApplicationService::store()` |
| `InvalidMimeTypeException` | `App\Media\Exception` | `MediaApplicationService::store()` |
| `StorageException` | `App\Media\Exception` | `MediaApplicationService::store()` |
## Base de données

View File

@@ -429,8 +429,8 @@ Qui assemble les dépendances ? PHP-DI dans `config/container.php`. Il résout a
// Extrait de config/container.php
// Binding interface → implémentation : PHP-DI injecte PostRepository partout où
// PostRepositoryInterface est demandé. PostService lui-même est résolu par autowiring.
PostRepositoryInterface::class => autowire(PostRepository::class),
PostServiceInterface::class => autowire(PostService::class),
PostRepositoryInterface::class => autowire(PdoPostRepository::class),
PostServiceInterface::class => autowire(PostApplicationService::class),
```
> 💡 Pour ajouter un nouveau service : créer la classe avec ses dépendances typées en constructeur, puis déclarer le binding interface → classe dans `config/container.php`. Si toutes les dépendances sont elles-mêmes typées sur des interfaces déjà liées, PHP-DI résout tout automatiquement — aucune factory à écrire.
@@ -873,8 +873,8 @@ Les services dépendent des interfaces, jamais des classes concrètes. Cela appo
```php
// config/container.php
PostRepositoryInterface::class => autowire(PostRepository::class),
PostServiceInterface::class => autowire(PostService::class),
PostRepositoryInterface::class => autowire(PdoPostRepository::class),
PostServiceInterface::class => autowire(PostApplicationService::class),
```
**Factories scalaires** — pour les dépendances qui ont besoin de paramètres issus de `.env` ou du système de fichiers (PDO, Twig, Monolog) :
@@ -979,7 +979,7 @@ DuplicateEmailException — adresse e-mail déjà utilisée
WeakPasswordException — mot de passe inférieur à 8 caractères
```
Elles sont levées par `UserService` (`DuplicateUsernameException`, `DuplicateEmailException`, `WeakPasswordException`) et par `AuthService` et `PasswordResetService` (`WeakPasswordException`), puis attrapées dans les contrôleurs via un seul bloc `catch(\InvalidArgumentException)` : le message de l'exception est transmis directement au flash et affiché dans le formulaire.
Elles sont levées par `UserService` (`DuplicateUsernameException`, `DuplicateEmailException`, `WeakPasswordException`) et par `AuthApplicationService` et `PasswordResetApplicationService` (`WeakPasswordException`), puis attrapées dans les contrôleurs via un seul bloc `catch(\InvalidArgumentException)` : le message de l'exception est transmis directement au flash et affiché dans le formulaire.
### 5.9 Gestion des erreurs et messages flash