We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Outputting a large amount of data to the command line can quickly become a hell. Luckily there are tables that can display your data in a more readable way. The tables in Laravel are based on the Symfony Table Component.
For example, if we look at the php artisan route:list
command, we always get a table back as a response with our routes in it. It is the default layout of a table for the console component in Laravel.
$ php artisan route:list
+--------+----------+----------+------+---------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+----------+------+---------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/user | | Closure | api,auth:api |
+--------+----------+----------+------+---------+--------------+
Themes
The table component comes with different table themes. The default theme is appropriately named default
. Alongside the "default" theme, you also have others: compact
, borderless
, box
, box-double
. If we take the same table from the php artisan route:list
command, we get the following results:
Compact
Domain Method URI Name Action Middleware
GET|HEAD / Closure web
GET|HEAD api/user Closure api,api:auth
Borderless
======== ========== ========== ====== ========= ==============
Domain Method URI Name Action Middleware
======== ========== ========== ====== ========= ==============
GET|HEAD / Closure web
GET|HEAD api/user Closure api,auth:api
======== ========== ========== ====== ========= ==============
Box
โโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโโโโโ
โ Domain โ Method โ URI โ Name โ Action โ Middleware โ
โโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโโโโโค
โ โ GET|HEAD โ / โ โ Closure โ web โ
โ โ GET|HEAD โ api/user โ โ Closure โ api,auth:api โ
โโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโโโโโ
Box-double
โโโโโโโโโโคโโโโโโโโโโโคโโโโโโโโโโโคโโโโโโโคโโโโโโโโโโคโโโโโโโโโโโโโโโ
โ Domain โ Method โ URI โ Name โ Action โ Middleware โ
โ โโโโโโโโโชโโโโโโโโโโโชโโโโโโโโโโโชโโโโโโโชโโโโโโโโโโชโโโโโโโโโโโโโโโฃ
โ โ GET|HEAD โ / โ โ Closure โ web โ
โ โ GET|HEAD โ api/user โ โ Closure โ api,auth:api โ
โโโโโโโโโโงโโโโโโโโโโโงโโโโโโโโโโโงโโโโโโโงโโโโโโโโโโงโโโโโโโโโโโโโโโ
With these default styles, you can already do a lot of cool things. Before we continue with creating our own theme, we should have a basic command to play with. Let's set up a command that displays all our users in a table for us.
class ListUsers extends Command
{
protected $signature = 'secrets:list-users';
protected $description = 'List all users';
public function handle()
{
$users = User::all();
$headers = ['name', 'email', 'email verified at'];
$data = $users->map(function (User $user) {
return [
'name' => $user->name,
'email' => $user->email,
'email_verified_at' => $user->hasVerifiedEmail()
? $user->email_verified_at->format('Y-m-d')
: 'Not verified',
];
});
$this->table($headers, $data);
}
}
We have a minimal console command now that fetches all of our users and displays them. So if we had 4 users, it would look like this by default:
+------------------+----------------------------+-------------------+
| name | email | email verified at |
+------------------+----------------------------+-------------------+
| Nils Nader | edmund38@example.net | 2019-09-29 |
| Judah Quigley | haley.karine@example.net | 2019-09-29 |
| Lilyan Walker | lolita@example.net | 2019-09-29 |
| Kristofer Winter | gibson.savanna@example.org | 2019-09-29 |
+------------------+----------------------------+-------------------+
Laravel makes it easy to change the theme of our table. Let's pick one of the above theme names and pass it along as the third argument in our console command.
public function handle()
{
// Fetch data
$this->table($headers, $data, 'box');
}
Custom Themes
The default themes already provide you with a lot of flexibility. However, you can do much more with tables. Let's dive into how you can create your own table style and make something useful. How can we register our custom theme?
public function handle()
{
$this->registerCustomTableStyle();
// Fetch data
$this->table($headers, $data, 'secrets');
}
private function registerCustomTableStyle()
{
$tableStyle = (new TableStyle())
->setCellHeaderFormat('<fg=black;bg=yellow>%s</>');
Table::setStyleDefinition('secrets', $tableStyle);
}
In the above example, the registerCustomTableStyle
method is called, which registers the custom theme. The custom theme is called secrets
, which is also the name used as the third argument on the table
method. In this case, the custom theme only sets the background color and text color of the header row.
Now that you know how to create custom themes, let's create a custom table. This theme will help you focus on the content and less on the lines. Let's try this:
private function registerCustomTableStyle()
{
$tableStyle = (new TableStyle())
->setHorizontalBorderChars('โ')
->setVerticalBorderChars('โ')
->setCrossingChars(' ', 'โ', 'โ', 'โ', 'โ', 'โ', 'โ', 'โ', 'โ');
Table::setStyleDefinition('secrets', $tableStyle);
}
This will result in the following table:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ id โ name โ email โ email verified at โ
โโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ 1 | Nils Nader โ edmund38@example.net โ 2019-09-29 โ
โ 2 โ Judah Quigley โ haley.karine@example.com โ 2019-09-29 โ
โ 3 โ Lilyan Walker โ lolita.wiza@example.com โ 2019-09-29 โ
โ 4 โ Kristofer Ball โ gibson.savanna@example.org โ 2019-09-29 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Layout Elements
Customizing the theme of the table is one thing, but we can do even more with tables. Let's look at adding row separators, titles and footers. We'll start with the row separators.
For the separator, we can just add it as one of the lines in the table. Then the console will automatically insert a line with the same styling as the other lines.
new TableSeparator()
Since we use a collection to insert the data, we can use the splice
method to insert the separator anywhere we want. That code looks like this:
$data->splice(3, 0, [new TableSeparator()]);
$this->table($headers, $data);
In the code above, we add the table separator just after the third item using the splice
method of the collection. That will result in the following:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ id โ name โ email โ email verified at โ
โโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ 1 โ Ashleigh Harris โ arnold20@example.org โ 2019-10-13 โ
โ 2 โ Rico Hermist โ kuhic.barry@example.com โ 2019-10-13 โ
โ 3 โ Robb Collin โ donnell55@example.org โ 2019-10-13 โ
โโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ 4 โ Kaylin Kuhlman โ ahmed.jacobi@example.org โ 2019-10-13 โ
โ 5 โ Clifton Harvey โ arohan@example.net โ 2019-10-13 โ
โ 6 โ Tristian Brown โ kianna.brakus@example.com โ 2019-10-13 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Apart from adding separators, we can also set a header title and even a footer title of the table. We can put anything in there. In a table, for example, a footer can be helpful to tell the user that this is only showing a part of the results, like pagination. It might even offer some extra useful statistics.
We can set a header and footer title like so:
$table->setHeaderTitle('Header Title');
$table->setFooterTitle('Footer Title');
However, this presents us with a new challenge. Laravel has the helper method called table
for outputting tables in the console that we used in the previous example. This method doesn't allow for passing in a header or footer. For that, we need the actual table object. We can quickly get the same result and add the header and footer by creating and rendering the table ourselves.
$table = new Table($this->output);
$table->setHeaders($headers)
->setRows($data->toArray())
->setStyle('secrets');
$table->setHeaderTitle('All users');
$table->setFooterTitle(
sprintf('%d%% verified by email', $percentageVerified)
);
$table->render();
By adding the header and footer in the table, some parts of the table's lines will be removed and updated with the text. The calculation of where the text should be is all being done in the table component. Eventually, we end up with something like this:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ All users โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ id โ name โ email โ email verified at โ
โโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ 1 โ Ashleigh Harris โ arnold20@example.org โ 2019-10-13 โ
โ 2 โ Rico Hermist โ kuhic.barry@example.com โ 2019-10-13 โ
โ 3 โ Robb Collins โ donnell55@example.org โ Not verified โ
โ 4 โ Kaylin Kuhlman โ ahmed.jacobi@example.org โ Not verified โ
โ 5 โ Clifton Harvey โ arohan@example.net โ 2019-10-13 โ
โ 6 โ Tristian Brown โ kianna.brakus@example.com โ 2019-10-13 โ
โโโโโโโโโโโโโโโโโโโโโโโโ 67% verified by email โโโโโโโโโโโโโโโโโโโโโโโโโ
Rendering the table ourselves is very cool. However, it doesn't add much value. It only brings extra code that we need to maintain. We can use a different solution to add additional information to our table. This way, we can keep using the $this->table
console helper method provided by Laravel.
For this, we can use the TableCell
helper class. This class acts like a new cell in a row. All the items you put in the array are converted to TableCell
objects and added to the table. We can reuse this logic and build our header and footer.
$headers = [
[new TableCell(
'A list of all your users, showing if they are verified.',
['colspan' => 4]
)],
['id', 'name', 'email', 'email verified at']
];
$data->push(new TableSeparator());
$data->push([new TableCell(
sprintf('%d%% verified by email', $percentageVerified),
['colspan' => 4]
)]);
$this->table($headers, $data, 'secrets');
As you can see in the above code, we now have an array of headers. The reason we do this, is so they both get the same styling. So if our header is green text, all our headers will be green. We specify that the colspan
should be set to 4. This way, it will be printed over the full table.
We push a TableSeparator
and a TableCell
with the data set's information for the footer part. We need to do it this way because we don't know how many lines you are going to have in the end.
Finally, we pass the collected data to the table
helper method and print the table. This results in the following:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ A list of all your users, showing if they are verified. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ id โ name โ email โ email verified at โ
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ 1 โ Ashleigh Harris โ arnold20@example.org โ 2019-10-13 โ
โ 2 โ Rico Hermist โ kuhic.barry@example.com โ 2019-10-13 โ
โ 3 โ Robb Collins โ donnell55@example.org โ Not verified โ
โ 4 โ Kaylin Kuhlman โ ahmed.jacobi@example.org โ Not verified โ
โ 5 โ Clifton Harvey โ arohan@example.net โ 2019-10-13 โ
โ 6 โ Tristian Brown โ kianna.brakus@example.com โ 2019-10-13 โ
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ 66% verified by email โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Why Customize the Tables?
The more you work with data on the command line, the more essential tables become. Tables can help you get the information processable on the screen. In combination with other components like pagination and questions, this can be powerful.
Customizing the table can help you as a developer to be more specific about a particular part of the data. For example, adding color to a single row or table cell gives it more attention in the overview.
Although this brings some extra work and maybe some more investigation time, generating these tables can help you out in the long run. A lot of developers just echo out everything with strings and use that as output. However, this is harder to process and also harder to share with others. A table can be easily shared as a snippet and is readable right away.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.