laravel dompdf post

Generar PDFs en proyectos actuales es tan común hoy en día que es imposible dejarlo pasar por alto. Por eso en este artículo vamos a conocer las funcionalidades que tenemos disponibles y que nos pueden ser de gran ayuda para generar PDFs gracias al paquete Laravel Dompdf.

Dompdf

Laravel Dompdf es una extensión o wrapper para Laravel de la librería Dompdf de PHP. Sus principales características son:

  • Maneja la mayoría de propiedades CSS 2.1 y algunas de CSS3, incluidas las reglas @import, @media y @page.
  • Admite la mayoría de los atributos de presentación 4.0 de HTML.
  • Admite hojas de estilo externas, locales o a través de http/ftp (a través de fopen-wrappers).
  • Admite tablas complejas, que incluyen intervalos de filas y columnas, modelos de bordes separados y contraídos, estilo de celda individual.
  • Soporte de imagen (gif, png (8, 24 y 32 bits con canal alfa), bmp y jpeg) sin dependencias de bibliotecas PDF externas, gracias a la clase R&OS PDF
  • Soporte PHP en línea.

Adicionalmente, debes tomar en cuenta las siguientes limitaciones:

  • No es particularmente tolerante a la entrada HTML mal formada (usar Tidy primero puede ayudar).
  • Los archivos grandes o las tablas grandes pueden tardar un tiempo en renderizarse.
  • CSS float no es compatible (pero está en proceso).

Instalación del paquete

La instalación de este paquete es muy simple solo debemos requerirlo con Composer ejecutando el siguiente comando:

composer require barryvdh/laravel-dompdf

No es necesario registrar el service provider y el alias puesto que el paquete tiene soporte para el auto-descubrimiento de Laravel

Después de la instalación se recomienda copiar el archivo de configuración a nuestro proyecto para personalizar los PDF según las necesidades del proyecto. Por lo tanto al ejecutar el próximo comando tendremos el archivo config/dompdf.php:

php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"

Creando una instancia PDF

Hay dos manera de llamar a la instancia de Laravel Dompdf en tu proyecto:

  • Resolviéndolo desde el contenedor de servicios con:
$pdf = App::make('dompdf.wrapper');

// alternativamente con:

$pdf = app('dompdf.wrapper');

  • Usando el Facade PDF y no olvides importarlo.

Creación de un PDF

Puedes crear un PDF a partir de tres tipos de orígenes:

  • Desde un HTML con el método loadHTML.
  • Desde un archivo HTML con el método loadFile.
  • Desde una vista Blade con el método loadView.

Como salida tienes tres opciones:

  • Guardarlo como un archivo con el método save.
  • Mostrarlo en el navegador con el método stream.
  • Permitir descargarlo directamente con el método download.

Creación de un simple PDF desde un HTML

La simpleza de este paquete es lo que lo característica ya que para generar un PDF nos podemos dirigir a cualquier método de alguno de nuestros controladores donde esté apuntando una ruta y con solo el siguiente código ya estaremos generando un PDF:

public function download()
{
    $pdf = app('dompdf.wrapper');
    $pdf->loadHTML('<h1>Styde.net</h1>');

    return $pdf->download('mi-archivo.pdf');
}

Se crea una instancia de la clase Barryvdh\DomPDF\PDF resolviéndolo desde el contenedor de servicios de Laravel, creando el PDF a partir de un HTML usando el loadHtml y como salida que se descargue directamente con el nombre 'mi-archivo.pdf'.

Generar PDF desde una vista Blade

En el ejemplo anterior estamos ingresando el HTML como una cadena de texto y esto hace que sea muy complicado de mantener. Podemos aprovechar Blade el motor de plantillas de Laravel para que la plantilla de nuestro PDF sea representada por una vista de Laravel y así podamos trabajar con variables.

public function download()
{
    $data = [
        'titulo' => 'Styde.net'
    ];

    $pdf = \PDF::loadView('vista-pdf', $data);

    return $pdf->download('archivo.pdf');
}

En esta ocasión hacemos uso del Facade del paquete usando el alias PDF definido por paquete. Para generar un PDF a partir de una vista Blade usamos el método loadView el cual recibirá como primer parámetro la ubicación de nuestra vista Blade sin especificar la extensión. Como segundo parámetro pasamos un arreglo asociativo con los datos que queremos pasar a nuestra vista. En este ejemplo se especifica que la llave titulo tiene como valor 'Styde.net' y esto quiere decir que tendremos una variable en nuestra vista llamada $titulo con el valor antes mencionado.

Abrir documento en una nueva pestaña del navegador

Para evitar que el documento se descargue solo debemos cambiar el método download de nuestro ejemplo anterior por stream de esta forma:

public function download()
{
    $data = [
        'titulo' => 'Styde.net'
    ];

    return PDF::loadView('vista-pdf', $data)
        ->stream('archivo.pdf');
}

Cambiar la orientación de la hoja

En ocasiones es necesario cambiar la orientación de la hoja del documento. Por ejemplo, si deseamos mostrar una tabla con bastantes columnas será entonces una necesidad poder voltear la hoja.

public function download()
{
    $data = [
        'titulo' => 'Styde.net'
    ];

    return \PDF::loadView('vista-pdf', $data)
        ->setPaper('a4', 'landscape')
        ->download('archivo.pdf');
}

Con el método setPaper definimos en su primer parámetro el tamaño de la hoja, en Estados Unidos el estándar es letter mientras que en otro países generalmente es a4. Como segundo parámetro especificamos  landscape para cambiar su orientación.

Estamos concatenando métodos a una interfaz y esto se considera una interfaz fluida. Este tema se cubre en el Curso de programación orientada a objetos con PHP, específicamente en la lección Constructores semánticos e interfaces fluidas.

Saltos de página

Gracias a una clase de CSS este paquete nos ofrece la posibilidad de saltar de una hoja a otra. Solo debemos definir la clase CSS y usarla de esta forma en la vista a partir de la cual generamos el archivo PDF:

<style>
.page-break {
    page-break-after: always;
}
</style>

<h1>Pagina 1</h1>
<div class="page-break"></div>
<h1>Pagina 2</h1>

Agregar número de página

Podemos ejecutar un script PHP por cada hoja pero antes debemos activar esta opción en el archivo config/dompdf.php.

"enable_php" => true, // Por defecto esta en false

Al activar esta opción podemos definir un script de tipo "text/php" en nuestra vista el cual será ejecutado en todas las páginas. Este paquete nos ofrece algunas variables como $PAGE_NUM que nos entrega el número de la página actual mientras que $PAGE_COUNT nos muestra el total de páginas.

<style>
.page-break {
    page-break-after: always;
}
</style>

<h1>Pagina 1</h1>
<div class="page-break"></div>
<h1>Pagina 2</h1>

<script type="text/php">
    if ( isset($pdf) ) {
        $pdf->page_script('
            $font = $fontMetrics->get_font("Arial, Helvetica, sans-serif", "normal");
            $pdf->text(270, 730, "Pagina $PAGE_NUM de $PAGE_COUNT", $font, 10);
        ');
    }
</script>

Con el método text estamos posicionando el mensaje que queremos mostrar en todas las hojas. Este método recibe la posición en X del texto, la posición en Y, el texto, la fuente y finalmente el tamaño.

Guardar PDF en nuestro proyecto

En ocasiones puede ser útil guardar un PDF dentro de nuestro proyecto y para esto tenemos un par de opciones las cuales vamos a ver.

use Barryvdh\DomPDF\Facade as PDF;

public function download()
{
    $data = [
        'titulo' => 'Styde.net'
    ];

    $data = PDF::loadView('vista-pdf', $data)
        ->save(storage_path('app/public/') . 'archivo.pdf');
}

Con el método save del paquete especificamos la dirección junto con el nombre y la extensión podemos guardarlo. En el caso de que solo se coloque el nombre junto con la extensión será guardado en la carpeta public del proyecto.

La siguiente opción es utilizando el facade Storage de esta forma:

use Barryvdh\DomPDF\Facade as PDF;
use Illuminate\Support\Facades\Storage;

public function download()
{
    $data = [
        'titulo' => 'Styde.net'
    ];

    $content = PDF::loadView('vista-pdf', $data)->output();

    Storage::disk('public')->put('mi-archivo.pdf', $content);
}

Adjuntar PDF a un email

Puede existir la posibilidad de querer adjuntar un PDF a un correo electrónico. Podemos hacerlo y sin tener que guardarlo en alguna parte de nuestro sistema.

use Barryvdh\DomPDF\Facade as PDF;

$pdf = PDF::loadView('emails/templates/invoice-pdf', $data);

Mail::send('emails/templates/send-invoice', $messageData, function ($mail) use ($pdf) {
    $mail->from('[email protected]', 'John Doe');
    $mail->to('[email protected]');
    $mail->attachData($pdf->output(), 'test.pdf');
});

Agregar Header y Footer para todas las páginas

Por defecto el paquete tomará la etiqueta main como el contenido, mientras que las etiquetas header y footer serán colocadas para todas las páginas. A continuación vamos a ver cómo posicionarlos en sus respectivos lugares con CSS.

<html>
<head>
    <style>
        @page {
            margin: 0cm 0cm;
            font-family: Arial;
        }

        body {
            margin: 3cm 2cm 2cm;
        }

        header {
            position: fixed;
            top: 0cm;
            left: 0cm;
            right: 0cm;
            height: 2cm;
            background-color: #2a0927;
            color: white;
            text-align: center;
            line-height: 30px;
        }

        footer {
            position: fixed;
            bottom: 0cm;
            left: 0cm;
            right: 0cm;
            height: 2cm;
            background-color: #2a0927;
            color: white;
            text-align: center;
            line-height: 35px;
        }
    </style>
</head>
<body>
<header>
    <h1>Styde.net</h1>
</header>

<main>
    <h1>Contenido</h1>
</main>

<footer>
    <h1>www.styde.net</h1>
</footer>
</body>
</html>

El resultado de este ejemplo sería algo parecido a lo que se ve en la siguiente imagen:

pdf con header y footer usando Dompdf

Con esto terminamos, por favor comparte este tutorial gratuito con tus colegas y en tus redes sociales.

Suscríbete a nuestro boletín

Te enviaremos publicaciones con consejos útiles y múltiples recursos para que sigas aprendiendo.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.