Product Decisions This Supports
- Making document output a first-class roadmap feature. Any item that ends in "…and the customer gets a PDF" — invoices, statements, contracts, packing slips, compliance certificates, receipts, report exports — needs an engine decision behind it. This package is a candidate input to that decision, not the decision itself.
- Build vs. buy on document rendering. The alternative is a SaaS rendering API (DocRaptor, PDFreactor, Prince, Adobe PDF Services) at roughly $0.01–$0.10 per document. This package supports the "build" side by making the renderer a swappable dependency rather than an architectural commitment, which is the right way to frame the cost comparison to finance.
- Engine risk as an explicit design goal. Its only durable asset is the abstraction: one uniform API over wkhtmltopdf, TCPDF, and Zend PDF. That maps to a product principle — "we will not let our report templates be hostage to one renderer" — which is worth writing into the architecture decision record regardless of what we build.
- Migration sequencing. If documents already ship via wkhtmltopdf or TCPDF, an adapter layer lets us move templates to a modern renderer report by report instead of a big-bang rewrite — a scoping decision with real delivery-date impact.
- Fidelity vs. portability trade-off. It gives us a way to A/B the same template across engines and answer "how much layout fidelity do we actually pay for?" That is a scope question for design-heavy customer-facing documents, and it is cheaper to answer before committing to a renderer.
- Data residency and on-prem commitments. Self-hosted rendering supports enterprise or regulated deals where documents cannot leave the customer's network — a deal-qualification input, not just an engineering preference.
- Caveat that shapes all of the above: this is a Symfony bundle, not a Laravel package. In a Laravel codebase the leverage is the pattern, not the code. Every product decision below should be made against the pattern and priced as such.
When to Consider This Package
Consider it — more precisely, consider its pattern — when:
- You are on a Symfony/PHP stack that already uses wkhtmltopdf or TCPDF and want a thin uniform interface in front of it.
- You need multiple engines for genuine reasons: legacy templates that only render correctly in one engine, per-tenant renderer choice, or a staged migration.
- Volume is low to moderate and documents are internal or semi-structured: statements, exports, back-office reports.
- No external API calls are permitted, or per-document SaaS pricing is hard to justify at your volume.
- You want a small, MIT-licensed, dependency-light adapter you can vendor or copy outright.
Look elsewhere when:
- You are on Laravel. There is no service provider, no publishable config, no facade, no auto-discovery. Adopting it means owning a container bridge before delivering any value. Reimplement the interface over
spatie/laravel-pdf, barryvdh/laravel-dompdf, or knplabs/knp-snappy — roughly a day of work, and it removes a dependency you cannot get support for.
- Adoption signal matters. 2 stars, 0 dependents, composite score 0.17: no community, no issue triage, no CVE response path, no evidence it works with your PHP or framework version. Treat it as sample code.
- The bundled engines are a problem. wkhtmltopdf is archived/EOL with unreliable flexbox, grid, and web fonts; Zend PDF is a dead namespace; TCPDF is legacy-maintained with a large memory footprint. If the product needs modern HTML/CSS, this engine list is a liability.
- You need print-grade or accessible output: PDF/UA tagging, digital signatures, form fields, CMYK/print color. The TCPDF/FPDF family is weak across all of these.
- Volume or latency is a product requirement. Batch statement runs need queueing, concurrency caps, and a headless-Chrome or Gotenberg-class renderer, not a PHP-native one.
How to Pitch It (Stakeholders)
To executives: This is a small, MIT-licensed piece of plumbing that lets us generate customer documents — invoices, statements, contracts — without paying a per-document SaaS fee or locking into a single rendering vendor. The strategic value is the architecture, not the code: one internal interface with several engines behind it, so we can change renderers as costs or requirements shift. Two cautions. First, it is built for Symfony, not Laravel, so we would be buying a design rather than a working component. Second, its health signals are weak — 2 stars, no downstream users, one bundled engine at end of life. Recommendation: do not adopt it as a dependency. Take the pattern, own roughly 200 lines of interface and adapters ourselves, and treat the engine choice as its own roadmap decision. Budget one 1–2 day spike to confirm, and expect total cost of ownership to sit in operations — binary provisioning, queueing, and renderer debugging — not in the wrapper.
To engineering: The only durable idea here is a PdfRenderer contract — render(template, data, options): stream — with adapters for the engines we actually run. Copy that shape into our codebase, wire it to what we already use (or to Browsershot/Gotenberg if we want modern CSS), and cut the vendor dependency. Benefits: template portability, per-tenant renderer selection, and a clean seam for load testing and queueing. Risks to log now: abandoned upstream with no security patch path, no Laravel integration surface, wkhtmltopdf EOL, Zend namespace collisions, and an abstraction leak where engine-specific options (--dpi, margins, header/footer) bleed into the interface — keep those in an options bag and document the lowest common denominator. Operational realities to plan for: move all generation off the request path, instrument missing/misversioned binaries, orphaned child processes, font and glyph gaps that produce blank output while reporting success, memory_limit exhaustion on large TCPDF documents, and golden-file drift whenever a backend is swapped. Name a maintainer and write the runbook before the first production document ships.