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 Generator Bundle Laravel Package

spraed/pdf-generator-bundle

Symfony bundle that turns Twig and HTML templates into PDFs using wkhtmltopdf, exposing a lightweight, configurable service API so you can render documents and return them as inline or downloadable responses with minimal setup in any Symfony project.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: this is a Symfony bundle, not a Laravel package. It ships a Bundle class, a DI extension, and an XML service definition — none of which Laravel's container will autoload. composer require spraed/pdf-generator-bundle inside a Laravel 9+ app will fight you on symfony/framework-bundle version constraints (the 2020 release caps at Symfony 5). Treat it as reference implementation for invoking Flying Saucer, not a drop-in dependency.

Three things to verify before writing any code:

  1. Java is installed and on PATH. Flying Saucer is a Java library; the bundle shells out to a JVM per render. java -version must succeed on every box, including queue workers and CI.
  2. Read DependencyInjection/Configuration.php. That file is the single source of truth for the config keys (binary, jar, tmp_dir or similar — the surface is small). If the keys don't match the README example, trust the Configuration class.
  3. Locate the jar under Resources/java/. If it isn't shipped, you must build or download the Flying Saucer + iText jar yourself — and that upstream project died with Google Code, so plan for an archived copy.

First use case: a server-side invoice or statement where you already have HTML/CSS and need pixel-stable A4 output with real page breaks, headers, and footers. Flying Saucer honours CSS 2.1 paged media (@page, size: A4, @bottom-center { content: counter(page) }), which is exactly the thing Dompdf and mPDF fumble. Render a Blade view to a string, hand it to the Java process, return a Content-Type: application/pdf response.

For a Laravel codebase, the cleanest first step is to skip the bundle and wrap the jar yourself with the Process component:

$html = view('invoices.pdf', $data)->render();
$tmp  = tempnam(sys_get_temp_dir(), 'pdf').'.html';
file_put_contents($tmp, $html);

Process::timeout(60)
    ->run(['java', '-Djava.awt.headless=true', '-jar', config('services.pdfgen.jar'), $tmp, $out]);

return response()->file($out)->deleteFileAfterSend();

Implementation Patterns

Render-to-string, then hand off. Never let the Java process fetch assets. Inline all CSS in a <style> block and convert images to absolute file:// paths or data: URIs. Your Blade view for PDF should have zero asset()/mix()/Vite calls — those produce URLs the JVM cannot resolve and you get silent missing logos.

Template split. Keep resources/views/pdf/*.blade.php separate from the web views. PDF views need table-based or float-based layout, explicit width in mm/pt, and a UTF-8 meta tag. Reusing web templates is the fastest route to a broken PDF.

Two output modes. Day-to-day you need exactly two: stream to browser (response()->file() / the bundle's generatePDF($html) cast to a Response) and persist to storage (Storage::disk('local')->put(...), then attach to a Mailable or queue a job). Model this as one small service class with render(string $html): string and renderToFile(string $html, string $path): void so controllers stay thin.

Merging documents. The bundle's selling point is generatePDFs(array $htmls) producing one concatenated PDF — useful for a cover page + invoice + terms in a single download. If you go the raw-jar route, either concatenate the HTML into one document with page-break-before: always between sections (simplest, preserves headers/footers) or merge with a separate library.

Queue it. A JVM cold start is roughly 1–3 seconds per document. For anything user-triggered at scale, dispatch a job, write to storage, and serve via signed URL. This also caps memory pressure and gives you retries.

Config. Put the jar path and Java binary in config/services.php (or a dedicated config/pdf.php), read from .env, and fail loudly at boot if is_file($jar) is false. A missing jar should be a deployment error, not a runtime 500 at 2 a.m.

Gotchas and Tips

  • CSS support is 2.1-era. No flexbox, no grid, no calc(), no CSS variables, no gap. If your design relies on Tailwind flex utilities, expect everything to stack. This is the single biggest source of "why does it look wrong" tickets.
  • Fonts must exist on the host. Flying Saucer resolves font-family against installed system fonts and any @font-face you point at a real file:// path. A font that renders in the browser and not in the PDF means it isn't installed on the server. Keep a curated set and fc-cache -f after adding.
  • Encoding. Declare <meta charset="utf-8"> and ensure the HTML is written as UTF-8 bytes. Otherwise curly quotes and accented names arrive as ?. Watch your Blade template file encodings too — Windows line endings plus BOM cause leading blank pages.
  • Temp files leak. Every render writes an HTML file and a PDF to tmp_dir. The bundle does not always clean up on exception. Set an app-specific tmp_dir, sweep it on a schedule, and never share a tmp_dir across parallel queue workers without unique filenames — concurrent renders in the same directory produce corrupt or mismatched output.
  • Debugging is blind by default. The wrapper converts Java stderr into a generic exception. Reproduce the failing render by running the exact java -jar ... command by hand; the JVM will tell you the real story (unresolved URI, missing font, XHTML parse error, OutOfMemoryError).
  • Strict XHTML. The parser rejects unclosed tags (<br>, <img>, <hr>) and unescaped & in text. Blade output from user data must be escaped — <br> for newlines, &amp; in addresses. Run templates through a strict validator if you keep getting parse exceptions.
  • Memory and concurrency. Each render forks a JVM with a default heap; a handful of parallel workers can OOM a small box. Pass -Xmx256m via the binary/options config and throttle the queue.
  • Abandonment risk is real. No dependents on Packagist, one release since 2020, upstream project dead. Pin the jar into your own repo, vendor it in storage/app/bin, and document the exact version. Don't rely on composer update to keep this working.
  • Escalation path. If you need modern CSS (flex, grid, web fonts, JS-rendered charts), the honest answer is Gotenberg or Browsershot — a headless Chromium renders your real HTML with your real assets. Keep Flying Saucer only if you specifically need fast, deterministic, low-memory paged output and your templates are already 2005-compatible.
  • Extension points. The jar path, Java binary, and temp directory are the only meaningful knobs; there is no plugin system. If you need custom behaviour, subclass or copy the generator rather than expecting hooks.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package