laravel

Crear PDF con Laravel

En este post te mostraré cómo crear o generar un PDF usando Laravel y las ventajas que nos ofrece este framework.

Vamos a usar la librería dompdf que, en combinación con Laravel y una librería extra, nos permitirá renderizar vistas de Blade y convertirlas a PDF de una manera realmente sencilla.

Asumo para este caso que ya sabes usar Laravel al menos de manera mínima, y que gestionas las dependencias de tu proyecto con composer.

También me gustaría recomendarte mi post sobre dompdf con php nativo; que si bien no es necesario, te ayudará a ver qué otras cosas puedes hacer. Entre los ejemplos está una factura con Bootstrap 3 o un ticket para impresora térmica.

Instalando soporte para dompdf

Vamos a usar la maravillosa envoltura creada por barryvdh que combinará las ventajas de Laravel con dompdf. Para ello instalamos con:

composer require barryvdh/laravel-dompdf

Ahora modificamos config/app.php y dentro del arreglo de providers agregamos:

Barryvdh\DomPDF\ServiceProvider::class,

Solo para ejemplificar, todo mi app.php queda así. Presta atención a la línea 169:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Application Name
    |--------------------------------------------------------------------------
    |
    | This value is the name of your application. This value is used when the
    | framework needs to place the application's name in a notification or
    | any other location as required by the application or its packages.
    |
    */
    'name' => env('APP_NAME', 'Laravel'),

    /*
    |--------------------------------------------------------------------------
    | Application Environment
    |--------------------------------------------------------------------------
    |
    | This value determines the "environment" your application is currently
    | running in. This may determine how you prefer to configure various
    | services the application utilizes. Set this in your ".env" file.
    |
    */
    'env' => env('APP_ENV', 'production'),

    /*
    |--------------------------------------------------------------------------
    | Application Debug Mode
    |--------------------------------------------------------------------------
    |
    | When your application is in debug mode, detailed error messages with
    | stack traces will be shown on every error that occurs within your
    | application. If disabled, a simple generic error page is shown.
    |
    */
    'debug' => env('APP_DEBUG', false),

    /*
    |--------------------------------------------------------------------------
    | Application URL
    |--------------------------------------------------------------------------
    |
    | This URL is used by the console to properly generate URLs when using
    | the Artisan command line tool. You should set this to the root of
    | your application so that it is used when running Artisan tasks.
    |
    */
    'url' => env('APP_URL', 'http://localhost'),

    'asset_url' => env('ASSET_URL', null),

    /*
    |--------------------------------------------------------------------------
    | Application Timezone
    |--------------------------------------------------------------------------
    |
    | Here you may specify the default timezone for your application, which
    | will be used by the PHP date and date-time functions. We have gone
    | ahead and set this to a sensible default for you out of the box.
    |
    */
    'timezone' => 'America/Mexico_City',

    /*
    |--------------------------------------------------------------------------
    | Application Locale Configuration
    |--------------------------------------------------------------------------
    |
    | The application locale determines the default locale that will be used
    | by the translation service provider. You are free to set this value
    | to any of the locales which will be supported by the application.
    |
    */
    'locale' => 'es',

    /*
    |--------------------------------------------------------------------------
    | Application Fallback Locale
    |--------------------------------------------------------------------------
    |
    | The fallback locale determines the locale to use when the current one
    | is not available. You may change the value to correspond to any of
    | the language folders that are provided through your application.
    |
    */
    'fallback_locale' => 'en',

    /*
    |--------------------------------------------------------------------------
    | Faker Locale
    |--------------------------------------------------------------------------
    |
    | This locale will be used by the Faker PHP library when generating fake
    | data for your database seeds. For example, this will be used to get
    | localized telephone numbers, street address information and more.
    |
    */
    'faker_locale' => 'en_US',

    /*
    |--------------------------------------------------------------------------
    | Encryption Key
    |--------------------------------------------------------------------------
    |
    | This key is used by the Illuminate encrypter service and should be set
    | to a random, 32 character string, otherwise these encrypted strings
    | will not be safe. Please do this before deploying an application!
    |
    */
    'key' => env('APP_KEY'),

    'cipher' => 'AES-256-CBC',

    /*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    |
    | The service providers listed here will be automatically loaded on the
    | request to your application. Feel free to add your own services to
    | this array to grant expanded functionality to your applications.
    |
    */
    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,

        /*
         * Package Service Providers...
         */
        Barryvdh\DomPDF\ServiceProvider::class,
        /*
         * Application Service Providers...
         */        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

    ],

    /*
    |--------------------------------------------------------------------------
    | Class Aliases
    |--------------------------------------------------------------------------
    |
    | This array of class aliases will be registered when this application
    | is started. However, feel free to register as many as you wish as
    | the aliases are "lazy" loaded so they don't hinder performance.
    |
    */
    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Arr' => Illuminate\Support\Arr::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Http' => Illuminate\Support\Facades\Http::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'Str' => Illuminate\Support\Str::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
    ],

];

Con esto basta. Ahora viene un paso importante y es que cada que necesitemos usar esta envoltura necesitaremos crear una instancia con App::make y para ello debemos indicar el uso del namespace al inicio del archivo, con:

use Illuminate\Support\Facades\App;

Eso es todo lo que necesitamos.

Generando PDF

Ahora podemos generar un PDF desde Laravel a partir de una vista de Blade. Un ejemplo básico es la siguiente vista:

<!doctype html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>PDF con Laravel</title>
</head>
<body>
<h1>Soy un título</h1>
<h2>El nombre es: {{$nombre}}</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Atque consectetur corporis deleniti dolore fugit incidunt
    magni nam, nesciunt nisi pariatur perferendis quam qui quisquam sit velit? Aspernatur debitis dolore maiores!</p>
</body>
</html>

En este caso solo estoy renderizando la variable $nombre pero se puede usar cualquier función de blade (@foreach, @if, etcétera). Además, no es necesario colocar todo el esqueleto, puedes heredar de vistas si quieres.

Ahora vamos a generar el PDF a partir de esta vista. Creamos la instancia, luego invocamos a loadView para cargar y renderizar la vista de Blade, pasándole datos y finalmente invocamos a stream para mostrarlo directamente en el navegador.

Lo he colocado en una ruta, pero tú puedes colocarlo dentro de un controlador o en donde mejor te convenga:

<?php
// ...
Route::get("test", function (Request $request) {
    $dompdf = App::make("dompdf.wrapper");
    $dompdf->loadView("ejemplo", [
        "nombre" => "Luis Cabrera Benito",
    ]);
    return $dompdf->stream();
});

Aquí vemos que estoy cargando la vista llamada ejemplo. En realidad el archivo se llama ejemplo.blade.php pero para cargarla desde Laravel solo se necesita el nombre (por cierto el archivo de la vista está en views).

Le pasamos las variables en un arreglo como segundo argumento y finalmente devolvemos el contenido del PDF para mostrarlo en el navegador.

PDF creado con Laravel

Otras opciones del PDF: guardar y descargar

Además de mostrar el PDF creado con Laravel en el navegador, podemos guardarlo en el disco duro o forzar su descarga.

Por ejemplo, para descargar el PDF invocamos al método download pasándole el nombre que queremos que se sugiera para el archivo:

<?php
$dompdf = App::make("dompdf.wrapper");
$dompdf->loadView("ejemplo", [
    "nombre" => "Luis Cabrera Benito",
]);
return $dompdf->download("mi_archivo.pdf");

Igualmente si quieres guardarlo en el disco duro, se puede hacer con:

<?php
$dompdf = App::make("dompdf.wrapper");
$dompdf->loadView("ejemplo", [
    "nombre" => "Luis Cabrera Benito",
]);
$dompdf->save("mi_archivo.pdf");
return "PDF guardado";

Nota: para este ejemplo, se guardará en public. También puedes especificar la ruta absoluta.

En este caso no podemos devolver el resultado de save, así que devuelvo una simple cadena, pero en tu caso puedes devolver lo que gustes, hacer un redirect, etcétera.

Conclusión

Vas a encontrar más ejemplos y documentación en el repositorio oficial. Recuerda que esta librería une a dompdf con Laravel, de una manera sencilla y rápida.

Como te mencionaba anteriormente, este fue un ejemplo sencillo. Puedes generar todo esto a partir de una base de datos, formularios, etcétera. La imaginación es el límite.

Para terminar, te invito a ver más tutoriales de Laravel en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

4 días hace

Esta web usa cookies.