Kenalan dengan Laravel Snappy PDF
TutorialLaravelPHP#laravel#php#tutorial#backend

Kenalan dengan Laravel Snappy PDF

A
Abd. Asis
Bagikan:

Kebutuhan generate PDF dari aplikasi Laravel hampir selalu muncul cepat atau lambat: invoice untuk checkout, laporan keuangan bulanan, sertifikat, atau surat resmi yang harus dicetak. Masalahnya, banyak library PDF memaksa kamu menggambar layout manual baris demi baris — pengalaman yang mirip menulis PostScript di tahun 90-an. Laravel Snappy menawarkan jalan yang lebih manusiawi: tulis HTML dan CSS seperti biasa, lalu biarkan wkhtmltopdf mengubahnya menjadi PDF berkualitas cetak.

Artikel ini akan mengenalkan Snappy dari nol — apa bedanya dengan alternatif lain, cara memasang binary wkhtmltopdf, sampai contoh pembuatan invoice sederhana dari Blade view.

Apa itu Laravel Snappy

Snappy adalah wrapper Laravel di atas library PHP KnpSnappy yang di-maintain oleh Barry vd. Heuvel. Intinya, Snappy meneruskan HTML ke binary wkhtmltopdf — sebuah tool command-line yang menggunakan engine WebKit untuk me-render halaman web menjadi file PDF. Karena rendering-nya memakai browser engine asli, hasil akhirnya sangat mirip dengan tampilan di Chrome atau Safari: CSS modern, font kustom, dan bahkan gambar remote semuanya didukung.

Ada dua alternatif populer di ekosistem Laravel: dompdf dan mPDF. Keduanya adalah pure-PHP, jadi tidak butuh binary tambahan, tapi trade-off-nya adalah dukungan CSS yang terbatas dan rendering yang kadang meleset dari ekspektasi. Snappy menang di sisi fidelity tapi kalah di sisi deployment — kamu harus memastikan wkhtmltopdf terpasang di server.

LibraryEngineDukungan CSSDependency
barryvdh/laravel-snappywkhtmltopdf (WebKit)Sangat baikBinary eksternal
barryvdh/laravel-dompdfDompdf (PHP)TerbatasHanya Composer
mpdf/mpdfmPDF (PHP)SedangHanya Composer

Kalau dokumenmu sederhana dan server-nya shared hosting, dompdf sudah cukup. Pilih Snappy ketika layout butuh CSS modern seperti flexbox, grid, atau font custom yang harus terlihat presisi.

Memasang wkhtmltopdf

Sebelum menginstal package Laravel-nya, siapkan dulu binary wkhtmltopdf. Cara paling mudah di lingkungan development Linux adalah lewat package manager, tapi versi yang disediakan distribusi kadang tertinggal jauh. Unduh versi resmi dari situs wkhtmltopdf untuk memastikan kompatibilitas dengan Snappy.

Setelah binary terpasang, verifikasi dari terminal:

BashBASH
wkhtmltopdf --version

Outputnya kira-kira seperti ini:

CodeCODE
wkhtmltopdf 0.12.6 (with patched qt)

Catat path binary dengan perintah which wkhtmltopdf — kita butuh path ini nanti saat mengisi config.

Versi wkhtmltopdf di repository Ubuntu/Debian sering kali tidak di-patch dengan Qt, yang artinya fitur penting seperti header, footer, dan page break tidak berjalan dengan benar. Selalu pakai build resmi dari situs wkhtmltopdf untuk produksi.

Instalasi Laravel Snappy

Pasang package via Composer di project Laravel-mu:

BashBASH
composer require barryvdh/laravel-snappy

Laravel 5.5 ke atas sudah mendukung package auto-discovery, jadi ServiceProvider-nya akan otomatis terdaftar. Berikutnya, publish file konfigurasi default:

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

Perintah ini akan membuat file config/snappy.php. Buka file tersebut dan pastikan path binary yang kamu catat tadi sudah benar:

PHPPHP
// config/snappy.php

return [
    'pdf' => [
        'enabled' => true,
        'binary'  => '/usr/local/bin/wkhtmltopdf',
        'timeout' => false,
        'options' => [],
        'env'     => [],
    ],
    'image' => [
        'enabled' => true,
        'binary'  => '/usr/local/bin/wkhtmltoimage',
        'timeout' => false,
        'options' => [],
        'env'     => [],
    ],
];

Kunci utamanya adalah field binary — ini harus mengarah ke eksekutabel wkhtmltopdf yang aktif. Di server produksi, sebaiknya simpan path ini sebagai environment variable supaya bisa berbeda antara lokal dan production.

Membuat Invoice PDF dari Blade

Skenario paling umum: kamu punya data order dan ingin mengirim PDF invoice ke pelanggan. Mulai dari route sederhana yang menerima ID order, lalu teruskan ke controller yang me-render Blade view menjadi PDF.

PHPPHP
// routes/web.php

use App\Http\Controllers\InvoiceController;

Route::get('/orders/{order}/invoice', [InvoiceController::class, 'download'])
    ->name('orders.invoice');

Lanjut ke controller. Di sini kamu memanfaatkan facade PDF (alias dari Barryvdh\Snappy\Facades\SnappyPdf) untuk memuat view dan langsung men-download hasilnya.

PHPPHP
// app/Http/Controllers/InvoiceController.php

namespace App\Http\Controllers;

use App\Models\Order;
use Barryvdh\Snappy\Facades\SnappyPdf as PDF;

class InvoiceController extends Controller
{
    public function download(Order $order)
    {
        $invoice = PDF::loadView('invoices.template', [
            'order'      => $order->load('items', 'customer'),
            'issuedAt'   => now(),
        ]);

        $invoice->setPaper('a4')
            ->setOption('margin-top', '15mm')
            ->setOption('margin-bottom', '15mm');

        return $invoice->download("invoice-{$order->id}.pdf");
    }
}

Perhatikan tiga hal penting dari method download di atas. Pertama, loadView menerima nama Blade view dan array data — sama persis seperti memanggil view() biasa. Kedua, setPaper dan setOption memungkinkan kamu mengatur ukuran kertas dan margin dengan satuan yang familiar seperti mm. Ketiga, method download mengembalikan response HTTP yang memaksa browser menyimpan file dengan nama yang ditentukan.

Sekarang buat Blade template-nya. Snappy me-render HTML ini melalui WebKit, jadi kamu bebas memakai CSS modern.

Laravel BladeBLADE
{{-- resources/views/invoices/template.blade.php --}}

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Invoice #{{ $order->id }}</title>
    <style>
        body { font-family: 'Helvetica', sans-serif; color: #1f2937; }
        .header { display: flex; justify-content: space-between; margin-bottom: 32px; }
        .title { font-size: 28px; font-weight: 700; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 8px 12px; border-bottom: 1px solid #e5e7eb; text-align: left; }
        .total { font-weight: 700; text-align: right; margin-top: 16px; }
    </style>
</head>
<body>
    <div class="header">
        <div>
            <div class="title">INVOICE</div>
            <div>#{{ str_pad($order->id, 6, '0', STR_PAD_LEFT) }}</div>
        </div>
        <div>{{ $issuedAt->format('d M Y') }}</div>
    </div>

    <p>Ditagihkan kepada: <strong>{{ $order->customer->name }}</strong></p>

    <table>
        <thead>
            <tr>
                <th>Produk</th>
                <th>Qty</th>
                <th>Harga</th>
                <th>Subtotal</th>
            </tr>
        </thead>
        <tbody>
            @foreach ($order->items as $item)
                <tr>
                    <td>{{ $item->name }}</td>
                    <td>{{ $item->quantity }}</td>
                    <td>Rp {{ number_format($item->price, 0, ',', '.') }}</td>
                    <td>Rp {{ number_format($item->subtotal, 0, ',', '.') }}</td>
                </tr>
            @endforeach
        </tbody>
    </table>

    <div class="total">
        Total: Rp {{ number_format($order->total, 0, ',', '.') }}
    </div>
</body>
</html>

Setelah semuanya siap, kunjungi /orders/1/invoice di browser. Snappy akan memproses Blade view di atas, meneruskan HTML hasil render ke wkhtmltopdf, dan mengirim file PDF kembali ke browser sebagai attachment.

Menyimpan atau Menampilkan Inline

Tidak selalu kamu ingin memaksa download. Kadang PDF perlu disimpan ke storage untuk diarsipkan, atau ditampilkan langsung di tab browser sebagai preview. Snappy menyediakan method yang berbeda untuk setiap kasus ini.

PHPPHP
// simpan ke storage
$invoice->save(storage_path("app/invoices/{$order->id}.pdf"));

// tampilkan inline di browser
return $invoice->inline("invoice-{$order->id}.pdf");

// ambil sebagai string biner untuk dikirim via email
$binary = $invoice->output();

Method output sangat berguna ketika kamu mengirim PDF sebagai attachment email lewat Mailable. Kamu tinggal memanggilnya di dalam method build dan melampirkan hasilnya dengan attachData.

Catatan Penting untuk Produksi

Dua gotcha yang paling sering menjegal developer saat memakai Snappy di server produksi. Pertama, wkhtmltopdf membutuhkan akses ke file system yang bisa dieksekusi — kalau aplikasi di-deploy di container, pastikan binary ikut masuk ke image Docker. Solusi praktis adalah memakai base image yang sudah menyertakan binary, atau pasang saat build dengan perintah seperti apt-get install wkhtmltopdf.

Kedua, rendering PDF adalah proses yang berat secara CPU dan bisa memakan beberapa detik per dokumen. Untuk dokumen dengan banyak halaman atau gambar, jalankan generation-nya di queue job, bukan di request lifecycle. Teknik ini mirip pola yang dibahas di Clean Code Laravel dengan Service Action Pattern — pisahkan logic berat ke action yang bisa dipanggil dari job.

Jangan pernah meneruskan input pengguna langsung ke loadHTML tanpa sanitasi. wkhtmltopdf akan mengeksekusi JavaScript dan memuat resource eksternal dari HTML yang diberikan, yang berpotensi menjadi vektor SSRF jika kontennya tidak dikontrol.

Kesimpulan

Laravel Snappy adalah pilihan pragmatis ketika kamu butuh PDF berkualitas tinggi tanpa harus belajar API low-level yang asing. Dengan menulis HTML dan CSS biasa, kamu bisa menghasilkan invoice, laporan, atau sertifikat yang terlihat sama persis dengan preview browser — asal kamu siap mengelola binary wkhtmltopdf di lingkungan deploy. Langkah berikutnya yang layak dicoba: pindahkan generation ke queue, eksperimen dengan header dan footer lewat opsi header-html, dan integrasikan dengan storage cloud untuk menyimpan arsip dokumen.

Referensi

  1. 1 Repository Resmi barryvdh/laravel-snappy di GitHub
  2. 2 Situs Resmi wkhtmltopdf
  3. 3 KnpLabs Snappy — Library PHP yang Mendasari Laravel Snappy
Abd. Asis
Ditulis oleh
Abd. Asis

Software Developer dari Madura. Menulis tentang PHP, Laravel, dan pengembangan web modern dalam Bahasa Indonesia.