8000 Added a new command to create users · SofHad/symfony@d33a650 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit d33a650

Browse files
committed
Added a new command to create users
1 parent 6dd29ce commit d33a650

File tree

4 files changed

+313
-5
lines changed

4 files changed

+313
-5
lines changed

app/Resources/assets/scss/main.scss

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,24 @@ body#homepage {
144144
// Page: 'login'
145145
// --------------------------------------------------
146146
body#login {
147+
#login-users-help p {
148+
font-size: $font-size-base;
149+
line-height: $line-height-base;
150+
151+
&:last-child {
152+
margin-bottom: 0;
153+
}
154+
155+
.label {
156+
margin-right: 5px;
157+
}
158+
159+
.console {
160+
display: block;
161+
margin: 5px 0;
162+
padding: 10px;
163+
}
164+
}
147165
}
148166

149167
//

app/Resources/views/security/login.html.twig

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,24 @@
5959
</tbody>
6060
</table>
6161

62-
<p>
63-
If they don't work, reload your fixtures by running this command
64-
from the terminal: <br/>
65-
<code>$ php app/console doctrine:fixtures:load</code>
66-
</p>
62+
<div id="login-users-help" class="panel panel-default">
63+
<div class="panel-body">
64+
<p>
65+
<span class="label label-success">NOTE</span>
66+
If these users don't work, reload application fixtures by
67+
running this command from the terminal: <br/>
68+
69+
<code class="console">$ php app/console doctrine:fixtures:load</code>
70+
</p>
71+
72+
<p>
73+
<span class="label label-success">TIP</span>
74+
If you want to create new users, run this other command: <br/>
75+
76+
<code class="console">$ php app/console app:add-user</code>
77+
</p>
78+
</div>
79+
</div>
6780
</div>
6881
</div>
6982
{% endblock %}
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace AppBundle\Command;
13+
14+
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputInterface;
17+
use Symfony\Component\Console\Input\InputOption;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
use Symfony\Component\Console\Question\Question;
20+
use Doctrine\Common\Persistence\ObjectManager;
21+
use AppBundle\Entity\User;
22+
23+
/**
24+
* A command console that creates users and stores them in the database.
25+
* To use this command, open a terminal window, enter into your project
26+
* directory and execute the following:
27+
* $ php app/console app:add-user
28+
*
29+
* To output detailed information, increase the command verbosity:
30+
* $ php app/console app:add-user -vv
31+
*
32+
* See http://symfony.com/doc/current/cookbook/console/console_command.html
33+
*
34+
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
35+
*/
36+
class AddUserCommand extends ContainerAwareCommand
37+
{
38+
const MAX_ATTEMPTS = 5;
39+
40+
/** @var ObjectManager */
41+
private $em;
42+
43+
protected function configure()
44+
{
45+
$this
46+
// a good practice is to use the 'app:' prefix to group all your custom application commands
47+
->setName('app:add-user')
48+
->setDescription('Creates users and stores them in the database')
49+
->setHelp($this->getCommandHelp())
50+
// commands can optionally define arguments and/or options (mandatory and optional)
51+
// see http://symfony.com/doc/current/components/console/console_arguments.html
52+
->addArgument('username', InputArgument::OPTIONAL, 'The username of the new user')
53+
->addArgument('password', InputArgument::OPTIONAL, 'The plain password of the new user')
54+
->addArgument('email', InputArgument::OPTIONAL, 'The email of the new user')
55+
->addOption('is-admin', null, InputOption::VALUE_NONE, 'If set, the user is created as an administrator')
56+
;
57+
}
58+
59+
/**
60+
* This method is executed before initialize() and execute(). Its purpose is
61+
* to check if some of the options/arguments are missing and interactively
62+
* ask the user for those values.
63+
*
64+
* This method is completely optional. If you are developing an internal console
65+
* command, you probably should not implement this method because it requires
66+
* quite a lot of work. However, if the command is meant to be used by external
67+
* users, this method is a nice way to fall back and prevent errors.
68+
*/
69+
protected function interact(InputInterface $input, OutputInterface $output)
70+
{
71+
if (null !== $input->getArgument('username') && null !== $input->getArgument('password') && null !== $input->getArgument('email')) {
72+
return;
73+
}
74+
75+
$output->writeln('');
76+
$output->writeln('Add User Command Interactive Wizard');
77+
$output->writeln('-----------------------------------');
78+
79+
$output->writeln(array(
80+
'',
81+
'If you prefer to not use this interactive wizard, provide the',
82+
'arguments required by this command as follows:',
83+
'',
84+
' $ php app/console app:add-user username password email@example.com',
85+
'',
86+
));
87+
88+
$output->writeln(array(
89+
'',
90+
'Now we\'ll ask you for the value of all the missing command arguments.',
91+
'',
92+
));
93+
94+
// See http://symfony.com/doc/current/components/console/helpers/questionhelper.html
95+
$console = $this->getHelper('question');
96+
97+
// Ask for the username if it's not defined
98+
if (null === $username = $input->getArgument('username')) {
99+
$question = new Question(' > <info>Username</>: ');
100+
$question->setValidator(function ($answer) {
101+
if (empty($answer)) {
102+
throw new \RuntimeException('The username cannot be empty');
103+
}
104+
105+
return $answer;
106+
});
107+
$question->setMaxAttempts(self::MAX_ATTEMPTS);
108+
109+
$username = $console->ask($input, $output, $question);
110+
$input->setArgument('username', $username);
111+
} else {
112+
$output->writeln(' > <info>Username</>: '.$username);
113+
}
114+
115+
// Ask for the password if it's not defined
116+
if (null === $password = $input->getArgument('password')) {
117+
$question = new Question(' > <info>Password</> (your type will be hidden): ');
118+
$question->setValidator(array($this, 'passwordValidator'));
119+
$question->setHidden(true);
120+
$question->setMaxAttempts(self::MAX_ATTEMPTS);
121+
122+
$password = $console->ask($input, $output, $question);
123+
$input->setArgument('password', $password);
124+
} else {
125+
$output->writeln(' > <info>Password</>: '.str_repeat('*', strlen($password)));
126+
}
127+
128+
// Ask for the email if it's not defined
129+
if (null === $email = $input->getArgument('email')) {
130+
$question = new Question(' > <info>Email</>: ');
131+
$question->setValidator(array($this, 'emailValidator'));
132+
$question->setMaxAttempts(self::MAX_ATTEMPTS);
133+
134+
$email = $console->ask($input, $output, $question);
135+
$input->setArgument('email', $email);
136+
} else {
137+
$output->writeln(' > <info>Email</>: '.$email);
138+
}
139+
}
140+
141+
/**
142+
* This method is executed after the interact() and before the execute()
143+
* method. It's main purpose is to initialize the variables used in the rest
144+
* of the command methods.
145+
*/
146+
protected function initialize(InputInterface $input, OutputInterface $output)
147+
{
148+
$this->em = $this->getContainer()->get('doctrine')->getManager();
149+
}
150+
151+
/**
152+
* This method is executed after interact() and initialize(). It usually
153+
* contains the logic to execute to complete this command task.
154+
*/
155+
protected function execute(InputInterface $input, OutputInterface $output)
156+
{
157+
$startTime = microtime(true);
158+
159+
$username = $input->getArgument('username');
160+
$plainPassword = $input->getArgument('password');
161+
$email = $input->getArgument('email');
162+
$isAdmin = $input->getOption('is-admin');
163+
164+
// first check if a user with the same username already exists
165+
$existingUser = $this->em->getRepository('AppBundle:User')->findOneBy(array('username' => $username));
166+
167+
if (null !== $existingUser) {
168+
throw new \RuntimeException(sprintf('There is already a user registered with the "%s" username.', $username));
169+
}
170+
171+
// create the user and encode its password
172+
$user = new User();
173+
$user->setUsername($username);
174+
$user->setEmail($email);
175+
$user->setRoles(array($isAdmin ? 'ROLE_ADMIN' : 'ROLE_USER'));
176+
177+
// See http://symfony.com/doc/current/book/security.html#security-encoding-password
178+
$encoder = $this->getContainer()->get('security.password_encoder');
179+
$encodedPassword = $encoder->encodePassword($user, $plainPassword);
180+
$user->setPassword($encodedPassword);
181+
182+
$this->em->persist($user);
183+
$this->em->flush($user);
184+
185+
$output->writeln('');
186+
$output->writeln(sprintf('[OK] %s was successfully created: %s (%s)', $isAdmin ? 'Administrator user' : 'User', $user->getUsername(), $user->getEmail()));
187+
188+
if ($output->isVerbose()) {
189+
$finishTime = microtime(true);
190+
$elapsedTime = $finishTime - $startTime;
191+
192+
$output->writeln(sprintf('[INFO] New user database id: %d / Elapsed time: %.2f ms', $user->getId(), $elapsedTime*1000));
193+
}
194+
}
195+
196+
/**
197+
* This internal method should be private, but it's declared as public to
198+
* maintain PHP 5.3 compatibility when using it in a callback.
199+
*
200+
* @internal
201+
*/
202+
public function passwordValidator($plainPassword)
203+
{
204+
if (empty($plainPassword)) {
205+
throw new \Exception('The password can not be empty');
206+
}
207+
208+
if (strlen(trim($plainPassword)) < 6) {
209+
throw new \Exception('The password must be at least 6 characters long');
210+
}
211+
212+
return $plainPassword;
213+
}
214+
215+
/**
216+
* This internal method should be private, but it's declared as public to
217+
* maintain PHP 5.3 compatibility when using it in a callback.
218+
*
219+
* @internal
220+
*/
221+
public function emailValidator($email)
222+
{
223+
if (empty($email)) {
224+
throw new \Exception('The email can not be empty');
225+
}
226+
227+
if (false === strpos($email, '@')) {
228+
throw new \Exception('The email should look like a real email');
229+
}
230+
231+
return $email;
232+
}
233+
234+
/**
235+
* The command help is usually included in the configure() method, but when
236+
* it's too long, it's better to define a separate method to maintain the
237+
* code readability.
238+
*/
239+
private function getCommandHelp()
240+
{
241+
return <<<HELP
242+
The <info>%command.name%</info> command creates new users and saves them in the database:
243+
244+
<info>php %command.full_name%</info> <comment>username password email</comment>
245+
246+
By default the command creates regular users. To create administrator users,
247+
add the <comment>--is-admin</comment> option:
248+
249+
<info>php %command.full_name%</info> username password email <comment>--is-admin</comment>
250+
251+
If you omit any of the t F438 hree required arguments, the command will ask you to
252+
provide the missing values:
253+
254+
# command will ask you for the email
255+
<info>php %command.full_name%</info> <comment>username password</comment>
256+
257+
# command will ask you for the email and password
258+
<info>php %command.full_name%</info> <comment>username</comment>
259+
260+
# command will ask you for all arguments
261+
<info>php %command.full_name%</info>
262+
263+
HELP;
264+
}
265+
}

web/css/app.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7046,6 +7046,18 @@ footer {
70467046
body#homepage {
70477047
text-align: center; }
70487048

7049+
body#login #login-users-help p {
7050+
font-size: 15px;
7051+
line-height: 1.42857; }
7052+
body#login #login-users-help p:last-child {
7053+
margin-bottom: 0; }
7054+
body#login #login-users-help p .label {
7055+
margin-right: 5px; }
7056+
body#login #login-users-help p .console {
7057+
display: block;
7058+
margin: 5px 0;
7059+
padding: 10px; }
7060+
70497061
body#blog_index h1 {
70507062
margin-bottom: .5em; }
70517063
body#blog_index article.post {

0 commit comments

Comments
 (0)
0