Skip to content

Commit 5180bdc

Browse files
committed
Tweaked the use of SymfonyStyle in commands
1 parent 515c00e commit 5180bdc

File tree

3 files changed

+72
-82
lines changed

3 files changed

+72
-82
lines changed

src/AppBundle/Command/AddUserCommand.php

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
use Symfony\Component\Console\Input\InputInterface;
1919
use Symfony\Component\Console\Input\InputOption;
2020
use Symfony\Component\Console\Output\OutputInterface;
21-
use Symfony\Component\Console\Question\Question;
2221
use Symfony\Component\Console\Style\SymfonyStyle;
2322
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
23+
use Symfony\Component\Stopwatch\Stopwatch;
2424

2525
/**
2626
* A command console that creates users and stores them in the database.
@@ -45,6 +45,7 @@ class AddUserCommand extends Command
4545
{
4646
const MAX_ATTEMPTS = 5;
4747

48+
private $io;
4849
private $entityManager;
4950
private $passwordEncoder;
5051

@@ -76,6 +77,18 @@ protected function configure()
7677
;
7778
}
7879

80+
/**
81+
* This optional method is the first one executed for a command after configure()
82+
* and is useful to initialize properties based on the input arguments and options.
83+
*/
84+
protected function initialize(InputInterface $input, OutputInterface $output)
85+
{
86+
// SymfonyStyle is an optional feature that Symfony provides so you can
87+
// apply a consistent look to the commands of your application.
88+
// See https://symfony.com/doc/current/console/style.html
89+
$this->io = new SymfonyStyle($input, $output);
90+
}
91+
7992
/**
8093
* This method is executed after initialize() and before execute(). Its purpose
8194
* is to check if some of the options/arguments are missing and interactively
@@ -92,18 +105,10 @@ protected function interact(InputInterface $input, OutputInterface $output)
92105
return;
93106
}
94107

95-
// See: http://symfony.com/doc/current/console/style.html
96-
$io = new SymfonyStyle($input, $output);
97-
98-
// Use the title() method to display the title
99-
$io->title('Add User Command Interactive Wizard');
100-
101-
// multi-line messages can be displayed this way...
102-
$io->text('If you prefer to not use this interactive wizard, provide the');
103-
$io->text('arguments required by this command as follows:');
104-
105-
// ...but you can also pass an array of strings to the text() method
106-
$io->text([
108+
$this->io->title('Add User Command Interactive Wizard');
109+
$this->io->text([
110+
'If you prefer to not use this interactive wizard, provide the',
111+
'arguments required by this command as follows:',
107112
'',
108113
' $ php bin/console app:add-user username password [email protected]',
109114
'',
@@ -112,61 +117,45 @@ protected function interact(InputInterface $input, OutputInterface $output)
112117

113118
// Ask for the username if it's not defined
114119
$username = $input->getArgument('username');
115-
if (null === $username) {
116-
$question = new Question('Username');
117-
$question->setValidator(function ($answer) {
120+
if (null !== $username) {
121+
$this->io->text(' > <info>Username</info>: '.$username);
122+
} else {
123+
$username = $this->io->ask('Username', null, function ($answer) {
118124
if (empty($answer)) {
119125
throw new \RuntimeException('The username cannot be empty');
120126
}
121127

122128
return $answer;
123129
});
124-
$question->setMaxAttempts(self::MAX_ATTEMPTS);
125130

126-
$username = $io->askQuestion($question);
127131
$input->setArgument('username', $username);
128-
} else {
129-
$io->text(' > <info>Username</info>: '.$username);
130132
}
131133

132134
// Ask for the password if it's not defined
133135
$password = $input->getArgument('password');
134-
if (null === $password) {
135-
$question = new Question('Password (your type will be hidden)');
136-
$question->setValidator([$this, 'passwordValidator']);
137-
$question->setHidden(true);
138-
$question->setMaxAttempts(self::MAX_ATTEMPTS);
139-
140-
$password = $io->askQuestion($question);
141-
$input->setArgument('password', $password);
136+
if (null !== $password) {
137+
$this->io->text(' > <info>Password</info>: '.str_repeat('*', mb_strlen($password)));
142138
} else {
143-
$io->text(' > <info>Password</info>: '.str_repeat('*', mb_strlen($password)));
139+
$password = $this->io->askHidden('Password (your type will be hidden)', null, [$this, 'passwordValidator']);
140+
$input->setArgument('password', $password);
144141
}
145142

146143
// Ask for the email if it's not defined
147144
$email = $input->getArgument('email');
148-
if (null === $email) {
149-
$question = new Question('Email');
150-
$question->setValidator([$this, 'emailValidator']);
151-
$question->setMaxAttempts(self::MAX_ATTEMPTS);
152-
153-
$email = $io->askQuestion($question);
154-
$input->setArgument('email', $email);
145+
if (null !== $email) {
146+
$this->io->text(' > <info>Email</info>: '.$email);
155147
} else {
156-
$io->text(' > <info>Email</info>: '.$email);
148+
$email = $this->io->ask('Email', null, [$this, 'emailValidator']);
149+
$input->setArgument('email', $email);
157150
}
158151

159152
// Ask for the full name if it's not defined
160153
$fullName = $input->getArgument('full-name');
161-
if (null === $fullName) {
162-
$question = new Question('Full Name');
163-
$question->setValidator([$this, 'fullNameValidator']);
164-
$question->setMaxAttempts(self::MAX_ATTEMPTS);
165-
166-
$fullName = $io->askQuestion($question);
167-
$input->setArgument('full-name', $fullName);
154+
if (null !== $fullName) {
155+
$this->io->text(' > <info>Full Name</info>: '.$fullName);
168156
} else {
169-
$io->text(' > <info>Full Name</info>: '.$fullName);
157+
$fullName = $this->io->ask('Full Name', null, [$this, 'fullNameValidator']);
158+
$input->setArgument('full-name', $fullName);
170159
}
171160
}
172161

@@ -176,8 +165,8 @@ protected function interact(InputInterface $input, OutputInterface $output)
176165
*/
177166
protected function execute(InputInterface $input, OutputInterface $output)
178167
{
179-
$startTime = microtime(true);
180-
$io = new SymfonyStyle($input, $output);
168+
$stopwatch = new Stopwatch();
169+
$stopwatch->start('add-user-command');
181170

182171
$username = $input->getArgument('username');
183172
$plainPassword = $input->getArgument('password');
@@ -202,13 +191,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
202191
$this->entityManager->persist($user);
203192
$this->entityManager->flush();
204193

205-
$io->success(sprintf('%s was successfully created: %s (%s)', $isAdmin ? 'Administrator user' : 'User', $user->getUsername(), $user->getEmail()));
194+
$this->io->success(sprintf('%s was successfully created: %s (%s)', $isAdmin ? 'Administrator user' : 'User', $user->getUsername(), $user->getEmail()));
206195

196+
$event = $stopwatch->stop('add-user-command');
207197
if ($output->isVerbose()) {
208-
$finishTime = microtime(true);
209-
$elapsedTime = $finishTime - $startTime;
210-
211-
$io->note(sprintf('New user database id: %d / Elapsed time: %.2f ms', $user->getId(), $elapsedTime * 1000));
198+
$this->io->comment(sprintf('New user database id: %d / Elapsed time: %.2f ms / Consumed memory: %.2f MB', $user->getId(), $event->getDuration(), $event->getMemory() / pow(1024, 2)));
212199
}
213200
}
214201

src/AppBundle/Command/DeleteUserCommand.php

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class DeleteUserCommand extends Command
4040
{
4141
const MAX_ATTEMPTS = 5;
4242

43+
private $io;
4344
private $entityManager;
4445

4546
public function __construct(EntityManagerInterface $em)
@@ -71,18 +72,22 @@ protected function configure()
7172
);
7273
}
7374

75+
protected function initialize(InputInterface $input, OutputInterface $output)
76+
{
77+
// SymfonyStyle is an optional feature that Symfony provides so you can
78+
// apply a consistent look to the commands of your application.
79+
// See https://symfony.com/doc/current/console/style.html
80+
$this->io = new SymfonyStyle($input, $output);
81+
}
82+
7483
protected function interact(InputInterface $input, OutputInterface $output)
7584
{
7685
if (null !== $input->getArgument('username')) {
7786
return;
7887
}
7988

80-
// See: http://symfony.com/doc/current/console/style.html
81-
$io = new SymfonyStyle($input, $output);
82-
83-
$io->title('Delete User Command Interactive Wizard');
84-
85-
$io->text([
89+
$this->io->title('Delete User Command Interactive Wizard');
90+
$this->io->text([
8691
'If you prefer to not use this interactive wizard, provide the',
8792
'arguments required by this command as follows:',
8893
'',
@@ -92,8 +97,7 @@ protected function interact(InputInterface $input, OutputInterface $output)
9297
'',
9398
]);
9499

95-
$username = $io->ask('Username', null, [$this, 'usernameValidator']);
96-
100+
$username = $this->io->ask('Username', null, [$this, 'usernameValidator']);
97101
$input->setArgument('username', $username);
98102
}
99103

@@ -118,8 +122,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
118122
$this->entityManager->remove($user);
119123
$this->entityManager->flush();
120124

121-
(new SymfonyStyle($input, $output))
122-
->success(sprintf('User "%s" (ID: %d, email: %s) was successfully deleted.', $user->getUsername(), $userId, $user->getEmail()));
125+
$this->io->success(sprintf('User "%s" (ID: %d, email: %s) was successfully deleted.', $user->getUsername(), $userId, $user->getEmail()));
123126
}
124127

125128
/**

src/AppBundle/Command/ListUsersCommand.php

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
use AppBundle\Entity\User;
1515
use Doctrine\ORM\EntityManagerInterface;
1616
use Symfony\Component\Console\Command\Command;
17-
use Symfony\Component\Console\Helper\Table;
1817
use Symfony\Component\Console\Input\InputInterface;
1918
use Symfony\Component\Console\Input\InputOption;
2019
use Symfony\Component\Console\Output\BufferedOutput;
2120
use Symfony\Component\Console\Output\OutputInterface;
21+
use Symfony\Component\Console\Style\SymfonyStyle;
2222

2323
/**
2424
* A command console that lists all the existing users.
@@ -94,34 +94,34 @@ protected function execute(InputInterface $input, OutputInterface $output)
9494

9595
// Doctrine query returns an array of objects and we need an array of plain arrays
9696
$usersAsPlainArrays = array_map(function (User $user) {
97-
return [$user->getId(), $user->getFullName(), $user->getUsername(), $user->getEmail(), implode(', ', $user->getRoles())];
97+
return [
98+
$user->getId(),
99+
$user->getFullName(),
100+
$user->getUsername(),
101+
$user->getEmail(),
102+
implode(', ', $user->getRoles()),
103+
];
98104
}, $users);
99105

100106
// In your console commands you should always use the regular output type,
101107
// which outputs contents directly in the console window. However, this
102-
// particular command uses the BufferedOutput type instead.
103-
// The reason is that the table displaying the list of users can be sent
104-
// via email if the '--send-to' option is provided. Instead of complicating
105-
// things, the BufferedOutput allows to get the command output and store
106-
// it in a variable before displaying it.
108+
// command uses the BufferedOutput type instead, to be able to get the output
109+
// contents before displaying them. This is needed because the command allows
110+
// to send the list of users via email with the '--send-to' option
107111
$bufferedOutput = new BufferedOutput();
112+
$io = new SymfonyStyle($input, $bufferedOutput);
113+
$io->table(
114+
['ID', 'Full Name', 'Username', 'Email', 'Roles'],
115+
$usersAsPlainArrays
116+
);
108117

109-
$table = new Table($bufferedOutput);
110-
$table
111-
->setHeaders(['ID', 'Full Name', 'Username', 'Email', 'Roles'])
112-
->setRows($usersAsPlainArrays)
113-
->setStyle(clone Table::getStyleDefinition('symfony-style-guide'))
114-
;
115-
$table->render();
116-
117-
// instead of displaying the table of users, store it in a variable
118-
$tableContents = $bufferedOutput->fetch();
118+
// instead of just displaying the table of users, store its contents in a variable
119+
$usersAsATable = $bufferedOutput->fetch();
120+
$output->write($usersAsATable);
119121

120122
if (null !== $email = $input->getOption('send-to')) {
121-
$this->sendReport($tableContents, $email);
123+
$this->sendReport($usersAsATable, $email);
122124
}
123-
124-
$output->writeln($tableContents);
125125
}
126126

127127
/**

0 commit comments

Comments
 (0)