From 15a0ff55a38a7eb4df11a6df5bf0376e42373660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 20 Aug 2026 10:02:17 +0200 Subject: [PATCH] refactor(security): segregate ClientDirectory and ClientRepository ports (ISP) --- .../Ports/Directories/ClientDirectory.php | 25 +++++++++++++++++++ .../Ports/Repositories/ClientRepository.php | 16 +++--------- .../FindAllClients/FindAllClients.php | 6 ++--- .../Usecases/FindClient/FindClient.php | 6 ++--- .../Repositories/ApiClientRepository.php | 3 ++- .../Repositories/InMemoryClientRepository.php | 3 ++- .../Providers/SecurityServiceProvider.php | 2 ++ .../Services/ClientConsoleResolver.php | 6 +++-- 8 files changed, 45 insertions(+), 22 deletions(-) create mode 100644 src/Application/Security/Ports/Directories/ClientDirectory.php diff --git a/src/Application/Security/Ports/Directories/ClientDirectory.php b/src/Application/Security/Ports/Directories/ClientDirectory.php new file mode 100644 index 0000000..68119cf --- /dev/null +++ b/src/Application/Security/Ports/Directories/ClientDirectory.php @@ -0,0 +1,25 @@ + + */ +interface ClientDirectory extends Directory +{ + public function find(ClientId $id): ?Client; + + /** @return Paginated */ + public function search(string $query, Pagination $pagination): Paginated; + + /** @return Paginated */ + public function findAll(Pagination $pagination): Paginated; +} diff --git a/src/Application/Security/Ports/Repositories/ClientRepository.php b/src/Application/Security/Ports/Repositories/ClientRepository.php index 863ebe9..4a2f03d 100644 --- a/src/Application/Security/Ports/Repositories/ClientRepository.php +++ b/src/Application/Security/Ports/Repositories/ClientRepository.php @@ -10,8 +10,6 @@ use Application\Security\Models\ValueObjects\ClientIdentifier; use Application\Security\Models\ValueObjects\ClientName; use Application\Security\Models\ValueObjects\Entities\ClientId; use Shared\DDD\Port\Repository; -use Shared\Paginated; -use Shared\Pagination; /** * @extends Repository @@ -20,20 +18,14 @@ interface ClientRepository extends Repository { public function find(ClientId $id): ?Client; + public function findByIdentifier(ClientIdentifier $identifier): ?Client; + + public function existsByName(ClientName $name): bool; + public function persist(Client $client): void; /** * @throws ClientNotFoundException */ public function delete(Client $client): void; - - public function existsByName(ClientName $name): bool; - - public function findByIdentifier(ClientIdentifier $identifier): ?Client; - - /** @return Paginated */ - public function search(string $query, Pagination $pagination): Paginated; - - /** @return Paginated */ - public function findAll(Pagination $pagination): Paginated; } diff --git a/src/Application/Security/Usecases/FindAllClients/FindAllClients.php b/src/Application/Security/Usecases/FindAllClients/FindAllClients.php index d72517c..0525364 100644 --- a/src/Application/Security/Usecases/FindAllClients/FindAllClients.php +++ b/src/Application/Security/Usecases/FindAllClients/FindAllClients.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Application\Security\Usecases\FindAllClients; use Application\Security\Models\Entities\Client; -use Application\Security\Ports\Repositories\ClientRepository; +use Application\Security\Ports\Directories\ClientDirectory; use Shared\DDD\Usecase\Input as BaseInput; use Shared\DDD\Usecase\Usecase; use Shared\Paginated; @@ -15,7 +15,7 @@ use Webmozart\Assert\Assert; final readonly class FindAllClients implements Usecase { public function __construct( - private ClientRepository $repository, + private ClientDirectory $directory, ) { } @@ -24,7 +24,7 @@ final readonly class FindAllClients implements Usecase { Assert::isInstanceOf($input, Input::class); - $page = $this->repository->findAll($input->pagination); + $page = $this->directory->findAll($input->pagination); return $this->toOutput($page); } diff --git a/src/Application/Security/Usecases/FindClient/FindClient.php b/src/Application/Security/Usecases/FindClient/FindClient.php index 491ae09..0ac0cf9 100644 --- a/src/Application/Security/Usecases/FindClient/FindClient.php +++ b/src/Application/Security/Usecases/FindClient/FindClient.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Application\Security\Usecases\FindClient; -use Application\Security\Ports\Repositories\ClientRepository; +use Application\Security\Ports\Directories\ClientDirectory; use Shared\DDD\Usecase\Input as BaseInput; use Shared\DDD\Usecase\Usecase; use Shared\Pagination; @@ -14,7 +14,7 @@ use Webmozart\Assert\Assert; final readonly class FindClient implements Usecase { public function __construct( - private ClientRepository $clientRepository, + private ClientDirectory $clientDirectory, ) { } @@ -24,7 +24,7 @@ final readonly class FindClient implements Usecase Assert::isInstanceOf($input, Input::class); $pagination = $input->pagination ?? Pagination::ofOffsetAndLimit(0, 20); - $paginated = $this->clientRepository->search($input->query, $pagination); + $paginated = $this->clientDirectory->search($input->query, $pagination); return new Output($paginated); } diff --git a/src/Infra/Adapters/Repositories/ApiClientRepository.php b/src/Infra/Adapters/Repositories/ApiClientRepository.php index 22c4c7f..c146490 100644 --- a/src/Infra/Adapters/Repositories/ApiClientRepository.php +++ b/src/Infra/Adapters/Repositories/ApiClientRepository.php @@ -9,13 +9,14 @@ use Application\Security\Models\Entities\Client; use Application\Security\Models\ValueObjects\ClientIdentifier; use Application\Security\Models\ValueObjects\ClientName; use Application\Security\Models\ValueObjects\Entities\ClientId; +use Application\Security\Ports\Directories\ClientDirectory; use Application\Security\Ports\Repositories\ClientRepository; use Illuminate\Support\Str; use Infra\Database\Models\ApiClient; use Shared\Paginated; use Shared\Pagination; -final class ApiClientRepository implements ClientRepository +final class ApiClientRepository implements ClientDirectory, ClientRepository { #[\Override] public function persist(Client $client): void diff --git a/src/Infra/Adapters/Repositories/InMemoryClientRepository.php b/src/Infra/Adapters/Repositories/InMemoryClientRepository.php index efc9d80..5f38677 100644 --- a/src/Infra/Adapters/Repositories/InMemoryClientRepository.php +++ b/src/Infra/Adapters/Repositories/InMemoryClientRepository.php @@ -9,12 +9,13 @@ use Application\Security\Models\Entities\Client; use Application\Security\Models\ValueObjects\ClientIdentifier; use Application\Security\Models\ValueObjects\ClientName; use Application\Security\Models\ValueObjects\Entities\ClientId; +use Application\Security\Ports\Directories\ClientDirectory; use Application\Security\Ports\Repositories\ClientRepository; use Illuminate\Support\Str; use Shared\Paginated; use Shared\Pagination; -final class InMemoryClientRepository implements ClientRepository +final class InMemoryClientRepository implements ClientDirectory, ClientRepository { /** @var array */ private array $clients = []; diff --git a/src/Infra/Providers/SecurityServiceProvider.php b/src/Infra/Providers/SecurityServiceProvider.php index 85a1337..3f9ef42 100644 --- a/src/Infra/Providers/SecurityServiceProvider.php +++ b/src/Infra/Providers/SecurityServiceProvider.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Infra\Providers; +use Application\Security\Ports\Directories\ClientDirectory; use Application\Security\Ports\Repositories\ClientRepository; use Application\Security\Ports\Services\ClientCredentialGenerator; use Application\Security\Ports\Services\HmacSignatureValidator; @@ -32,6 +33,7 @@ final class SecurityServiceProvider extends ServiceProvider { $this->app->bind(ClientCredentialGenerator::class, ClientCredentialGeneratorImpl::class); $this->app->bind(ClientRepository::class, ApiClientRepository::class); + $this->app->bind(ClientDirectory::class, ApiClientRepository::class); $this->app->bind(HmacSignatureValidator::class, HmacSignatureValidatorImpl::class); $this->app->bind(NonceValidator::class, function (Application $app): CachedNonceValidator { diff --git a/src/Presentation/Console/Services/ClientConsoleResolver.php b/src/Presentation/Console/Services/ClientConsoleResolver.php index 0d5cd79..be6e41a 100644 --- a/src/Presentation/Console/Services/ClientConsoleResolver.php +++ b/src/Presentation/Console/Services/ClientConsoleResolver.php @@ -7,6 +7,7 @@ namespace Presentation\Console\Services; use Application\Security\Models\Entities\Client; use Application\Security\Models\ValueObjects\ClientIdentifier; use Application\Security\Models\ValueObjects\Entities\ClientId; +use Application\Security\Ports\Directories\ClientDirectory; use Application\Security\Ports\Repositories\ClientRepository; use Application\Security\Usecases\FindClient\FindClient; use Application\Security\Usecases\FindClient\Input as FindClientInput; @@ -22,6 +23,7 @@ final readonly class ClientConsoleResolver { public function __construct( private ClientRepository $clientRepository, + private ClientDirectory $clientDirectory, private FindClient $findClient, private UsecaseExecutor $executor, ) { @@ -32,7 +34,7 @@ final readonly class ClientConsoleResolver */ public function complete(CompletionSuggestions $suggestions): void { - $clients = $this->clientRepository->findAll(Pagination::ofOffsetAndLimit(0, 100)); + $clients = $this->clientDirectory->findAll(Pagination::ofOffsetAndLimit(0, 100)); /** @var list $items */ $items = array_map( @@ -56,7 +58,7 @@ final readonly class ClientConsoleResolver $trimmed = trim($value); if ($trimmed === '') { - $clients = $this->clientRepository->findAll(Pagination::ofOffsetAndLimit(0, 10)); + $clients = $this->clientDirectory->findAll(Pagination::ofOffsetAndLimit(0, 10)); $options = []; foreach ($clients->getItems() as $client) { $options[$client->identifier->value] = sprintf(