From 3b34d00872b047b978ca1623ffe1cc855f9dabdf Mon Sep 17 00:00:00 2001 From: Matthieu Date: Tue, 14 Apr 2026 16:40:44 +0200 Subject: [PATCH] feat(core) : RBAC Task 2 - repositories Permission et Role - PermissionRepositoryInterface avec findByCode et findAllCodes (pour le sync command et le futur PermissionVoter) - RoleRepositoryInterface avec findByCode - Implementations Doctrine alignees sur DoctrineUserRepository - Alias DI dans config/services.yaml - Rebranchement de repositoryClass sur les entites Permission et Role Ticket #343 - 2/7 : couche persistence RBAC. Co-Authored-By: Claude Opus 4.6 (1M context) --- config/services.yaml | 6 ++ src/Module/Core/Domain/Entity/Permission.php | 4 +- src/Module/Core/Domain/Entity/Role.php | 4 +- .../PermissionRepositoryInterface.php | 33 ++++++++++ .../Repository/RoleRepositoryInterface.php | 27 ++++++++ .../ApiPlatform/State/Provider/MeProvider.php | 3 +- .../Doctrine/DoctrinePermissionRepository.php | 62 +++++++++++++++++++ .../Doctrine/DoctrineRoleRepository.php | 45 ++++++++++++++ 8 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 src/Module/Core/Domain/Repository/PermissionRepositoryInterface.php create mode 100644 src/Module/Core/Domain/Repository/RoleRepositoryInterface.php create mode 100644 src/Module/Core/Infrastructure/Doctrine/DoctrinePermissionRepository.php create mode 100644 src/Module/Core/Infrastructure/Doctrine/DoctrineRoleRepository.php diff --git a/config/services.yaml b/config/services.yaml index 9690014..9457e91 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -16,5 +16,11 @@ services: App\: resource: '../src/' + App\Module\Core\Domain\Repository\PermissionRepositoryInterface: + alias: App\Module\Core\Infrastructure\Doctrine\DoctrinePermissionRepository + + App\Module\Core\Domain\Repository\RoleRepositoryInterface: + alias: App\Module\Core\Infrastructure\Doctrine\DoctrineRoleRepository + App\Module\Core\Domain\Repository\UserRepositoryInterface: alias: App\Module\Core\Infrastructure\Doctrine\DoctrineUserRepository diff --git a/src/Module/Core/Domain/Entity/Permission.php b/src/Module/Core/Domain/Entity/Permission.php index 19e5ff5..e5e92a0 100644 --- a/src/Module/Core/Domain/Entity/Permission.php +++ b/src/Module/Core/Domain/Entity/Permission.php @@ -4,11 +4,11 @@ declare(strict_types=1); namespace App\Module\Core\Domain\Entity; +use App\Module\Core\Infrastructure\Doctrine\DoctrinePermissionRepository; use Doctrine\ORM\Mapping as ORM; use InvalidArgumentException; -// TODO: brancher repositoryClass au ticket 343 partie 2 (Task 2). -#[ORM\Entity] +#[ORM\Entity(repositoryClass: DoctrinePermissionRepository::class)] #[ORM\Table(name: 'permission')] #[ORM\UniqueConstraint(name: 'uniq_permission_code', columns: ['code'])] #[ORM\Index(name: 'idx_permission_module', columns: ['module'])] diff --git a/src/Module/Core/Domain/Entity/Role.php b/src/Module/Core/Domain/Entity/Role.php index 3782a58..7583454 100644 --- a/src/Module/Core/Domain/Entity/Role.php +++ b/src/Module/Core/Domain/Entity/Role.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Module\Core\Domain\Entity; use App\Module\Core\Domain\Exception\SystemRoleDeletionException; +use App\Module\Core\Infrastructure\Doctrine\DoctrineRoleRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; @@ -17,8 +18,7 @@ use Doctrine\ORM\Mapping as ORM; * "personnalise" (cree par un administrateur). Seuls les roles personnalises * peuvent etre supprimes. */ -// TODO: brancher repositoryClass au ticket 343 partie 2 (Task 2). -#[ORM\Entity] +#[ORM\Entity(repositoryClass: DoctrineRoleRepository::class)] #[ORM\Table(name: '`role`')] #[ORM\UniqueConstraint(name: 'uniq_role_code', columns: ['code'])] #[ORM\Index(name: 'idx_role_is_system', columns: ['is_system'])] diff --git a/src/Module/Core/Domain/Repository/PermissionRepositoryInterface.php b/src/Module/Core/Domain/Repository/PermissionRepositoryInterface.php new file mode 100644 index 0000000..7464c93 --- /dev/null +++ b/src/Module/Core/Domain/Repository/PermissionRepositoryInterface.php @@ -0,0 +1,33 @@ + + */ + public function findAll(): array; + + /** + * @return array liste des codes connus, pour la commande de sync et le futur voter + */ + public function findAllCodes(): array; + + public function save(Permission $permission): void; +} diff --git a/src/Module/Core/Domain/Repository/RoleRepositoryInterface.php b/src/Module/Core/Domain/Repository/RoleRepositoryInterface.php new file mode 100644 index 0000000..c952d7d --- /dev/null +++ b/src/Module/Core/Domain/Repository/RoleRepositoryInterface.php @@ -0,0 +1,27 @@ + + */ + public function findAll(): array; + + public function save(Role $role): void; +} diff --git a/src/Module/Core/Infrastructure/ApiPlatform/State/Provider/MeProvider.php b/src/Module/Core/Infrastructure/ApiPlatform/State/Provider/MeProvider.php index 5359d7b..ea088c8 100644 --- a/src/Module/Core/Infrastructure/ApiPlatform/State/Provider/MeProvider.php +++ b/src/Module/Core/Infrastructure/ApiPlatform/State/Provider/MeProvider.php @@ -6,6 +6,7 @@ namespace App\Module\Core\Infrastructure\ApiPlatform\State\Provider; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProviderInterface; +use Symfony\Bundle\SecurityBundle\Security; /** * @implements ProviderInterface @@ -13,7 +14,7 @@ use ApiPlatform\State\ProviderInterface; class MeProvider implements ProviderInterface { public function __construct( - private readonly \Symfony\Bundle\SecurityBundle\Security $security, + private readonly Security $security, ) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object diff --git a/src/Module/Core/Infrastructure/Doctrine/DoctrinePermissionRepository.php b/src/Module/Core/Infrastructure/Doctrine/DoctrinePermissionRepository.php new file mode 100644 index 0000000..b62f2cb --- /dev/null +++ b/src/Module/Core/Infrastructure/Doctrine/DoctrinePermissionRepository.php @@ -0,0 +1,62 @@ + + */ +class DoctrinePermissionRepository extends ServiceEntityRepository implements PermissionRepositoryInterface +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Permission::class); + } + + public function findById(int $id): ?Permission + { + return $this->find($id); + } + + public function findByCode(string $code): ?Permission + { + return $this->findOneBy(['code' => $code]); + } + + /** + * @return array + */ + public function findAll(): array + { + return parent::findAll(); + } + + /** + * @return array + */ + public function findAllCodes(): array + { + // Requete legere : on ne selectionne que la colonne code (pas d'hydratation + // d'entites Permission) car findAllCodes() est appelee par la commande de + // sync et le futur voter qui n'ont besoin que des chaines. + $rows = $this->createQueryBuilder('p') + ->select('p.code') + ->getQuery() + ->getArrayResult() + ; + + return array_column($rows, 'code'); + } + + public function save(Permission $permission): void + { + $this->getEntityManager()->persist($permission); + $this->getEntityManager()->flush(); + } +} diff --git a/src/Module/Core/Infrastructure/Doctrine/DoctrineRoleRepository.php b/src/Module/Core/Infrastructure/Doctrine/DoctrineRoleRepository.php new file mode 100644 index 0000000..7667440 --- /dev/null +++ b/src/Module/Core/Infrastructure/Doctrine/DoctrineRoleRepository.php @@ -0,0 +1,45 @@ + + */ +class DoctrineRoleRepository extends ServiceEntityRepository implements RoleRepositoryInterface +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Role::class); + } + + public function findById(int $id): ?Role + { + return $this->find($id); + } + + public function findByCode(string $code): ?Role + { + return $this->findOneBy(['code' => $code]); + } + + /** + * @return array + */ + public function findAll(): array + { + return parent::findAll(); + } + + public function save(Role $role): void + { + $this->getEntityManager()->persist($role); + $this->getEntityManager()->flush(); + } +}