diff --git a/src/Module/Core/Infrastructure/Console/CreateUserCommand.php b/src/Module/Core/Infrastructure/Console/CreateUserCommand.php index 7133adc..f13afeb 100644 --- a/src/Module/Core/Infrastructure/Console/CreateUserCommand.php +++ b/src/Module/Core/Infrastructure/Console/CreateUserCommand.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace App\Module\Core\Infrastructure\Console; use App\Module\Core\Domain\Entity\User; +use App\Module\Core\Domain\Repository\RoleRepositoryInterface; use App\Module\Core\Domain\Repository\UserRepositoryInterface; +use App\Module\Core\Domain\Security\SystemRoles; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -17,13 +19,14 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; #[AsCommand( name: 'app:create-user', - description: 'Create a new user', + description: 'Cree un utilisateur rattache au role systeme admin ou user.', )] -class CreateUserCommand extends Command +final class CreateUserCommand extends Command { public function __construct( private readonly UserRepositoryInterface $userRepository, private readonly UserPasswordHasherInterface $passwordHasher, + private readonly RoleRepositoryInterface $roleRepository, ) { parent::__construct(); } @@ -31,9 +34,9 @@ class CreateUserCommand extends Command protected function configure(): void { $this - ->addArgument('username', InputArgument::REQUIRED, 'Username') - ->addArgument('password', InputArgument::REQUIRED, 'Plain password') - ->addOption('admin', null, InputOption::VALUE_NONE, 'Grant ROLE_ADMIN') + ->addArgument('username', InputArgument::REQUIRED, 'Nom d\'utilisateur') + ->addArgument('password', InputArgument::REQUIRED, 'Mot de passe en clair') + ->addOption('admin', null, InputOption::VALUE_NONE, 'Rattache au role systeme admin + active is_admin') ; } @@ -43,19 +46,34 @@ class CreateUserCommand extends Command $username = $input->getArgument('username'); $plainPassword = $input->getArgument('password'); + $isAdmin = (bool) $input->getOption('admin'); + + $roleCode = $isAdmin ? SystemRoles::ADMIN_CODE : SystemRoles::USER_CODE; + $role = $this->roleRepository->findByCode($roleCode); + + if (null === $role) { + $io->error(sprintf( + 'Le role systeme "%s" est introuvable. Lance "bin/console doctrine:migrations:migrate" pour le seeder.', + $roleCode, + )); + + return Command::FAILURE; + } $user = new User(); $user->setUsername($username); $user->setPassword($this->passwordHasher->hashPassword($user, $plainPassword)); - - if ($input->getOption('admin')) { - // TODO Task 6 : attacher l'entite Role "admin" en plus du flag is_admin. - $user->setIsAdmin(true); - } + $user->setIsAdmin($isAdmin); + $user->addRbacRole($role); $this->userRepository->save($user); - $io->success(sprintf('User "%s" created%s.', $username, $input->getOption('admin') ? ' with ROLE_ADMIN' : '')); + $io->success(sprintf( + 'Utilisateur "%s" cree, rattache au role systeme "%s"%s.', + $username, + $roleCode, + $isAdmin ? ' (bypass is_admin actif)' : '', + )); return Command::SUCCESS; } diff --git a/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php b/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php index 0ba45fa..bde7cc8 100644 --- a/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php +++ b/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php @@ -4,36 +4,72 @@ declare(strict_types=1); namespace App\Module\Core\Infrastructure\DataFixtures; +use App\Module\Core\Domain\Entity\Role; use App\Module\Core\Domain\Entity\User; +use App\Module\Core\Domain\Repository\RoleRepositoryInterface; +use App\Module\Core\Domain\Security\SystemRoles; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; +/** + * Fixtures de base du module Core : 3 utilisateurs (1 admin + 2 standards) + * rattaches aux roles systeme RBAC seedes par la migration Version20260414150034. + * + * Note : le purger Doctrine execute avant load() supprime l'ensemble des + * entites managees, ce qui inclut la table role. On re-seede donc les roles + * systeme de maniere idempotente avant de rattacher les utilisateurs, afin + * que le workflow "make db-reset && make fixtures" reste one-shot. + */ class AppFixtures extends Fixture { public function __construct( private readonly UserPasswordHasherInterface $passwordHasher, + private readonly RoleRepositoryInterface $roleRepository, ) {} public function load(ObjectManager $manager): void { - // TODO Task 6 : cette fixture sera refactoree pour attacher les entites Role RBAC. + $adminRole = $this->ensureSystemRole($manager, SystemRoles::ADMIN_CODE, 'Administrateur'); + $userRole = $this->ensureSystemRole($manager, SystemRoles::USER_CODE, 'Utilisateur'); + $admin = new User(); $admin->setUsername('admin'); $admin->setIsAdmin(true); $admin->setPassword($this->passwordHasher->hashPassword($admin, 'admin')); + $admin->addRbacRole($adminRole); $manager->persist($admin); $alice = new User(); $alice->setUsername('alice'); $alice->setPassword($this->passwordHasher->hashPassword($alice, 'alice')); + $alice->addRbacRole($userRole); $manager->persist($alice); $bob = new User(); $bob->setUsername('bob'); $bob->setPassword($this->passwordHasher->hashPassword($bob, 'bob')); + $bob->addRbacRole($userRole); $manager->persist($bob); $manager->flush(); } + + /** + * Retourne le role systeme correspondant au code donne, en le creant + * s'il n'existe pas encore (le purger Doctrine a pu vider la table role). + */ + private function ensureSystemRole(ObjectManager $manager, string $code, string $label): Role + { + $role = $this->roleRepository->findByCode($code); + + if (null !== $role) { + return $role; + } + + $role = new Role($code, $label, isSystem: true); + $manager->persist($role); + + return $role; + } }