65 lines
2.3 KiB
PHP
65 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Module\Core\Domain\Security;
|
|
|
|
use App\Module\Core\Domain\Entity\User;
|
|
use App\Module\Core\Domain\Exception\LastAdminProtectionException;
|
|
use App\Module\Core\Domain\Repository\UserRepositoryInterface;
|
|
|
|
/**
|
|
* Gardien de l'invariant domaine : l'instance doit toujours conserver
|
|
* au moins un utilisateur administrateur.
|
|
*
|
|
* Ce service est appele avant toute operation susceptible de reduire le
|
|
* nombre d'admins (retrait du flag isAdmin, suppression d'un utilisateur).
|
|
* Il compte les admins restants et leve LastAdminProtectionException si
|
|
* le seuil minimum (1) serait franchi.
|
|
*/
|
|
final class AdminHeadcountGuard
|
|
{
|
|
public function __construct(private readonly UserRepositoryInterface $userRepository) {}
|
|
|
|
/**
|
|
* Verifie qu'il restera au moins un admin apres la demote de $user.
|
|
*
|
|
* L'argument $user est accepte mais non utilise dans la logique de comptage :
|
|
* l'appelant a deja determine que cet utilisateur va perdre son statut admin ;
|
|
* le garde se contente de verifier qu'il en reste au moins un autre.
|
|
* Le parametre est conserve pour la lisibilite du site d'appel et pour
|
|
* permettre une evolution future (ex : journalisation, audit trail).
|
|
*/
|
|
public function ensureAtLeastOneAdminRemainsAfterDemotion(User $user): void
|
|
{
|
|
$this->checkAdminHeadcount();
|
|
}
|
|
|
|
/**
|
|
* Verifie qu'il restera au moins un admin apres la suppression de $user.
|
|
*
|
|
* Meme principe que ensureAtLeastOneAdminRemainsAfterDemotion() : $user
|
|
* est accepte pour la symetrie du contrat et les evolutions futures,
|
|
* mais le comptage ne depend pas de son identite.
|
|
*/
|
|
public function ensureAtLeastOneAdminRemainsAfterDeletion(User $user): void
|
|
{
|
|
$this->checkAdminHeadcount();
|
|
}
|
|
|
|
/**
|
|
* Compte les administrateurs et leve une exception si le seuil minimum est atteint.
|
|
*
|
|
* La verification est volontairement conservative (<=1) pour couvrir
|
|
* le cas defensif ou la base serait deja dans un etat incoherent (0 admin).
|
|
*
|
|
* @throws LastAdminProtectionException si le nombre d'admins est inferieur ou egal a 1
|
|
*/
|
|
private function checkAdminHeadcount(): void
|
|
{
|
|
if ($this->userRepository->countAdmins() <= 1) {
|
|
throw new LastAdminProtectionException();
|
|
}
|
|
}
|
|
}
|