2222use Symfony \Bundle \MakerBundle \Security \InteractiveSecurityHelper ;
2323use Symfony \Bundle \MakerBundle \Security \SecurityConfigUpdater ;
2424use Symfony \Bundle \MakerBundle \Security \SecurityControllerBuilder ;
25- use Symfony \Bundle \MakerBundle \Str ;
2625use Symfony \Bundle \MakerBundle \Util \ClassSourceManipulator ;
2726use Symfony \Bundle \MakerBundle \Util \YamlManipulationFailedException ;
2827use Symfony \Bundle \MakerBundle \Util \YamlSourceManipulator ;
2928use Symfony \Bundle \MakerBundle \Validator ;
3029use Symfony \Bundle \SecurityBundle \SecurityBundle ;
30+ use Symfony \Bundle \TwigBundle \TwigBundle ;
3131use Symfony \Component \Console \Command \Command ;
3232use Symfony \Component \Console \Input \InputArgument ;
3333use 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 (
0 commit comments