Take a look at the code of any command that you've developed for your own Symfony applications. Odds are that its source code is "a mess" that mixes content with presentation. For example, to display a title in your command's output, you may have used any of these common alternatives:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// alternative 1
$formatter = $this->getHelperSet()->get('formatter');
$formattedBlock = $formatter->formatBlock('Lorem Ipsum Dolor Sit Amet', '', true);
$output->writeln($formattedBlock);
// alternative 2
$title = 'Lorem Ipsum Dolor Sit Amet';
$output->writeln('<info>'.$title.'</info>');
$output->writeln(str_repeat('=', strlen($title)));
// alternative 3
$output->writeln('');
$output->writeln('<info>Lorem Ipsum Dolor Sit Amet</>');
$output->writeln('<info>--------------------------</>');
$output->writeln('');
A few months ago we decided to improve this situation by introducing a new Style Guide for Symfony Commands. These styles are available in Symfony 2.7, but we really started using them in Symfony 2.8. Using a web application analogy, these styles allow you to create console commands which are semantic and forget about their styling and behavior. Your commands just define "the HTML" and the style guide is "the Bootstrap and jQuery" that brings them to life.
Using the new style guide in your commands is as easy as instantiating the
SymfonyStyle
class, passing to it the $input
and $output
of your
command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class MyCommand extends ContainerAwareCommand
{
protected function configure()
{
// ...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
// ...
}
}
We recommend you to name this variable $io
because you will use it both for
input and output operations. Following the same example shown above, this is
how you can output a title in your commands:
1
$io->title('Lorem Ipsum Dolor Sit Amet');
Symfony will take care about the styling details for you: it will change the font color, it will add a newline before and after the title and it will display the title text underlined.
The style guide includes lots of shortcut methods for common needs, such as displaying a table:
1 2 3 4 5 6 7
$headers = ['Parameter', 'Value'];
$rows = [
['Param1', 'Value1'],
['Param2', 'Value2']
];
$io->table($headers, $rows);
The API of the style guide is concise, expressive and intuitive, to ease its learning curve:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
$io = new SymfonyStyle($input, $output);
// common output elements
$io->title(string $message);
$io->section(string $message);
$io->text(string|array $message);
$io->comment(string|array $message);
// more advanced output elements
$io->note(string|array $message);
$io->caution(string|array $message);
$io->listing(array $elements);
$io->table(array $headers, array $rows);
// ask for user's input
$io->ask(string $question, string|null $default = null, callable|null $validator = null);
$io->askHidden(string $question, callable|null $validator = null);
$io->confirm(string $question, bool $default = true);
$io->choice(string $question, array $choices, string|int|null $default = null);
// display the result of the command or some important task
$io->success(string|array $message);
$io->error(string|array $message);
$io->warning(string|array $message);
In practice, this is how each of the above elements is displayed in the command output:
The main advantages of using this new Style Guide are:
- It makes your commands appearance consistent, saving you lots of time deciding which styles to apply for each command.
- It trims a lot of fat in your commands, shaving hundreds of lines dedicated to define the presentation of the information.
- It only requires you to import one class (
SymfonyStyle
) instead of lots of different classes (Table
,ProgressBar
,ChoiceQuestion
,ConfirmationQuestion
, etc.)
Documentation is not ready yet for this style guide, but you can take a look at the source code of the built-in Symfony 2.8 or 3.0 commands, which have been completely redesigned.
Awesome! Also remembers me a lot markdown, is it intentional?
Very nice! I was really impressed by this feature at Symfonycon.
This is AWESOME !!!
Now I have tons of command to refactor with this !!
<3
@Emanuele it's not entirely intentional, but we wanted to provide a familiar and neutral look, nothing fancy or trendy.
Glad to finally see a blog post about this feature ! This one missed some love since its release :D
Like you said in the SymfonyCon, very fast release! Congrats and Thanks!
Sure it is a very usefull/important feature! :D
Nice feature!
Very useful helper, thx!
This is useful! Thanks :)
Another great example of DX!
I like it :)
Great work Javier! This eases a lot the formatting for common sections present in majority of console commands.
Thank you so much.
I Like it!!! great job! Is this feature in 3.0?
Thanks!!
@Martin, yes this feature is available in Symfony 3.0.
I saw this new feature at Symfonycon, it' amazing.
Awesome! Very useful addition!
Saw it at SymfonyCon and now using SymfonyStyle in an import translations command.
@Javier Eguiluz, what about interactive command testing? I mean that same feature http://symfony.com/doc/current/components/console/helpers/questionhelper.html#testing-a-command-that-expects-input is absent at this time in SymfonyStyle class. There is only one place where uses questionHelper https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Console/Style/SymfonyStyle.php#L326 but it haven't provide setter for this private property. 326-328 lines can be deleted freely for now, if you will not add setter.
Ahh yes, no more inventing my own styles!
@Alexander I think you are right. You should probably create a new issue at https://github.com/symfony/symfony to discuss about this.
Thanks a lot.
Thanks for that! It's going to save us a lot of time!