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) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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'])]
|
||||
|
||||
@@ -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'])]
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Domain\Repository;
|
||||
|
||||
use App\Module\Core\Domain\Entity\Permission;
|
||||
|
||||
/**
|
||||
* Contrat du catalogue de permissions RBAC.
|
||||
*
|
||||
* Utilise par la commande de synchronisation (app:sync-permissions), les
|
||||
* fixtures, et — a terme (ticket #345) — par le PermissionVoter pour valider
|
||||
* que les codes verifies existent bien dans le catalogue.
|
||||
*/
|
||||
interface PermissionRepositoryInterface
|
||||
{
|
||||
public function findById(int $id): ?Permission;
|
||||
|
||||
public function findByCode(string $code): ?Permission;
|
||||
|
||||
/**
|
||||
* @return array<int, Permission>
|
||||
*/
|
||||
public function findAll(): array;
|
||||
|
||||
/**
|
||||
* @return array<int, string> liste des codes connus, pour la commande de sync et le futur voter
|
||||
*/
|
||||
public function findAllCodes(): array;
|
||||
|
||||
public function save(Permission $permission): void;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Domain\Repository;
|
||||
|
||||
use App\Module\Core\Domain\Entity\Role;
|
||||
|
||||
/**
|
||||
* Contrat des roles RBAC.
|
||||
*
|
||||
* Utilise par les fixtures, la future API d'administration (ticket #344) et
|
||||
* le PermissionVoter pour resoudre les permissions effectives d'un role.
|
||||
*/
|
||||
interface RoleRepositoryInterface
|
||||
{
|
||||
public function findById(int $id): ?Role;
|
||||
|
||||
public function findByCode(string $code): ?Role;
|
||||
|
||||
/**
|
||||
* @return array<int, Role>
|
||||
*/
|
||||
public function findAll(): array;
|
||||
|
||||
public function save(Role $role): void;
|
||||
}
|
||||
@@ -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<object>
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Infrastructure\Doctrine;
|
||||
|
||||
use App\Module\Core\Domain\Entity\Permission;
|
||||
use App\Module\Core\Domain\Repository\PermissionRepositoryInterface;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Permission>
|
||||
*/
|
||||
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<int, Permission>
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
return parent::findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Infrastructure\Doctrine;
|
||||
|
||||
use App\Module\Core\Domain\Entity\Role;
|
||||
use App\Module\Core\Domain\Repository\RoleRepositoryInterface;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Role>
|
||||
*/
|
||||
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<int, Role>
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
return parent::findAll();
|
||||
}
|
||||
|
||||
public function save(Role $role): void
|
||||
{
|
||||
$this->getEntityManager()->persist($role);
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user