Skip to content

Commit c44f878

Browse files
committed
fix after review - batch 1
1 parent 9ec9766 commit c44f878

File tree

21 files changed

+270
-259
lines changed

21 files changed

+270
-259
lines changed

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
"symfony/dependency-injection": "^3.4|^4.0",
2121
"symfony/filesystem": "^3.4|^4.0",
2222
"symfony/finder": "^3.4|^4.0",
23+
"symfony/form": "^4.1",
2324
"symfony/framework-bundle": "^3.4|^4.0",
24-
"symfony/http-kernel": "^3.4|^4.0"
25+
"symfony/http-kernel": "^3.4|^4.0",
26+
"symfony/security": "^4.1"
2527
},
2628
"require-dev": {
2729
"allocine/twigcs": "^3.0",

src/Doctrine/DoctrineHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,6 @@ public function isClassAMappedEntity(string $className): bool
184184
return false;
185185
}
186186

187-
return (bool) $this->getMetadata($className);
187+
return (bool) $this->getMetadata(trim($className, '\\'));
188188
}
189189
}

src/Generator.php

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ public function dumpFile(string $targetPath, string $contents)
8484
];
8585
}
8686

87+
public function getFileContents(string $targetPath): string
88+
{
89+
if (!isset($this->pendingOperations[$targetPath])) {
90+
throw new RuntimeCommandException(sprintf('File "%s" is not in the Generator\'s pending operations', $targetPath));
91+
}
92+
93+
return $this->generateFileContents(
94+
$targetPath,
95+
$this->pendingOperations[$targetPath]
96+
);
97+
}
98+
8799
/**
88100
* Creates a helper object to get data about a class name.
89101
*
@@ -178,20 +190,27 @@ public function writeChanges()
178190
continue;
179191
}
180192

181-
$templatePath = $templateData['template'];
182-
$parameters = $templateData['variables'];
183-
184-
$templateParameters = array_merge($parameters, [
185-
'relative_path' => $this->fileManager->relativizePath($targetPath),
186-
]);
187-
188-
$fileContents = $this->fileManager->parseTemplate($templatePath, $templateParameters);
189-
$this->fileManager->dumpFile($targetPath, $fileContents);
193+
$this->fileManager->dumpFile(
194+
$targetPath,
195+
$this->generateFileContents($targetPath, $templateData)
196+
);
190197
}
191198

192199
$this->pendingOperations = [];
193200
}
194201

202+
private function generateFileContents(string $targetPath, array $templateData)
203+
{
204+
$templatePath = $templateData['template'];
205+
$parameters = $templateData['variables'];
206+
207+
$templateParameters = array_merge($parameters, [
208+
'relative_path' => $this->fileManager->relativizePath($targetPath),
209+
]);
210+
211+
return $this->fileManager->parseTemplate($templatePath, $templateParameters);
212+
}
213+
195214
public function getRootNamespace(): string
196215
{
197216
return $this->namespacePrefix;

src/Maker/MakeAuthenticator.php

Lines changed: 101 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
use Symfony\Bundle\MakerBundle\Security\InteractiveSecurityHelper;
2323
use Symfony\Bundle\MakerBundle\Security\SecurityConfigUpdater;
2424
use Symfony\Bundle\MakerBundle\Security\SecurityControllerBuilder;
25-
use Symfony\Bundle\MakerBundle\Str;
2625
use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator;
2726
use Symfony\Bundle\MakerBundle\Util\YamlManipulationFailedException;
2827
use Symfony\Bundle\MakerBundle\Util\YamlSourceManipulator;
2928
use Symfony\Bundle\MakerBundle\Validator;
3029
use Symfony\Bundle\SecurityBundle\SecurityBundle;
30+
use Symfony\Bundle\TwigBundle\TwigBundle;
3131
use Symfony\Component\Console\Command\Command;
3232
use Symfony\Component\Console\Input\InputArgument;
3333
use Symfony\Component\Console\Input\InputInterface;
@@ -75,14 +75,20 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
7575

7676
public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
7777
{
78+
if (!$this->fileManager->fileExists($path = 'config/packages/security.yaml')) {
79+
throw new RuntimeCommandException('File "security.yaml" does not exist!');
80+
}
81+
$manipulator = new YamlSourceManipulator($this->fileManager->getFileContents($path));
82+
$securityData = $manipulator->getData();
83+
7884
// authenticator type
7985
$authenticatorTypeValues = [
8086
'Empty authenticator' => self::AUTH_TYPE_EMPTY_AUTHENTICATOR,
8187
'Form login' => self::AUTH_TYPE_FORM_LOGIN,
8288
];
8389
$command->addArgument('authenticator-type', InputArgument::REQUIRED);
8490
$authenticatorType = $io->choice(
85-
'Which authentication type do you want ?',
91+
'What style of authentication do you want?',
8692
array_keys($authenticatorTypeValues),
8793
key($authenticatorTypeValues)
8894
);
@@ -91,12 +97,21 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma
9197
$authenticatorTypeValues[$authenticatorType]
9298
);
9399

94-
$manipulator = new YamlSourceManipulator($this->fileManager->getFileContents('config/packages/security.yaml'));
95-
$securityData = $manipulator->getData();
100+
if (self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type')) {
101+
$dependencies = new DependencyBuilder();
102+
$dependencies->addClassDependency(
103+
TwigBundle::class,
104+
'tiwg'
105+
);
96106

97-
if (self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type')
98-
&& !isset($securityData['security']['providers']) || !$securityData['security']['providers']) {
99-
throw new RuntimeCommandException('You need to have at least one provider defined in security.yaml');
107+
$missingPackagesMessage = $dependencies->getMissingPackagesMessage(self::getCommandName(), 'Twig must be installed to display login form');
108+
if ($missingPackagesMessage) {
109+
throw new RuntimeCommandException($missingPackagesMessage);
110+
}
111+
112+
if (!isset($securityData['security']['providers']) || !$securityData['security']['providers']) {
113+
throw new RuntimeCommandException('To generate a form login authentication, you must configure at least one entry under "providers" in "security.yaml".');
114+
}
100115
}
101116

102117
// authenticator class
@@ -116,17 +131,18 @@ function ($answer) {
116131
);
117132
$input->setArgument('authenticator-class', $io->askQuestion($questionAuthenticatorClass));
118133

134+
$interactiveSecurityHelper = new InteractiveSecurityHelper();
119135
$command->addOption('firewall-name', null, InputOption::VALUE_OPTIONAL);
120-
$input->setOption('firewall-name', $firewallName = InteractiveSecurityHelper::guessFirewallName($io, $securityData));
136+
$input->setOption('firewall-name', $firewallName = $interactiveSecurityHelper->guessFirewallName($io, $securityData));
121137

122138
$command->addOption('entry-point', null, InputOption::VALUE_OPTIONAL);
123139
$input->setOption(
124140
'entry-point',
125-
InteractiveSecurityHelper::guessEntryPoint($io, $securityData, $input->getArgument('authenticator-class'), $firewallName)
141+
$interactiveSecurityHelper->guessEntryPoint($io, $securityData, $input->getArgument('authenticator-class'), $firewallName)
126142
);
127143

128144
if (self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type')) {
129-
$command->addArgument('controller-class', InputArgument::OPTIONAL);
145+
$command->addArgument('controller-class', InputArgument::REQUIRED);
130146
$input->setArgument(
131147
'controller-class',
132148
$io->ask(
@@ -137,25 +153,44 @@ function ($answer) {
137153
);
138154

139155
$command->addArgument('user-class', InputArgument::OPTIONAL);
140-
$input->setArgument('user-class', InteractiveSecurityHelper::guessUserClass($io, $securityData));
156+
$userClass = $interactiveSecurityHelper->guessUserClass($io, $securityData['security']['providers']);
157+
if (0 !== strpos($userClass, '\\')) {
158+
$userClass = '\\'.$userClass;
159+
}
160+
$input->setArgument('user-class', $userClass);
141161
}
142162
}
143163

144164
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
145165
{
146166
// generate authenticator class
147-
$generator->generateClass(
148-
$input->getArgument('authenticator-class'),
149-
self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type') ?
150-
($this->doctrineHelper->isClassAMappedEntity($input->getArgument('user-class')) ? 'authenticator/LoginFormEntityAuthenticator.tpl.php' : 'authenticator/LoginFormNotEntityAuthenticator.tpl.php')
151-
: 'authenticator/Empty.tpl.php',
152-
$input->hasArgument('user-class') ?
167+
if (self::AUTH_TYPE_EMPTY_AUTHENTICATOR === $input->getArgument('authenticator-type')) {
168+
$generator->generateClass(
169+
$input->getArgument('authenticator-class'),
170+
'authenticator/EmptyAuthenticator.tpl.php',
171+
[]
172+
);
173+
} elseif ($this->doctrineHelper->isClassAMappedEntity($input->getArgument('user-class'))) {
174+
$userClassNameDetails = $generator->createClassNameDetails(
175+
$input->getArgument('user-class'),
176+
'Entity\\'
177+
);
178+
179+
$generator->generateClass(
180+
$input->getArgument('authenticator-class'),
181+
'authenticator/LoginFormEntityAuthenticator.tpl.php',
153182
[
154-
'user_fully_qualified_class_name' => $input->getArgument('user-class'),
155-
'user_class_name' => substr(strrchr($input->getArgument('user-class'), '\\'), 1),
183+
'user_fully_qualified_class_name' => trim($userClassNameDetails->getFullName(), '\\'),
184+
'user_class_name' => $userClassNameDetails->getShortName(),
156185
]
157-
: []
158-
);
186+
);
187+
} else {
188+
$generator->generateClass(
189+
$input->getArgument('authenticator-class'),
190+
'authenticator/LoginFormNotEntityAuthenticator.tpl.php',
191+
[]
192+
);
193+
}
159194

160195
// update security.yaml with guard config
161196
$securityYamlUpdated = false;
@@ -175,51 +210,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
175210
}
176211

177212
if (self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type')) {
178-
$controllerClassNameDetails = $generator->createClassNameDetails(
179-
$input->getArgument('controller-class'),
180-
'Controller\\',
181-
'Controller'
182-
);
183-
184-
if (class_exists($controllerClassNameDetails->getFullName())) {
185-
// If provided security controller class exist, add login() method
186-
if (method_exists($controllerClassNameDetails->getFullName(), 'login')) {
187-
throw new RuntimeCommandException(sprintf('Method "login" already exists on class %s', $controllerClassNameDetails->getFullName()));
188-
}
189-
190-
$manipulator = new ClassSourceManipulator(
191-
$this->fileManager->getFileContents($controllerPath = $this->fileManager->getRelativePathForFutureClass($controllerClassNameDetails->getFullName())),
192-
true
193-
);
194-
$securityControllerBuilder = new SecurityControllerBuilder();
195-
$securityControllerBuilder->addLoginMethod($manipulator);
196-
197-
if (method_exists($controllerClassNameDetails->getFullName(), 'logout')) {
198-
throw new RuntimeCommandException(sprintf('Method "logout" already exists on class %s', $controllerClassNameDetails->getFullName()));
199-
}
200-
$securityControllerBuilder->addLogoutMethod($manipulator);
201-
202-
$this->generator->dumpFile($controllerPath, $manipulator->getSourceCode());
203-
} else {
204-
// otherwise, create security controller
205-
$controllerPath = $generator->generateClass(
206-
$controllerClassNameDetails->getFullName(),
207-
'authenticator/SecurityController.tpl.php',
208-
[
209-
'parent_class_name' => \method_exists(AbstractController::class, 'getParameter') ? 'AbstractController' : 'Controller',
210-
]
211-
);
212-
}
213-
214-
// create login form template
215-
$templateName = Str::asFilePath($controllerClassNameDetails->getRelativeNameWithoutSuffix()).'/login.html.twig';
216-
$generator->generateFile(
217-
'templates/'.$templateName,
218-
'authenticator/login_form.tpl.php',
219-
[
220-
'controller_path' => $controllerPath,
221-
]
222-
);
213+
$this->generateFormLoginFiles($input);
223214
}
224215

225216
$generator->writeChanges();
@@ -239,6 +230,50 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
239230
$io->text($text);
240231
}
241232

233+
private function generateFormLoginFiles(InputInterface $input)
234+
{
235+
$controllerClassNameDetails = $this->generator->createClassNameDetails(
236+
$input->getArgument('controller-class'),
237+
'Controller\\',
238+
'Controller'
239+
);
240+
241+
if (!class_exists($controllerClassNameDetails->getFullName())) {
242+
$controllerPath = $this->generator->generateClass(
243+
$controllerClassNameDetails->getFullName(),
244+
'authenticator/EmptySecurityController.tpl.php',
245+
[
246+
'parent_class_name' => \method_exists(AbstractController::class, 'getParameter') ? 'AbstractController' : 'Controller',
247+
]
248+
);
249+
250+
$controllerSourceCode = $this->generator->getFileContents($controllerPath);
251+
} else {
252+
$controllerPath = $this->fileManager->getRelativePathForFutureClass($controllerClassNameDetails->getFullName());
253+
$controllerSourceCode = $this->fileManager->getFileContents($controllerPath);
254+
}
255+
256+
if (method_exists($controllerClassNameDetails->getFullName(), 'login')) {
257+
throw new RuntimeCommandException(sprintf('Method "login" already exists on class %s', $controllerClassNameDetails->getFullName()));
258+
}
259+
260+
$manipulator = new ClassSourceManipulator($controllerSourceCode, true);
261+
262+
$securityControllerBuilder = new SecurityControllerBuilder();
263+
$securityControllerBuilder->addLoginMethod($manipulator);
264+
265+
$this->generator->dumpFile($controllerPath, $manipulator->getSourceCode());
266+
267+
// create login form template
268+
$this->generator->generateFile(
269+
'templates/security/login.html.twig',
270+
'authenticator/login_form.tpl.php',
271+
[
272+
'controller_path' => $controllerPath,
273+
]
274+
);
275+
}
276+
242277
public function configureDependencies(DependencyBuilder $dependencies, InputInterface $input = null)
243278
{
244279
$dependencies->addClassDependency(
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?= "<?php\n" ?>
2+
3+
namespace App\Controller;
4+
5+
use Symfony\Bundle\FrameworkBundle\Controller\<?= $parent_class_name; ?>;
6+
use Symfony\Component\Routing\Annotation\Route;
7+
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
8+
9+
class <?= $class_name; ?> extends <?= $parent_class_name; ?><?= "\n" ?>
10+
{
11+
}

src/Resources/skeleton/authenticator/LoginFormEntityAuthenticator.tpl.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@
2121
class <?= $class_name; ?> extends AbstractFormLoginAuthenticator
2222
{
2323
use TargetPathTrait;
24+
2425
private $entityManager;
2526
private $router;
2627
private $csrfTokenManager;
2728
private $passwordEncoder;
2829

2930
public function __construct(EntityManagerInterface $entityManager, RouterInterface $router, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
3031
{
32+
$this->entityManager = $entityManager;
3133
$this->router = $router;
3234
$this->csrfTokenManager = $csrfTokenManager;
3335
$this->passwordEncoder = $passwordEncoder;
34-
$this->entityManager = $entityManager;
3536
}
3637

3738
public function supports(Request $request)
@@ -76,7 +77,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token,
7677
return new RedirectResponse($targetPath);
7778
}
7879

79-
return new RedirectResponse($this->router->generate('app_homepage'));
80+
throw new \Exception('TODO: provide a valid redirection inside '.__FILE__);
8081
}
8182

8283
protected function getLoginUrl()

src/Resources/skeleton/authenticator/LoginFormNotEntityAuthenticator.tpl.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
class <?= $class_name; ?> extends AbstractFormLoginAuthenticator
2020
{
2121
use TargetPathTrait;
22+
2223
private $router;
2324
private $csrfTokenManager;
2425
private $passwordEncoder;
@@ -58,6 +59,8 @@ public function getUser($credentials, UserProviderInterface $userProvider)
5859
throw new InvalidCsrfTokenException();
5960
}
6061

62+
// Load / create our user however you need.
63+
// You can do this by calling the user provider, or with custom logic here.
6164
return $userProvider->loadUserByUsername($credentials['email']);
6265
}
6366

@@ -72,7 +75,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token,
7275
return new RedirectResponse($targetPath);
7376
}
7477

75-
return new RedirectResponse($this->router->generate('app_homepage'));
78+
throw new \Exception('TODO: provide a valid redirection inside '.__FILE__);
7679
}
7780

7881
protected function getLoginUrl()

0 commit comments

Comments
 (0)