pontedilana/weasyprint-bundle
Symfony bundle that integrates WeasyPrint to turn HTML and CSS into high-quality PDFs. Render Twig templates through a simple service, with configurable binary path and clean Symfony integration for invoices, reports, and printable documents.
Framing correction (blocking, unchanged by 3.1.0): The premise describes this as a Laravel/PHP package. It is not. pontedilana/weasyprint-bundle is a Symfony bundle — it ships a DependencyInjection/Extension, a Configuration tree, and autowired services intended to be registered in a Symfony kernel. Laravel will not discover or boot it. Any "integration" in a Laravel codebase is a DIY adapter, not a package install. This reframes the decision from "adopt a library" to "reference an implementation." Nothing in 3.1.0 changes this.
Architecture fit
symfony/process, with Twig rendering HTML upstream of the call. Roughly: render template → write temp HTML → shell out → return PDF bytes.php-weasyprint (the underlying library), and the WeasyPrint binary must now all be version-aligned. Two of the three release-note items are explicitly gated on php-weasyprint versions (2.5.1+ for ExecutableFinder path resolution, 2.6+ for allowed_schemes). This is no longer a two-body problem.symfony/process invocation), treat this repo as a reference design, not a dependency.Integration feasibility
symfony/process is already a transitive Laravel dependency, so the process layer costs nothing new. The real cost is the system runtime: Python 3, WeasyPrint, plus native libraries (Pango, HarfBuzz, fontconfig, GDK-Pixbuf, cffi/pydyf). This is a container-image problem, not a Composer problem.symfony/http-foundation, symfony/http-kernel, and symfony/process versions to patched releases — correct for Symfony shops, but it further narrows the already-unlikely intersection with a given Laravel version's pinned Symfony set. Expect conflicts; the upgrade makes the install path marginally worse, not better.Technical risk
php-weasyprint version. pdf.allowed_schemes is accepted by config but inert below php-weasyprint 2.6 — a security control that no-ops without error is worse than no control, because it manufactures false assurance. Similarly, ExecutableFinder behavior differs at 2.5.1. Mitigation: assert the resolved library and binary versions at boot and fail fast.allowed_schemes knob is the right shape of control, but it is scheme-level only, it must be explicitly configured, and the default posture should be assumed unchanged. Restricting to file/data only breaks legitimate remote CSS/image/font references, so most teams will allowlist https and remain exposed to remote-fetch stalls and internal-address probing. Egress-block the worker network namespace regardless; treat allowed_schemes as defense in depth, not the primary control.process_timeout: false disables the generator timeout entirely. This is a legitimate escape hatch for queue workers governed by an external supervisor timeout, and a production hazard everywhere else. It must be forbidden on any synchronous request path and permitted only with a documented outer timeout.pdf.binary via PATH improves DX but makes the invoked interpreter/binary a function of the worker's environment — which can differ between web and queue containers, or change silently on image rebuild. Absolute paths are still used as-is; production config should use them.Key questions
allowed_schemes, do our templates need remote https resources — and if so, is egress already locked down?php-weasyprint / WeasyPrint versions at boot, given the silent-no-op behavior below 2.6?Stack fit
spatie/browsershot or a hosted API (DocRaptor, PDFShift) has materially lower TCO.Migration path (Laravel)
Process::run('weasyprint ...') from an artisan command. Measure latency, memory, and fidelity. Gate everything on this.app/Services/Pdf/WeasyPrintDriver.php behind a PdfRenderer contract; render Blade → temp file → symfony/process → validate %PDF magic bytes → cleanup.php-weasyprint-equivalent behavior and binary version are what config assumes. This is the single highest-value lesson from 3.1.0: never let a security or timeout setting degrade silently.WeasyPrint service class if its argument/flag handling is worth keeping; do not register it via Composer.php-weasyprint bump and a Symfony patch-level floor — treat all three as one tested change.Compatibility
composer.json PHP and symfony/* constraints against the target Laravel version before assuming installability. 3.1.0's raised Symfony minimums increase the chance of conflict; prefer avoiding the install entirely.php-weasyprint upgrades as a tested change, not a rebuild side effect.allowed_schemes is actually honored (i.e., that the underlying library is ≥2.6).Sequencing
Infra (Python runtime, fonts, network egress lockdown) → feasibility spike → PdfRenderer contract + driver (scheme allowlist, absolute binary, explicit timeout, boot-time version assertion) → queue worker + retry/timeout policy → golden-file visual regression tests → cutover.
Maintenance
Support
php-weasyprint releases and security patches. Weigh that positively, but it does not constitute a support commitment.Scaling
Failure modes to instrument
allowed_schemes set but underlying library < 2.6) → security posture believed-but-not-applied; assert versions at boot, alarm on drift.process_timeout: false leaking into a request path → unbounded worker occupancy and queue collapse; lint config in CI and require an external supervisor timeout wherever the generator timeout is disabled./tmp accumulation → always unlink in finally; alert on disk pressure.%PDF header and page count before persisting.Ramp-up
@page rules, margin boxes, counters, break-inside, widow/orphan control) — this is the real skill gap, and it is unrelated to the bundle.PdfRenderer interface — but the Symfony framing, bus-factor-one maintenance, and three-way version coupling all stand. Build in-house, or choose Chromium/headless or a managed API if the Python runtime footprint is unacceptable.How can I help you explore Laravel packages today?