mkebza/wk-pdf-bundle
A Laravel/PHP bundle that integrates wkhtmltopdf for generating PDFs from HTML views, giving you a simple wrapper to render templates, configure binary paths and options, and stream or save documents from your application.
wkhtmltopdf. Install the binary on every machine that will render PDFs (apt-get install wkhtmltopdf on Debian/Ubuntu, brew install wkhtmltopdf on macOS) and verify with wkhtmltopdf --version. Prefer the patched-Qt 0.12.6 build; the distro-packaged unpatched build silently drops flexbox and some CSS3 features.composer require mkebza/wk-pdf-bundle, then add the bundle class to config/bundles.php (there is no Flex recipe, so this is manual). Read DependencyInjection/Configuration.php and Resources/config/services.xml in the vendor directory before writing any code — that is where the real service id, config keys, and option pass-through live.config/packages/wk_pdf.yaml (or the key the extension actually defines). Point it at an absolute path; which wkhtmltopdf resolves differently under PHP-FPM than in your shell.Response with Content-Type: application/pdf and a Content-Disposition: attachment; filename="invoice-123.pdf" header. This is the 90% case and the fastest way to validate the whole chain end-to-end.Inject the service, don't fetch from the container. Type-hint the bundle's service in your controller or a dedicated InvoicePdfGenerator class. Wrapping it in your own interface from day one is the single highest-value decision here (see Gotchas).
Render HTML through Twig, not string concatenation.
$html = $this->twig->render('pdf/invoice.html.twig', ['invoice' => $invoice]);
$pdf = $this->wkPdf->generateFromHtml($html); // method name per vendor source
Keep a separate templates/pdf/ directory with a print-specific base layout: fixed-width body, explicit @page margins, no reliance on the app's JS bundle.
Streaming vs. persisting. For one-off downloads, write to a temp file (tempnam(sys_get_temp_dir(), 'pdf_')) and return a BinaryFileResponse with deleteFileAfterSend(true). For anything reused, store on a filesystem disk (S3/local) keyed by a content hash of the template data, and serve the cached artifact — regeneration is expensive and deterministic.
Push heavy renders to Messenger. wkhtmltopdf forks a WebKit process, burns CPU for 1–10 s, and blocks the FPM worker. Dispatch a GenerateInvoicePdf message, render in a worker, notify or email on completion. This also lets you set a longer timeout than your web request allows.
Batch generation. Reuse a single service instance across a loop rather than rebuilding it per item, and chunk large batches (hundreds of documents) into separate worker runs to avoid memory creep from orphaned wkhtmltopdf subprocesses.
Asset handling in templates. All CSS/images must be absolute URLs or file:// paths. When rendering from disk, you generally need the local-file-access flag (0.12.6 disabled it by default) or every local asset renders blank.
Header/footer and page options. Pass page size, margins, orientation, and header/footer HTML through the bundle's options array. Header/footer templates have their own restricted layout — they don't inherit the main document's CSS.
Integration with tests. Snapshot the HTML output separately from the PDF; asserting on PDF bytes is brittle. A small "golden HTML" fixture test catches template regressions without invoking the binary in CI.
barryvdh/laravel-dompdf, knplabs/knp-snappy (same wkhtmltopdf engine, framework-agnostic), or spatie/browsershot (Chromium — better modern CSS support). If you're bridging the two worlds, hide it behind your own PdfRenderer interface so the engine is swappable.composer.json, vendor-wrap the service, and keep knplabs/knp-snappy as a documented fallback. The migration cost is low precisely because the abstraction is thin.proc_open with an argument array. If the bundle builds a shell string internally, audit it before passing any user data.position: sticky, limited custom properties. Chromium-based renderers (browsershot, wkhtmltopdf's successor ecosystem) are the answer if your design needs it. Page breaks still use the deprecated page-break-before/after/inside properties.--javascript-delay and --no-stop-slow-scripts; even then, SPAs are a poor fit. Render server-side HTML instead.wkhtmltopdf and fonts into the image and assert --version in a health check; a silently missing binary looks identical to a broken template.pdf_url(); add a Messenger middleware for PDF jobs. All of these are cheaper than forking.wkhtmltopdf sometimes exits non-zero while producing a valid file (warnings about QFont or SSL). Check for file existence and non-zero size, not just the exit code — but log the stderr either way.How can I help you explore Laravel packages today?