nowo-tech/word-to-pdf-bundle
A Symfony bundle for converting Word documents to PDF. It provides a simple service and configuration to turn .doc and .docx files into PDFs within your PHP application, making it easy to generate PDFs from uploaded or stored Word documents.
Architecture fit. nowo-tech/word-to-pdf-bundle is a Symfony bundle, not a Laravel package. Its value proposition is thin glue: a DI extension, a config tree, and a service that shells out to LibreOffice Writer in headless mode (soffice --headless --convert-to pdf) to render .doc/.docx with print-quality fidelity. For a Laravel codebase the bundle packaging is dead weight — Laravel has no bundle registration, compiler passes, or Configuration tree — and the only reusable asset is the conversion service itself. Fit therefore hinges on one unverified question: is the converter service framework-agnostic (constructor-injected binary path, timeout, temp directory; returns a path or stream), or is it coupled to Symfony HttpFoundation responses, Filesystem, or event dispatchers? If the former, it is effectively a small library wearing a bundle costume and can be adopted; if the latter, adoption means a fork or an adapter, which changes the cost calculus materially. For a Symfony shop the fit is natural and low-friction; for a Laravel-first stack it is a deliberate, small extraction project.
Integration feasibility. Composer installation is trivial; the runtime dependency is not. The host — container, VM, or serverless image — must ship LibreOffice Writer plus a coherent font set (Calibri/Cambria are absent by default and will silently substitute, shifting pagination and line breaks; Carlito/Caladea are the metric-compatible stand-ins). That typically means a 500 MB–1.5 GB image layer, a longer CI build, and a pinning strategy so output does not drift when the distro updates LibreOffice. Conversion is CPU-bound and process-spawning; it does not belong in a request/response cycle for anything above toy volume. The package targets PHP ≥8.2 and Symfony 7/8, which is compatible with current Laravel (11/12) at the PHP level but risks Composer conflict if the bundle's require pulls symfony/framework-bundle or constrains symfony/* components more tightly than Laravel's own pins — verify with a dry-run install before committing.
Technical risk. High, and mostly not about code quality:
| Risk | Severity | Notes |
|---|---|---|
| Maturity / adoption | High | 0 stars, 0 dependents, no ecosystem validation. Effectively unproven in production. |
| Bus factor | High | Single-maintainer pattern typical of nowo-tech/*; assume you may need to vendor or fork. |
| Security surface | High | LibreOffice parsing untrusted Office XML is a documented attack surface (macro execution, XXE in OOXML, zip bombs, memory-corruption CVEs). Any user-supplied upload path needs sandboxing, size caps, and macro-disabled profiles. |
| Release anomaly | Medium | "Last release 2026-10-13" is a future date relative to typical evaluation windows — likely a mistagged or pre-dated release. Treat the version history as unverified until confirmed on Packagist. |
| Output fidelity | Medium | Headless rendering is not byte-identical to Word; complex layouts, embedded fonts, tracked changes, and footnotes can shift. Acceptable for many use cases, disqualifying for contractual/regulatory document generation. |
| Operational coupling | Medium | You inherit LibreOffice lifecycle management (zombie soffice processes, profile lock contention, temp-dir growth) — not visible from the package API. |
Licensing is clean: MIT for the package, MPL for LibreOffice, no copyleft propagation into your application. Font licensing (Microsoft core fonts) is the only legal wrinkle worth a look if you redistribute the image.
Key questions to resolve before any commitment.
-env:UserInstallation profile dirs — does the package handle this, or will concurrency silently serialize or fail?Stack fit. Frame the decision honestly for stakeholders: this is not "a Laravel package we can install," it is "a Symfony bundle containing a LibreOffice wrapper we may be able to reuse." Two viable paths, and one that should be the default comparison:
DocumentConverter interface in the Laravel container; implement it with the package's service (or a thin subclass/fork). All application code depends on the interface, never the package. This buys optionality at near-zero cost.new Converter($binaryPath, $timeout, $tempDir)).Migration path. There is nothing to migrate from unless you currently shell out to soffice ad hoc or rely on a SaaS converter. If a SaaS (CloudConvert, DocRaptor) is in place, the migration is a cost/latency trade: self-hosting removes per-page fees and data-egress concerns but transfers LibreOffice operations onto your team. If you are on Word automation via COM or a Windows worker, this is a genuine improvement (no Windows licensing, no Office install) — that is the strongest migration story here.
Compatibility. Confirm three things concretely in a scratch branch: (1) composer require resolves against your Laravel version's symfony/* pins without conflict; (2) the package runs on your PHP 8.2/8.3/8.4 target with no deprecation noise; (3) the LibreOffice version in your base image produces acceptable output for your real document corpus — tested against fixtures, not a hello-world .docx. Treat the Symfony 7/8 targeting as a signal the package is new, not as evidence it is stable.
Sequencing.
.doc legacy file, a heavily formatted report, and a corrupt/password-protected file. Capture latency, peak memory, and output diffs.DocumentConverter::convert(UploadedFile|string $path): ConversionResult. Implementation detail is swappable; add a fake for tests.Maintenance. The dominant maintenance cost is not the PHP package — it is the LibreOffice runtime. Pin the image digest and the LibreOffice version; re-run your fixture corpus whenever either changes, because minor LibreOffice releases have historically altered layout output. The package itself is small enough to vendor into app/Support/ or fork under your own namespace if the upstream goes quiet, which given 0 stars and 0 dependents is a scenario to plan for rather than hope against. Budget a few hours per quarter for dependency bumps; near-zero for feature work, since the API surface is one method.
Support. There is no community to lean on: no issues history, no Stack Overflow corpus, no downstream users to observe. Your team becomes the de facto maintainer and the first line of support. Mitigate by writing a short runbook at adoption time covering binary path configuration, font installation, profile-directory contention, and the "conversion hung, kill the worker" procedure — this is cheap now and expensive to reconstruct during an incident.
Scaling. Conversion is CPU-bound and memory-hungry: expect roughly 1–3 s and 150–400 MB peak RSS per document depending on size, images, and page count — validate with your own corpus, do not trust the estimate. Scale horizontally with queue workers and replica count, not with in-process parallelism. Critically, concurrent soffice invocations need separate user-profile directories (-env:UserInstallation=file:///tmp/lo-<uuid>); without that, invocations contend on the profile lock and either serialize unpredictably or fail. Cap worker concurrency per host at roughly one conversion per vCPU and leave headroom — a saturated host makes every conversion slower, not just the extra one. If throughput requirements exceed a handful per minute, a pooled Gotenberg deployment is the more defensible architecture and this package becomes a fallback rather than a foundation.
Failure modes to design for explicitly.
proc_terminate then SIGKILL, and a reaper for orphaned processes.Ramp-up. Developer ramp-up is genuinely low: one interface, one method, a handful of config values — a competent Laravel engineer is productive in half a day. Operational ramp-up is moderate and is where the real cost sits: containerizing LibreOffice with correct fonts, tuning worker concurrency, writing the runbook, and building the fixture corpus for regression testing. Allocate roughly a week of combined engineering and ops effort for a production-grade rollout, and treat the package evaluation itself as a two-day spike with a pre-agreed fallback (Gotenberg) — at 0 stars and 0 dependents, the disciplined position is "promising component, unproven dependency; adopt behind an abstraction with an exit already priced in."
How can I help you explore Laravel packages today?