In many occation, my clients wanted their data to be exported into a PDF file so that it is portable and ready to print whenever the needed to. There are times when we, as a developer, need to generate those data in form of tables. The tricky part is to make tables look nice in a PDF file when exporting data with the help of PHP. In this article I am going to share some experience to make your tables look nice on a export-to-pdf process.
Suppose that a client has an employees table that he wants to export into a PDF file with table-formatted like this:
|
Employees table |
Step 1 : Add an "Export to PDF" Button
The first thing that we should do, of course, is to add an "Export to PDF" button somewhere on the page. In this case, I put it below the pagination buttons. Open the view file and add these html lines:
<div class="text-center">
<a href="{{ url('/employees/export-to-pdf') }}" class="btn btn-primary">
Export to PDF
</a>
</div>
Notice that the
href
attribute of the anchor tag (the button) is leading to
/employees/export-to-pdf. So later we need to make a route for it. For now, let's just save the view file, and refresh the page in the browser. It should look like this:
|
An "Export to PDF" button has been added |
Step 2 : Install a PDF Library
Next we need to install a tcpdf library that works well with laravel. I'm not recommending any specific package, but since use it in most of my projects, I will be using
tcpdf-laravel from
elibyy throughout this article.
Open the terminal, enter your laravel project directory, and run this artisan command:
composer require elibyy/tcpdf-laravel
After composer is done installing the package, open up the
config/app.php file, and add this line somewhere inside the providers array
Elibyy\TCPDF\ServiceProvider::class,
Also, add this line somewhere inside the aliases array:
'PDF' => Elibyy\TCPDF\Facades\TCPDF::class,
Now save the file and open the
routes/web.php file.
Step 3 : Add a Route
Add this line to make a route for our
/employees/export-to-pdf url:
Route::get('/employees/export-to-pdf', 'EmployeeController@exportToPdf');
Note that if you don't have the controller, create it before you add the route. This is how you create a controller from the terminal:
php artisan make:controller EmployeeController
Now save the file, and get ready put some code in the controller.
Step 4 : Add a Method in The Controller
Next, open up the
app/Http/Controllers/EmployeeController.php file, and add a public method as we defined previously in the route.
public function exportToPdf()
{
$employees = \App\User::all();
$html = view('employees-pdf', compact('employees'));
PDF::SetTitle('Employees Table');
PDF::SetPrintHeader(false);
PDF::SetPrintFooter(false);
PDF::SetMargins(20, 10, 15);
PDF::AddPage('P','LEGAL');
PDF::writeHTML($html, true, false, true, false, '');
$filename = public_path() . '/files/employees.pdf';
PDF::output($filename,'I');
}
Here is how it works:
- The first two lines of the method, are to gather all of the employees data, and load it into a view file named resources/views/employees-pdf.blade.php. Then store the view to a variable $html.
- The next five lines are the PDF settings.
- The last three lines are to save the view to a pdf file named /files/employees.pdf, relative to the public directory (also relative to the domain name of the application).
- Note that on the last line, the second parameter
'I'
is to directly stream the pdf to the browser. So you will be able to instantly see the PDF as a response of the /employee/esport-to-pdf url.
Step 5 : Create a View File
According to the exportToPdf
method on the EmployeeController
, There is supposed to be a view file named resource/views/employees-pdf.blade.php. so create the file if it hasn't been created yet. Open the file and put these html code:
<!DOCTYPE html>
<html>
<head>
<title>Employees</title>
</head>
<body>
<h1>Employees Table</h1>
<table class="table table-bordered" cellpadding="5" width:"100%">
<tr>
<th><div>ID</div></th>
<th><div>Name</div></th>
<th><div>Age</div></th>
<th><div>Division</div></th>
<th><div>Salary</div></th>
<th><div>Performance</div></th>
</tr>
@foreach($employees as $employee)
<tr nobr="true">
<td>{{ $employee->id }}</td>
<td>{{ $employee->name }}</td>
<td>{{ $employee->age }}</td>
<td>{{ $employee->division }}</td>
<td>{{ $employee->salary }}</td>
<td>{{ $employee->performance }}</td>
</tr>
@endforeach
</table>
</body>
</html>
Save it and test the "Export to PDF" button from the browser. It should look something like this:
|
Messy Employees Table |
Okay it works.. But.. It is sooo ugly..
We need to tweak the HTML mockup to beautify the table. Back to the
employees-pdf.blade.php file.
Add some styling just above the closing
</head>
tag
...
<style>
.text-center{text-align:center;}
.text-right{text-align:right;}
td,th{border:1px solid #000000;}
</style>
...
Add a pair of
<thead></thead>
tag after the first closing
</tr>
tag, and fill it with these:
...
<thead>
<tr>
<th width="50"><div class="text-center">1</div></th>
<th width="200"><div class="text-center">2</div></th>
<th width="50"><div class="text-center">3</div></th>
<th><div class="text-center">4</div></th>
<th width="70"><div class="text-center">5</div></th>
<th><div class="text-center">6</div></th>
</tr>
</thead>
...
The thead pairs will allow anything it contained to be displayed on each and every page.
Next, add an opening
<tbody>
tag before the
@foreach
statement, and also a closing
</tbody>
tag after the
@endforeach
statement.
...
<tbody>
@foreach($employees as $employee)
<tr>
...
</tr>
@endforeach
</tbody>
...
Next, adjust the width of the column titles, by following the width we defined in thead above
...
<tr>
<th width="50">ID</th>
<th width="200">Name</th>
<th width="50">Age</th>
<th>Division</th>
<th width="70">Salary</th>
<th>Performance</th>
</tr>
...
Lastly, center some columns by applying a corresponding class that we defined in the
style
tag above. Overall, the final version of the
employees-pdf.blade.php file will be like this:
<!DOCTYPE html>
<html>
<head>
<title>Employees</title>
<style>
.text-center{text-align:center;}
.text-right{text-align:right;}
td,th{border:1px solid #000000;}
</style>
</head>
<body>
<h1>Employees Table</h1>
<table class="table table-bordered" cellpadding="5" width:"100%">
<tr>
<th width="50"><div class="text-center">ID</div></th>
<th width="200"><div class="text-center">Name</div></th>
<th width="50"><div class="text-center">Age</div></th>
<th><div class="text-center">Division</div></th>
<th width="70"><div class="text-center">Salary</div></th>
<th><div class="text-center">Performance</div></th>
</tr>
<thead>
<tr>
<th width="50"><div class="text-center">1</div></th>
<th width="200"><div class="text-center">2</div></th>
<th width="50"><div class="text-center">3</div></th>
<th><div class="text-center">4</div></th>
<th width="70"><div class="text-center">5</div></th>
<th><div class="text-center">6</div></th>
</tr>
</thead>
<tbody>
@foreach($employees as $employee)
<tr>
<td><div class="text-center">{{ $employee->id }}</div></td>
<td>{{ $employee->name }}</td>
<td><div class="text-center">{{ $employee->age }}</div></td>
<td>{{ $employee->division }}</td>
<td>
<div class="text-right">
$ {{ number_format($employee->salary,0,',','.') }}
</div>
</td>
<td>
<div class="text-center">
{{ $employee->performance }}
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>
Save the file and test it out in the browser. It will look something like this:
|
Good Looking Table |
Better.. But hey, if you look at the bottom at each page, there will be an ugly breaking.
|
Static Column Title, But Ugly Breaks |
Well.. That is eazy.. Just add a
nobr="true"
attribute on the tr tag under the
@foreach
statement line
...
<tbody>
@foreach($employees as $employee)
<tr nobr="true">
...
</tr>
@endforeach
</tbody>
...
Save the file again, and test it in the browser. It will look something like this:
|
Nice Break |
Amazing.. We just got ourselves a nice and neat table. Why don't you give it a try and leave a comment below.
Happy coding ^_^