` pour * disposer de logins de test. * * Toute la logique (litteraux des roles, matrice, comptes demo) vit dans * RbacSeeder — cette commande n'en est que l'enveloppe CLI. */ #[AsCommand( name: 'app:seed-rbac', description: 'Seede les roles metier RBAC + la matrice § 2.7 (idempotent, non destructif).', )] final class SeedRbacCommand extends Command { /** Variable d'environnement de repli pour le mot de passe des comptes demo. */ private const string PASSWORD_ENV = 'RBAC_DEMO_PASSWORD'; public function __construct(private readonly RbacSeeder $seeder) { parent::__construct(); } protected function configure(): void { $this ->addOption( 'with-demo-users', null, InputOption::VALUE_NONE, 'Cree aussi un compte demo par role metier (recette/dev — JAMAIS en prod).', ) ->addOption( 'password', null, InputOption::VALUE_REQUIRED, 'Mot de passe des comptes demo (defaut : variable d\'env '.self::PASSWORD_ENV.'). Requis avec --with-demo-users.', ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); // 1. Roles metier + matrice § 2.7. attachMatrix() exige que les // permissions soient en base : sinon RbacSeedException porteuse de // l'invite a lancer `app:sync-permissions`. try { $createdRoles = $this->seeder->ensureRoles(); $addedLinks = $this->seeder->attachMatrix(); } catch (RbacSeedException $e) { $io->error($e->getMessage()); return Command::FAILURE; } $io->text(sprintf( 'Roles metier : %d cree(s), matrice § 2.7 : %d lien(s) ajoute(s).', count($createdRoles), $addedLinks, )); // 2. Comptes demo (optionnel, jamais en prod). if ((bool) $input->getOption('with-demo-users')) { $password = $this->resolveDemoPassword($input); if (null === $password) { $io->error(sprintf( '--with-demo-users exige un mot de passe : passe --password=<...> ou definis la variable d\'env %s. ' .'(Aucun mot de passe en dur cote serveur.)', self::PASSWORD_ENV, )); return Command::FAILURE; } try { $createdUsers = $this->seeder->ensureDemoUsers($password); } catch (RbacSeedException $e) { $io->error($e->getMessage()); return Command::FAILURE; } $io->text(sprintf( 'Comptes demo : %d cree(s)%s.', count($createdUsers), [] === $createdUsers ? '' : ' ['.implode(', ', $createdUsers).']', )); } $io->success('Seed RBAC metier termine (idempotent).'); return Command::SUCCESS; } /** * Resout le mot de passe demo : option `--password` prioritaire, sinon * variable d'environnement. Renvoie null si aucun n'est fourni (la commande * refuse alors --with-demo-users plutot que d'inventer un mot de passe). */ private function resolveDemoPassword(InputInterface $input): ?string { /** @var null|string $option */ $option = $input->getOption('password'); if (null !== $option && '' !== $option) { return $option; } $env = $_SERVER[self::PASSWORD_ENV] ?? $_ENV[self::PASSWORD_ENV] ?? getenv(self::PASSWORD_ENV); if (is_string($env) && '' !== $env) { return $env; } return null; } }