fix(shared): harmonize delete exception contracts on Repository and ClientRepository (LSP)

This commit is contained in:
Jérémy Munsch 2026-08-20 09:48:10 +02:00
parent 2bbfc7fa08
commit c8a46bb9b3
Signed by: forge-joniko
GPG key ID: D7EFE2F5CB6CC0E4
6 changed files with 43 additions and 1 deletions

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Application\Security\Ports\Repositories;
use Application\Security\Exceptions\ClientNotFoundException;
use Application\Security\Models\Entities\Client;
use Application\Security\Models\ValueObjects\ClientIdentifier;
use Application\Security\Models\ValueObjects\ClientName;
@ -21,6 +22,9 @@ interface ClientRepository extends Repository
public function persist(Client $client): void;
/**
* @throws ClientNotFoundException
*/
public function delete(Client $client): void;
public function existsByName(ClientName $name): bool;

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Infra\Adapters\Repositories;
use Application\Security\Exceptions\ClientNotFoundException;
use Application\Security\Models\Entities\Client;
use Application\Security\Models\ValueObjects\ClientIdentifier;
use Application\Security\Models\ValueObjects\ClientName;
@ -113,7 +114,7 @@ final class ApiClientRepository implements ClientRepository
{
$deleted = ApiClient::query()->where('id', $client->id->value)->delete();
if ($deleted === 0) {
throw new \LogicException('Client not found');
throw ClientNotFoundException::forClient($client->id->value);
}
}

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Infra\Adapters\Repositories;
use Application\Security\Exceptions\ClientNotFoundException;
use Application\Security\Models\Entities\Client;
use Application\Security\Models\ValueObjects\ClientIdentifier;
use Application\Security\Models\ValueObjects\ClientName;
@ -47,6 +48,10 @@ final class InMemoryClientRepository implements ClientRepository
#[\Override]
public function delete(Client $client): void
{
if (! isset($this->clients[$client->id->value])) {
throw ClientNotFoundException::forClient($client->id->value);
}
unset($this->clients[$client->id->value]);
}

View file

@ -11,6 +11,8 @@ namespace Shared\DDD\Port;
* @method TEntity|null find(TId $id)
* @method void persist(TEntity $entity)
* @method void delete(TEntity $entity)
*
* @throws \Shared\DDD\Exception\NotFoundException
*/
interface Repository
{

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Tests\Integration\Infra\Adapters\Repositories;
use Application\Security\Exceptions\ClientNotFoundException;
use Application\Security\Models\Entities\Client;
use Application\Security\Models\ValueObjects\ClientIdentifier;
use Application\Security\Models\ValueObjects\ClientName;
@ -185,6 +186,24 @@ describe('ApiClientRepository Integration Tests', function (): void {
]);
});
it('throws ClientNotFoundException when deleting non-existent client', function (): void {
// GIVEN
$repository = new ApiClientRepository();
$client = Client::hydrate(
id: new ClientId(Uuid::uuid7()),
name: new ClientName('Non Existent'),
identifier: new ClientIdentifier('arcadia_id_' . str_repeat('z', 32)),
secret: new ClientSecret('arcadia_sec_' . str_repeat('z', 86)),
isActive: true,
createdAt: new DateTimeImmutable(),
updatedAt: new DateTimeImmutable(),
);
// WHEN & THEN
expect(fn () => $repository->delete($client))
->toThrow(ClientNotFoundException::class);
});
it('finds all clients with pagination', function (): void {
// GIVEN
$repository = new ApiClientRepository();

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Tests\Unit\Infra\Adapters\Repositories;
use Application\Security\Exceptions\ClientNotFoundException;
use Application\Security\Models\Entities\Client;
use Application\Security\Models\ValueObjects\ClientIdentifier;
use Application\Security\Models\ValueObjects\ClientName;
@ -63,6 +64,16 @@ describe('InMemoryClientRepository Unit Tests', function (): void {
->and($foundAfterDelete)->toBeNull();
});
it('throws ClientNotFoundException when deleting non-existent client', function (): void {
// GIVEN
$repository = new InMemoryClientRepository();
$client = createClient('arcadia_id_' . str_repeat('9', 32));
// WHEN & THEN
expect(fn () => $repository->delete($client))
->toThrow(ClientNotFoundException::class);
});
it('finds all clients with pagination', function (): void {
// GIVEN
$repository = new InMemoryClientRepository();