Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pdf Bundle Laravel Package

siphoc/pdf-bundle

Siphoc PDF Bundle is a Symfony/PHP bundle that wraps wkhtmltopdf to generate PDFs from HTML strings or URLs. It provides service-based rendering, configurable binary paths and command options, and convenient streamed or downloadable responses for invoices, reports, tickets, and other printable docum...

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before you type composer require. This is a Symfony2 bundle, not a Laravel package. It ships a Symfony Bundle class, a DependencyInjection extension, and YAML service definitions — none of which Laravel's container will ever look at. Installing it in a Laravel app will either fail on symfony/symfony 2.x constraints or drag in an EOL framework you do not want in composer.lock. So "leveraging" it on a Laravel project means one of two things:

  1. Read it, don't install it. The bundle is a ~200-line adapter around a PHP PDF engine (historically dompdf/TCPDF). Its value to you is as a reference shape: how to bind a renderer into a container, how to expose paper/orientation options, how to return a streamed response.
  2. Pull in the engine it wraps, directly. In Laravel you'd composer require dompdf/dompdf (or mPDF/TCPDF) and write the ~30 lines of glue yourself.

Minimal setup (the realistic path):

composer require dompdf/dompdf

config/app.php (or bootstrap/providers.php on Laravel 11+):

App\Providers\PdfServiceProvider::class,
// app/Providers/PdfServiceProvider.php
public function register(): void
{
    $this->app->singleton(PdfRenderer::class, fn () => new DompdfRenderer([
        'defaultFont'   => 'DejaVu Sans',
        'isRemoteEnabled' => false, // keep off unless you truly need remote assets
    ]));
}

First use case — invoice/receipt streamed from a controller:

public function show(Invoice $invoice, PdfRenderer $pdf)
{
    $html = view('pdf.invoice', ['invoice' => $invoice])->render();
    $bytes = $pdf->render($html);

    return response()->streamDownload(
        fn () => print($bytes),
        "invoice-{$invoice->number}.pdf",
        ['Content-Type' => 'application/pdf']
    );
}

If you're porting an existing Symfony2 app that already uses this bundle, look first at DependencyInjection/Configuration.php and Resources/config/services.yml — that tells you the exact engine and option keys you need to reproduce before you rip the bundle out.

Implementation Patterns

  • One small interface, one implementation. This is the single most important habit if you're touching legacy Symfony code. Define App\Contracts\PdfRenderer with render(string $html): string, bind it in a provider, and never let Dompdf\Dompdf leak into controllers. When you later switch to Gotenberg/Browsershot, only the binding changes.

  • Dedicated Blade templates for print. Keep resources/views/pdf/*.blade.php separate from your web views. dompdf supports a small fraction of CSS (no flexbox, no grid, limited @media), so sharing markup with the web UI forces compromises in both directions. Pass explicit data via view('pdf.invoice', [...])->render(); avoid view composers and global shares that assume a request context.

  • A wrapper with three output modes. Mirror the bundle's intent — generate once, then stream(), download(), or save():

class InvoiceDocument
{
    public function __construct(private PdfRenderer $pdf, private Invoice $invoice) {}

    public function save(string $path): string
    {
        $bytes = $this->pdf->render(view('pdf.invoice', ['invoice' => $this->invoice])->render());
        Storage::disk('documents')->put($path, $bytes);
        return $path;
    }
}
  • Queue the batch jobs. Nightly statements, tickets, mailing lists — dispatch a GenerateStatements job per chunk (or a single job with ShouldQueue + $timeout = 300). PHP-FPM will 504 on a 200-page render otherwise. Write to Storage, then serve via a signed URL rather than regenerating on every download.

  • Per-document options, not global config. The bundle's classic weakness is that the service is bound to one paper size. In Laravel, pass options per call:

$pdf->render($html, ['paper' => 'a4', 'orientation' => 'portrait', 'margin' => 20]);
  • Console command for bulk/regeneration. php artisan pdf:regenerate --month=2024-01 using the injected renderer is how you backfill after a template change — and it's trivially testable compared to hitting a controller.

  • Cache the rendered output keyed on template + data hash. PDF rendering is CPU-bound; a 50-line Blade partial change shouldn't invalidate every invoice in the database.

  • Test what you can test. Don't assert on PDF bytes. Assert that the template renders with expected data ($this->assertStringContainsString('€49.00', $html)), and that your controller returns application/pdf with the right Content-Disposition. Add one smoke test that a real PDF is produced and starts with %PDF-.

Gotchas and Tips

  • You cannot install this bundle in Laravel. Composer constraints will conflict or succeed-but-uselessly. Treat it as read-only documentation of the dompdf integration pattern. If you inherit a Symfony2 service that uses it, the correct move is the interface-and-replace sequence, not a re-install.

  • Identify the engine before anything else. Its license, CVE history, and PHP 8 compatibility are the risk, not the bundle's 200 lines of DI glue. If it's TCPDF, check licensing and Unicode/font handling carefully for anything customer-facing.

  • dompdf's CSS support is the #1 source of "it looks wrong" tickets. No flexbox, no grid, unreliable float, no CSS variables, limited @page. Design with tables and explicit widths, and open the Blade output in a browser first — iterating on HTML is 50× faster than re-rendering PDFs.

  • Fonts and Unicode. Default fonts mangle €, ≥, and non-Latin scripts. Bundle a TTF (storage/fonts/DejaVuSans.ttf) and register it, or you'll discover this on the first German invoice. Same for right-to-left content.

  • Memory and timeouts. Large documents blow past memory_limit. Set ini_set('memory_limit', '512M') in the job (not globally), and prefer ->output() over chained calls in a loop — the dompdf instance is not free of retained state, so construct a fresh renderer per document in batch jobs.

  • isRemoteEnabled is a footgun. It's off by default for a reason; turning it on with user-controlled HTML is SSRF. Convert images to absolute local paths or data URIs before rendering.

  • Don't echo HTML into streamDownload. Capture the bytes into a variable and print inside the closure; otherwise the callback runs after the container tears down and you get half a PDF.

  • Response headers. Content-Disposition: attachment for downloads, inline for previews. Missing Content-Length causes truncated downloads behind some proxies — pass it explicitly.

  • Extension point to keep. If you ever do reintegrate with the Symfony side of an estate, keep the renderer binding behind your own contract. That single decision means the framework version stops mattering for document generation.

  • Watch the abandoned-dependency signal. 14 stars, zero dependents, no commits — assume no upstream fixes. Pin the engine version in composer.json, run composer audit in CI, and keep a ticket open to move rendering to an out-of-process service (Gotenberg / headless Chromium) once volume or fidelity requirements grow.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle