diff --git a/config/container.php b/config/container.php index a6a310c..5147e42 100644 --- a/config/container.php +++ b/config/container.php @@ -22,26 +22,26 @@ use App\Auth\PasswordResetRepositoryInterface; use App\Auth\Application\PasswordResetApplicationService; use App\Auth\PasswordResetServiceInterface; use App\Category\Application\CategoryApplicationService; -use App\Category\CategoryRepository; + use App\Category\CategoryRepositoryInterface; -use App\Category\CategoryService; + use App\Category\CategoryServiceInterface; use App\Category\Infrastructure\PdoCategoryRepository; use App\Media\Domain\MediaStorageInterface; use App\Media\Infrastructure\LocalMediaStorage; use App\Media\Infrastructure\PdoMediaRepository; -use App\Media\MediaRepository; + use App\Media\MediaRepositoryInterface; use App\Media\Application\MediaApplicationService; -use App\Media\MediaService; + use App\Media\MediaServiceInterface; use App\Post\Application\PostApplicationService; -use App\Post\PostRepository; + use App\Post\PostRepositoryInterface; -use App\Post\PostService; + use App\Post\PostServiceInterface; use App\Post\Infrastructure\PdoPostRepository; -use App\Post\RssController; +use App\Post\Http\RssController; use App\Shared\Config; use App\Shared\Extension\AppExtension; use App\Shared\Html\HtmlPurifierFactory; diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4807ebb..06aacf2 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -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 diff --git a/docs/GUIDE.md b/docs/GUIDE.md index e043e71..8be9bc5 100644 --- a/docs/GUIDE.md +++ b/docs/GUIDE.md @@ -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 diff --git a/src/Auth/AccountController.php b/src/Auth/AccountController.php deleted file mode 100644 index 2499277..0000000 --- a/src/Auth/AccountController.php +++ /dev/null @@ -1,12 +0,0 @@ -container->get(Twig::class); $twig->addExtension($this->container->get(AppExtension::class)); $twig->addExtension($this->container->get(SessionExtension::class)); - $twig->addExtension($this->container->get(PostExtension::class)); + $twig->addExtension($this->container->get(TwigPostExtension::class)); $this->app->add(TwigMiddleware::create($this->app, $twig)); diff --git a/src/Shared/Routes.php b/src/Shared/Routes.php index 524c899..837bfc3 100644 --- a/src/Shared/Routes.php +++ b/src/Shared/Routes.php @@ -3,17 +3,17 @@ declare(strict_types=1); namespace App\Shared; -use App\Auth\AccountController; +use App\Auth\Http\AccountController; use App\Auth\Middleware\AdminMiddleware; -use App\Auth\AuthController; +use App\Auth\Http\AuthController; use App\Auth\Middleware\AuthMiddleware; use App\Auth\Middleware\EditorMiddleware; -use App\Auth\PasswordResetController; -use App\Category\CategoryController; -use App\Media\MediaController; -use App\Post\PostController; -use App\Post\RssController; -use App\User\UserController; +use App\Auth\Http\PasswordResetController; +use App\Category\Http\CategoryController; +use App\Media\Http\MediaController; +use App\Post\Http\PostController; +use App\Post\Http\RssController; +use App\User\Http\UserController; use Slim\App; /** diff --git a/src/User/UserController.php b/src/User/UserController.php deleted file mode 100644 index 2a68ed5..0000000 --- a/src/User/UserController.php +++ /dev/null @@ -1,12 +0,0 @@ -