Generar PDF en Laravel
Índice de contenidos
Introducción
Para generar archivos PDFs desde PHP existen muchas librerías como: mPDF, FPDF, html2fpdf, Dompdf, TCPDF, FPDI, Zend_Pdf y otros. En este articulo voy a explicar como generar PDF en Laravel con la librería mPDF, porque ya tengo un buen tiempo utilizando esta librería y no he tenido muchos problemas para generar archivos PDFs.
En este ejemplo voy a realizar un diseño de una boleta de venta, el diseño sería así:
Y también haremos el diseño físico, para que se pueda imprimir en una hoja pre-impresa.
Entorno de trabajo
- PHP 7.1
- Servidor Web Apache/2.4.6
- Framework Laravel 5.5 funcionando correctamente
- Sistema Operativo CentOS Linux release 7.3 (Vagrant)
- MPDF 7.0
Instalar Mpdf en Laravel
Desde la terminal ejecutamos el siguiente comando.
composer require mpdf/mpdf |
Crear el controlador
Ahora creamos nuestro controlador
php artisan make:controller PdfController |
El contenido del archivo PdfController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Mpdf\Mpdf; class PdfController extends Controller { public function getIndex() { return view('pdf.index'); } public function getGenerar(Request $request) { $accion = $request->get('accion'); $tipo = $request->get('tipo'); return $this->pdf($accion,$tipo); } public function pdf($accion='ver',$tipo='digital') { $ruc = "10072486893"; $numero = "00000412"; $nombres = "DAVID OLIVARES PEÑA"; $dia = "09"; $mes = "04"; $ayo = "17"; $direccion = "Lima Perú"; $dni = "23918745"; $total = 0; $articulos = [ [ "cantidad" => 3, "descripcion" => "COCINA A GAS", "precio" => 400.00, "importe" => 1200, ], [ "cantidad" => 1, "descripcion" => "PLANCHA", "precio" => 85.00, "importe" => 85.00, ], ]; foreach ($articulos as $key => $value) { $total += $value["importe"]; $articulos[$key]["precio"] = number_format($value["precio"],2,'.',' ');; $articulos[$key]["importe"] = number_format($value["importe"],2,'.',' ');; } $total = number_format($total,2,'.',' '); $data['ruc'] = $ruc; $data['numero'] = $numero; $data['nombres'] = $nombres; $data['dia'] = $dia; $data['mes'] = $mes; $data['ayo'] = $ayo; $data['direccion'] = $direccion; $data['dni'] = $dni; $data['articulos'] = $articulos; $data['total'] = $total; $data['tipo'] = $tipo; if($accion=='html'){ return view('pdf.generar',$data); }else{ $html = view('pdf.generar',$data)->render(); } $namefile = 'boleta_de_venta_'.time().'.pdf'; $defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults(); $fontDirs = $defaultConfig['fontDir']; $defaultFontConfig = (new \Mpdf\Config\FontVariables())->getDefaults(); $fontData = $defaultFontConfig['fontdata']; $mpdf = new Mpdf([ 'fontDir' => array_merge($fontDirs, [ public_path() . '/fonts', ]), 'fontdata' => $fontData + [ 'arial' => [ 'R' => 'arial.ttf', 'B' => 'arialbd.ttf', ], ], 'default_font' => 'arial', // "format" => "A4", "format" => [264.8,188.9], ]); // $mpdf->SetTopMargin(5); $mpdf->SetDisplayMode('fullpage'); $mpdf->WriteHTML($html); // dd($mpdf); if($accion=='ver'){ $mpdf->Output($namefile,"I"); }elseif($accion=='descargar'){ $mpdf->Output($namefile,"D"); } } } |
En nuestro route agregamos lo siguiente
Route::get('pdf','PdfController@getIndex'); Route::get('pdf/generar','PdfController@getGenerar'); |
Crear la vista
Vista resources/views/pdf/index.blade.php es una página que tendrá los link para ver los PDFs, son 4 links, 2 para ver el PDF en el navegador web la versión digital y física y otros 2 para descargar los PDFs.
<!DOCTYPE html> <html> <head> <title>PDF</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> <h3>GENERAR PDF CON LARAVEL</h3> <ul> <li> <a target="_blank" href="{{ action('PdfController@getGenerar',['accion'=>'ver','tipo'=>'digital']) }}">Ver PDF digital</a> </li> <li> <a target="_blank" href="{{ action('PdfController@getGenerar',['accion'=>'ver','tipo'=>'fisico']) }}">Ver PDF físico</a> </li> <li> <a target="_blank" href="{{ action('PdfController@getGenerar',['accion'=>'descargar','tipo'=>'digital']) }}">Descargar PDF digital</a> </li> <li> <a target="_blank" href="{{ action('PdfController@getGenerar',['accion'=>'descargar','tipo'=>'fisico']) }}">Descargar PDF físico</a> </li> </ul> </div> </body> </html> |
Vista resources/views/pdf/generar.blade.php el diseño del PDF
<!DOCTYPE html> <html> <head> <title>BOLETA DE VENTA</title> <style type="text/css"> body{ font-size: 16px; font-family: "Arial"; } table{ border-collapse: collapse; } td{ padding: 6px 5px; font-size: 15px; } .h1{ font-size: 21px; font-weight: bold; } .h2{ font-size: 18px; font-weight: bold; } .tabla1{ margin-bottom: 20px; } .tabla2 { margin-bottom: 20px; } .tabla3{ margin-top: 15px; } .tabla3 td{ border: 1px solid #000; } .tabla3 .cancelado{ border-left: 0; border-right: 0; border-bottom: 0; border-top: 1px dotted #000; width: 200px; } .emisor{ color: red; } .linea{ border-bottom: 1px dotted #000; } .border{ border: 1px solid #000; } .fondo{ background-color: #dfdfdf; } .fisico{ color: #fff; } .fisico td{ color: #fff; } .fisico .border{ border: 1px solid #fff; } .fisico .tabla3 td{ border: 1px solid #fff; } .fisico .linea{ border-bottom: 1px dotted #fff; } .fisico .emisor{ color: #fff; } .fisico .tabla3 .cancelado{ border-top: 1px dotted #fff; } .fisico .text{ color: #000; } .fisico .fondo{ background-color: #fff; } @if($tipo=='fisico') #logo{ display: none; } @endif </style> </head> <body> <div class="@if($tipo=='fisico') fisico @endif"> <table width="100%" class="tabla1"> <tr> <td width="73%" align="center"><img id="logo" src="{{ asset('images/logo_dmc.png') }}" alt="" width="255" height="57"></td> <td width="27%" rowspan="3" align="center" style="padding-right:0"> <table width="100%"> <tr> <td height="50" align="center" class="border"><span class="h2">RUC: {{ $ruc }}</span></td> </tr> <tr> <td height="40" align="center" class="border fondo"><span class="h1">BOLETA DE VENTA</span></td> </tr> <tr> <td height="50" align="center" class="border">001- Nº <span class="text">{{ $numero }}</span></td> </tr> </table> </td> </tr> <tr> <td align="center">Jr. Santander Nro. 340 Jesus María - Lima</td> </tr> <tr> <td align="center">Telf.: (01) 364-2547 Cel.: 985-748514</td> </tr> </table> <table width="100%" class="tabla2"> <tr> <td width="11%">Señor (es):</td> <td width="37%" class="linea"><span class="text">{{ $nombres }}</span></td> <td width="5%"> </td> <td width="13%"> </td> <td width="4%"> </td> <td width="7%" align="center" class="border fondo"><strong>DÍA</strong></td> <td width="8%" align="center" class="border fondo"><strong>MES</strong></td> <td width="7%" align="center" class="border fondo"><strong>AÑO</strong></td> </tr> <tr> <td>Dirección:</td> <td class="linea"><span class="text">{{ $direccion }}</span></td> <td>DNI:</td> <td class="linea"><span class="text">{{ $dni }}</span></td> <td> </td> <td align="center" class="border"><span class="text">{{ $dia }}</span></td> <td align="center" class="border"><span class="text">{{ $mes }}</span></td> <td align="center" class="border"><span class="text">{{ $ayo }}</span></td> </tr> </table> <table width="100%" class="tabla3"> <tr> <td align="center" class="fondo"><strong>CANT.</strong></td> <td align="center" class="fondo"><strong>DESCRIPCIÓN</strong></td> <td align="center" class="fondo"><strong>P. UNITARIO</strong></td> <td align="center" class="fondo"><strong>IMPORTE</strong></td> </tr> @for ($i = 0; $i < 6; $i++) @if (array_key_exists($i, $articulos)) <tr> <td width="7%" align="center"><span class="text">{{ $articulos[$i]['cantidad'] }}</span></td> <td width="59%"><span class="text">{{ $articulos[$i]['descripcion'] }}</span></td> <td width="16%" align="right"><span class="text">{{ $articulos[$i]['precio'] }}</span></td> <td width="18%" align="right"><span class="text">{{ $articulos[$i]['importe'] }}</span></td> </tr> @else <tr> <td width="7%"> </td> <td width="59%"> </td> <td width="16%"> </td> <td width="18%" align="left"> </td> </tr> @endif @endfor <tr> <td style="border:0;"> </td> <td style="border:0;"> </td> <td align="right"><strong>TOTAL S/.</strong></td> <td align="right"><span class="text">{{ $total }}</span></td> </tr> <tr> <td style="border:0;"> </td> <td align="center" style="border:0;"> <table width="200" border="0" cellpadding="0" cellspacing="0"> <tr> <td align="center" class="cancelado">CANCELADO</td> </tr> </table> </td> <td style="border:0;"> </td> <td align="center" style="border:0;" class="emisor"><strong>EMISOR</strong></td> </tr> </table> </div> </body> </html> |
Probar el ejemplo
Ahora ingresamos a http://localhost/pdf veremos unos enlaces para ver y descargar los archivos PDFs.
Agregar un tipo de letra al PDF
Vamos agregar la fuente Arial, para eso vamos a ubicar los archivos arial.ttf y arialbd.ttf en la carpeta public/fonts, luego debemos establecer la ruta completa public_path() . '/fonts'
en la opción fontDir
.
En la opción fontdata
le agregamos los nombres de los archivos arial.ttf y arialbd.ttf
. Las opciones R y B son los estilos Regular y Bold del tipo de letra.
$defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults(); $fontDirs = $defaultConfig['fontDir']; $defaultFontConfig = (new \Mpdf\Config\FontVariables())->getDefaults(); $fontData = $defaultFontConfig['fontdata']; $mpdf = new Mpdf([ 'fontDir' => array_merge($fontDirs, [ public_path() . '/fonts', ]), 'fontdata' => $fontData + [ 'arial' => [ 'R' => 'arial.ttf', 'B' => 'arialbd.ttf', ], ], 'default_font' => 'arial', "format" => "A4", ]); |
Dimensiones del archivo PDF
En la opción format
agregamos la dimensión del archivo PDF, los valores predeterminados pueden ser: A4, A3, A2, etc.. El A4
por defecto es de orientación portrait, A4-L
sería orientación landscape.
También podemos pasarle un array con el ancho y altura en milimetros "format" => [264.8,188.9]
Descargar el archivo PDF
Para descargar el archivo le pasamos la opción D
$mpdf->Output("mi_archivo.pdf","D"); |
¿Cómo guardar un archivo PDF?
Para guardar el archivo le pasamos la opción F
$mpdf->Output("/path/mi_archivo.pdf","F"); |
Agregar una nueva página al archivo PDF
Cada vez que usamos la función $mpdf->AddPage();
se agrega una nueva página al archivo PDF.
$mpdf = new \Mpdf\Mpdf(); $mpdf->WriteHTML('Introducción'); $mpdf->AddPage(); $mpdf->WriteHTML('Aquí nueva página'); |
Si nuestro diseño tiene un Header y Footer que se repite en todas las páginas del archivo PDF, podemos usar las siguientes funciones:
$mpdf->SetHTMLHeader('Código HTML'); $mpdf->SetHTMLFooter('Código HTML'); |
Conclusión
Tenemos muchas librerías para generar PDF en Laravel, en lo particular MPDF es mi preferido, con otras librerías he tenido problemas, pero con MPDF no he tenido problemas, la única recomendación es no usar atributos CSS complejas, ni usar muchas clases por ejemplo: .wrapper .text li a
, ser más simples en el uso de código CSS.