Custom Command Styles With Laravel Artisan

December 3, 2016 —John Koster

Since Laravel's console application and commands are built on top of the Symfony console component, we can use Symfony's console style system within our Laravel commands. Styles are used to control the background and foreground colors of text that is displayed in the console window. Other options exist to further change the appearance of text (such as bold or underscore).

There are two ways to define styles. One is to define styles in-line using a special syntax enclosed in angle brackets similar to HTML. The following example would write a line to the console window with red text. It is important to note that when defining styles in-line that the style tags need to be closed with the </> closing tag.

1<?php
2 
3// ...
4 
5function handle()
6{
7 $this->line('<fg=red>A simple line.</>');
8}
9 
10// ...

To set the foreground color when styling command text set the fg property to a valid foreground color value. The background color can also be styled by setting the bg property to a valid background color value. The following example would also set the background color to yellow. Note that each property is separated by a semicolon.

1<?php
2 
3// ...
4 
5$this->line('<fg=red;bg=yellow>A simple line.</>');
6 
7// ...

It is also possible to only style certain sections of the message (line breaks have been added to improve readability of the code sample):

1<?php
2 
3// ...
4 
5$this->line('<fg=black>Black <fg=red>Red <fg=green>Green <fg=yellow>Yellow
6 <fg=blue>Blue <fg=magenta>Magenta <fg=cyan>Cyan
7 <fg=white;bg=black>White <fg=default;bg=black>Default</>');
8 
9// ...

It should also be noted that only one </> closing tag was added to the previous code sample. This is a feature that makes it simpler to add many styles in one message without having to clutter it with numerous closing tags. The previous example might generate a line similar to the following image:

Styling individual words

The following table lists the valid foreground and background colors:

Color Value Example
Black black fg=black;bg=black
Red red fg=red;bg=red
Green green fg=green;bg=green
Yellow yellow fg=yellow;bg=yellow
Blue blue fg=blue;bg=blue
Magenta magenta fg=magenta;bg=magenta
Cyan cyan fg=cyan;bg=cyan
White white fg=white;bg=white
Default default fg=default;bg=default

Options can also be used to change various aspects of the text as it is displayed. The following table lists each of the various options and a description of each:

Option Value Description
Bold bold Causes the formatted text to display more brightly than the surrounding text.
Underscore underscore Underlines the styled text.
Blink blink Causes the styled text to blink within the console terminal. Note: most modern terminals do not support blink.
Reverse reverse Swaps the foreground and background colors for the styled text.
Conceal conceal Sets the foreground color to transparent. This effectively makes the typed text invisible.

Styles can also be created by creating an instance of Symfony\Component\Console\Formatter\OutputFormatterStyle class. The signature for the OutputFormatterStyle constructor is:

1<?php
2 
3// ...
4 
5/**
6 * Initializes output formatter style.
7 *
8 * @param string|null $foreground The style foreground color name
9 * @param string|null $background The style background color name
10 * @param array $options The style options
11 */
12 public function __construct(
13 $foreground = null,
14 $background = null,
15 array $options = array()
16){}

The OutputFormatterStyle class can accept the foreground and background colors as well as an array of options. Each parameter is optional and not setting any values will cause the style to use the default values. When styles are created using the OutputFormatterStyle class they generally need to be registered with the console applications output formatter. The following example creates a new style, registers it and then uses it to produce some output.

1<?php
2 
3// ...
4 
5use Symfony\Component\Console\Formatter\OutputFormatterStyle;
6 
7// ...
8 
9function handle()
10{
11 $style = new OutputFormatterStyle('white', 'blue', ['bold']);
12 $this->output->getFormatter()->setStyle('bigBlue', $style);
13 
14 // Notice that we use the name of our new style inside the tags.
15 $this->line('<bigBlue>Hello, there</bigBlue>');
16}
17 
18// ...

#Table Styles

The way tabular data is rendered in your commands can be customized extensively. Customizing the way table cells, dividers and headers are rendered is not as simple as passing an array of data to a method, but it is not incredibly difficult. To create customized tables you will need to work with the following classes from the Symfony console component:

  • Symfony\Component\Console\Helper\Table
  • Symfony\Component\Console\Helper\TableSeparator
  • Symfony\Component\Console\Helper\TableCell

The Table class is the starting point to creating any table (Laravel's table method internally creates an instance of Table). When creating a new instance of the Table class we must supply an instance of Symfony\Component\Console\Output\OutputInterface to the constructor as the only argument. Luckily there is an instance of that interface stored in each commands $output property. Creating a new Table instance within a Laravel command might look like this:

1<?php
2 
3// ...
4 
5use Symfony\Component\Console\Helper\Table;
6 
7// ...
8 
9function handle()
10{
11 // Create a new Table instance.
12 $table = new Table($this->output);
13 
14 // Set the table headers.
15 $table->setHeaders([
16 'Site', 'Description'
17 ]);
18 
19 // Set the contents of the table.
20 $table->setRows([
21 ['https://laravel.com', 'The official Laravel website'],
22 ['https://forge.laravel.com/', 'Painless PHP Servers'],
23 ['https://envoyer.io/', 'Zero Downtime PHP Deployment']
24 ]);
25 
26 // Render the table to the output.
27 $table->render();
28 
29}
30 
31// ...

After a command similar to the previous example has executed the user might see something similar in their console window:

1+----------------------------+------------------------------+
2| Site | Description |
3+----------------------------+------------------------------+
4| https://laravel.com | The official Laravel website |
5| https://forge.laravel.com/ | Painless PHP Servers |
6| https://envoyer.io/ | Zero Downtime PHP Deployment |
7+----------------------------+------------------------------+

So far the table looks similar to the output generated by Laravel's table method. However, since we are working directly with the Table class we can use Symfony features to customize how the table is generated and rendered. The following example adds a separator between each of the table rows:

1<?php
2 
3// ...
4 
5use Symfony\Component\Console\Helper\Table;
6use Symfony\Component\Console\Helper\TableSeparator;
7 
8// ...
9 
10function handle()
11{
12 // Create a new Table instance.
13 $table = new Table($this->output);
14 
15 // Set the table headers.
16 $table->setHeaders([
17 'Site', 'Description'
18 ]);
19 
20 // Create a new TableSeparator instance.
21 $separator = new TableSeparator;
22 
23 // Set the contents of the table.
24 $table->setRows([
25 ['https://laravel.com', 'The official Laravel website'],
26 $separator,
27 ['https://forge.laravel.com/', 'Painless PHP Servers'],
28 $separator,
29 ['https://envoyer.io/', 'Zero Downtime PHP Deployment']
30 ]);
31 
32 // Render the table to the output.
33 $table->render();
34 
35}
36 
37// ...

After the previous example has executed the user might see something similar to the following output (notice the new separators between the table rows):

1+----------------------------+------------------------------+
2| Site | Description |
3+----------------------------+------------------------------+
4| https://laravel.com | The official Laravel website |
5+----------------------------+------------------------------+
6| https://forge.laravel.com/ | Painless PHP Servers |
7+----------------------------+------------------------------+
8| https://envoyer.io/ | Zero Downtime PHP Deployment |
9+----------------------------+------------------------------+
Managing TableSeparator Instances

In the previous example we created an instance of TableSeparator before adding the table data. Most examples demonstrate the table separator feature by creating a new instance of TableSeparator each time one is needed. On smaller datasets, this is not an issue, but on extremely large datasets this could cause issues in low memory environments. Each method is fine, but be aware of the intended data set size and memory considerations of the running environment.

Table cells can also be set to span multiple columns and rows, much like in HTML. To do this, table cells must be created explicitly by creating an instance of the TableCell class. The following example combines the previous example and column spanning to create a more interesting table:

1<?php
2 
3// ...
4 
5use Symfony\Component\Console\Helper\Table;
6 
7// ...
8 
9function handle()
10{
11 // Create a new Table instance.
12 $table = new Table($this->output);
13 
14 // Set the table headers.
15 $table->setHeaders([
16 'Site', 'Description'
17 ]);
18 
19 // Create a new TableSeparator instance.
20 $separator = new TableSeparator;
21 
22 // Set the contents of the table.
23 $table->setRows([
24 
25 // Create a row with only one table cell.
26 [new TableCell('First Party', ['colspan' => 2])],
27 $separator,
28 
29 ['https://laravel.com', 'The official Laravel website'],
30 ['https://forge.laravel.com/', 'Painless PHP Servers'],
31 ['https://envoyer.io/', 'Zero Downtime PHP Deployment'],
32 
33 $separator,
34 
35 // Create a row with only one table cell.
36 [new TableCell('Useful Resources', ['colspan' => 2])],
37 $separator,
38 
39 ['https://laracasts.com/', 'The Best Laravel and PHP Screencasts'],
40 ['https://laracasts.com/discuss', 'Laracasts Web Development Forum']
41 ]);
42 
43 // Render the table to the output.
44 $table->render();
45 
46}
47 
48// ...

After the previous command has executed the user would see a table similar to the following output:

1+-------------------------------+--------------------------------------+
2| Site | Description |
3+-------------------------------+--------------------------------------+
4| First Party |
5+-------------------------------+--------------------------------------+
6| https://laravel.com | The official Laravel website |
7| https://forge.laravel.com/ | Painless PHP Servers |
8| https://envoyer.io/ | Zero Downtime PHP Deployment |
9+-------------------------------+--------------------------------------+
10| Useful Resources |
11+-------------------------------+--------------------------------------+
12| https://laracasts.com/ | The Best Laravel and PHP Screencasts |
13| https://laracasts.com/discuss | Laracasts Web Development Forum |
14+-------------------------------+--------------------------------------+

Having table cells span multiple rows is very similar to setting cells to span multiple columns. Instead of setting the colspan option, simply set the rowspan option on the table cell. The colspan and rowspan options can be combined to have cells span multiple rows and columns to create more complicated table layouts.

Text styles can also be used when rendering tables (such as info and error) to further customize how tables are rendered. The following example will build on all of the previous examples to add a new "Status" column to our sites table. This column could be used to display the status of the website or status.

1<?php
2 
3// ...
4 
5use Symfony\Component\Console\Helper\Table;
6 
7// ...
8 
9function handle()
10{
11 // Create a new Table instance.
12 $table = new Table($this->output);
13 
14 // Set the table headers.
15 $table->setHeaders([
16 'Site', 'Description', 'Status'
17 ]);
18 
19 // Create a new TableSeparator instance.
20 $separator = new TableSeparator;
21 
22 // Set the contents of the table.
23 $table->setRows([
24 [new TableCell('First Party', ['colspan' => 3])],
25 $separator,
26 [
27 'https://laravel.com',
28 'The official Laravel website',
29 '<info>Online</info>'
30 ],
31 [
32 'https://forge.laravel.com/',
33 'Painless PHP Servers',
34 '<info>Online</info>'
35 ],
36 [
37 'https://envoyer.io/',
38 'Zero Downtime PHP Deployment',
39 '<info>Online</info>'
40 ],
41 $separator,
42 [new TableCell('Useful Resources', ['colspan' => 3])],
43 $separator,
44 [
45 'https://laracasts.com/',
46 'The Best Laravel and PHP Screencasts',
47 '<info>Online</info>'
48 ],
49 [
50 'https://laracasts.com/discuss',
51 'Laracasts Web Development Forum',
52 '<info>Online</info>'
53 ],
54 $separator,
55 [new TableCell('Other', ['colspan' => 3])],
56 $separator,
57 [
58 'example.org',
59 'An example experiencing issues.',
60 '<bg=yellow;fg=black>Experiencing Issues</>']
61 ,
62 ['example.org', 'An example offline site.', '<error>Offline</error>']
63 ]);
64 
65 // Render the table to the output.
66 $table->render();
67 
68}
69 
70// ...

The previous example would generate a table similar to the following figure. Notice that the values in the Status column have been styled to provide additional information to the end user.

Custom Table Styles | Styling table cell contents.

Some absolutely amazing
people

The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.