From 389046563894f01a61abf8f5ae780e6a58d908c4 Mon Sep 17 00:00:00 2001 From: eltharin Date: Tue, 17 Sep 2024 11:09:37 +0200 Subject: [PATCH] allow security:form-login non interractive --- src/Maker/Common/CanGenerateTestsTrait.php | 1 + src/Maker/Security/MakeFormLogin.php | 62 ++++++++++++++-------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/Maker/Common/CanGenerateTestsTrait.php b/src/Maker/Common/CanGenerateTestsTrait.php index 18d7566af..3ea57d014 100644 --- a/src/Maker/Common/CanGenerateTestsTrait.php +++ b/src/Maker/Common/CanGenerateTestsTrait.php @@ -50,6 +50,7 @@ public function interactSetGenerateTests(InputInterface $input, ConsoleStyle $io if (!$this->generateTests) { $this->generateTests = $io->confirm('Do you want to generate PHPUnit tests? [Experimental]', false); + $input->setOption('with-tests', $this->generateTests); } } diff --git a/src/Maker/Security/MakeFormLogin.php b/src/Maker/Security/MakeFormLogin.php index 8ae6e012e..66ad92152 100644 --- a/src/Maker/Security/MakeFormLogin.php +++ b/src/Maker/Security/MakeFormLogin.php @@ -35,7 +35,9 @@ use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\TwigBundle\TwigBundle; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Attribute\Route; @@ -57,11 +59,10 @@ final class MakeFormLogin extends AbstractMaker private const SECURITY_CONFIG_PATH = 'config/packages/security.yaml'; private YamlSourceManipulator $ysm; - private string $controllerName; private string $firewallToUpdate; private string $userClass; private string $userNameField; - private bool $willLogout; + private ?array $securityData = null; public function __construct( private FileManager $fileManager, @@ -77,9 +78,12 @@ public static function getCommandName(): string public function configureCommand(Command $command, InputConfiguration $inputConfig): void { - $command->setHelp(file_get_contents(\dirname(__DIR__, 2).'/Resources/help/security/MakeFormLogin.txt')); + $command->addArgument('controllerName', InputArgument::OPTIONAL, 'The class name of the Controller (e.g. SecurityController)') + ->addOption('will-logout', null, InputOption::VALUE_NONE, 'Will generate a \'/logout\' URL? ') + ->setHelp(file_get_contents(\dirname(__DIR__, 2).'/Resources/help/security/MakeFormLogin.txt')); $this->configureCommandWithTestsOption($command); + $inputConfig->setArgumentAsNonInteractive('controllerName'); } public static function getCommandDescription(): string @@ -111,30 +115,36 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma throw new RuntimeCommandException(\sprintf('The file "%s" does not exist. PHP & XML configuration formats are currently not supported.', self::SECURITY_CONFIG_PATH)); } - $this->ysm = new YamlSourceManipulator($this->fileManager->getFileContents(self::SECURITY_CONFIG_PATH)); - $securityData = $this->ysm->getData(); + $securityData = $this->getSecurityData(); if (!isset($securityData['security']['providers']) || !$securityData['security']['providers']) { throw new RuntimeCommandException('To generate a form login authentication, you must configure at least one entry under "providers" in "security.yaml".'); } - $this->controllerName = $io->ask( - 'Choose a name for the controller class (e.g. SecurityController)', - 'SecurityController', - Validator::validateClassName(...) - ); + if (null === $input->getArgument('controllerName')) { + $input->setArgument( + 'controllerName', $input->getArgument('controllerName') ?? $io->ask( + 'Choose a name for the controller class (e.g. SecurityController)', + 'SecurityController', + Validator::validateClassName(...) + )); + } - $securityHelper = new InteractiveSecurityHelper(); - $this->firewallToUpdate = $securityHelper->guessFirewallName($io, $securityData); - $this->userClass = $securityHelper->guessUserClass($io, $securityData['security']['providers']); - $this->userNameField = $securityHelper->guessUserNameField($io, $this->userClass, $securityData['security']['providers']); - $this->willLogout = $io->confirm('Do you want to generate a \'/logout\' URL?'); + if (false === $input->getOption('will-logout')) { + $input->setOption('will-logout',$io->confirm('Do you want to generate a \'/logout\' URL?')); + } $this->interactSetGenerateTests($input, $io); } public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void { + $securityData = $this->getSecurityData(); + $securityHelper = new InteractiveSecurityHelper(); + $this->firewallToUpdate = $securityHelper->guessFirewallName($io, $securityData); + $this->userClass = $securityHelper->guessUserClass($io, $securityData['security']['providers']); + $this->userNameField = $securityHelper->guessUserNameField($io, $this->userClass, $securityData['security']['providers']); + $useStatements = new UseStatementGenerator([ AbstractController::class, Response::class, @@ -142,7 +152,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen AuthenticationUtils::class, ]); - $controllerNameDetails = $generator->createClassNameDetails($this->controllerName, 'Controller\\', 'Controller'); + $controllerNameDetails = $generator->createClassNameDetails($input->getArgument('controllerName'), 'Controller\\', 'Controller'); $templatePath = strtolower($controllerNameDetails->getRelativeNameWithoutSuffix()); $controllerPath = $generator->generateController( @@ -155,7 +165,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen ] ); - if ($this->willLogout) { + if ($input->getOption('will-logout')) { $manipulator = new ClassSourceManipulator($generator->getFileContentsForPendingOperation($controllerPath)); $this->securityControllerBuilder->addLogoutMethod($manipulator); @@ -167,7 +177,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen \sprintf('%s/login.html.twig', $templatePath), 'security/formLogin/login_form.tpl.php', [ - 'logout_setup' => $this->willLogout, + 'logout_setup' => $input->getOption('will-logout'), 'username_label' => Str::asHumanWords($this->userNameField), 'username_is_email' => false !== stripos($this->userNameField, 'email'), ] @@ -175,18 +185,18 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen $securityData = $this->securityConfigUpdater->updateForFormLogin($this->ysm->getContents(), $this->firewallToUpdate, 'app_login', 'app_login'); - if ($this->willLogout) { + if ($input->getOption('will-logout')) { $securityData = $this->securityConfigUpdater->updateForLogout($securityData, $this->firewallToUpdate); } - if ($this->shouldGenerateTests()) { + if ($input->getOption('with-tests')) { $userClassNameDetails = $generator->createClassNameDetails( '\\'.$this->userClass, 'Entity\\' ); $testClassDetails = $generator->createClassNameDetails( - 'LoginControllerTest', + $controllerNameDetails->getShortName() . 'Test', 'Test\\', ); @@ -223,4 +233,14 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen \sprintf('Next: Review and adapt the login template: %s/login.html.twig to suit your needs.', $templatePath), ]); } + + private function getSecurityData(): array + { + if (null === $this->securityData) + { + $this->ysm = new YamlSourceManipulator($this->fileManager->getFileContents(self::SECURITY_CONFIG_PATH)); + $this->securityData = $this->ysm->getData(); + } + return $this->securityData; + } }