nowo-tech / word-to-pdf-bundle
Symfony bundle: convert Microsoft Word (.docx/.doc) to PDF via LibreOffice Writer (soffice) with named profiles and runtime dependency checks.
Package info
github.com/nowo-tech/WordToPdfBundle
Type:symfony-bundle
pkg:composer/nowo-tech/word-to-pdf-bundle
Requires
- php: >=8.2 <8.6
- ext-fileinfo: *
- league/flysystem: ^3.16
- symfony/config: ^7.0 || ^8.0
- symfony/console: ^7.0 || ^8.0
- symfony/dependency-injection: ^7.0 || ^8.0
- symfony/http-foundation: ^7.0 || ^8.0
- symfony/http-kernel: ^7.0 || ^8.0
- symfony/process: ^7.0 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/extension-installer: ^1.0
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^11.0
- rector/rector: ^2.0
- symfony/framework-bundle: ^7.0 || ^8.0
- symfony/yaml: ^7.0 || ^8.0
Suggests
- nowo-tech/html-to-word-bundle: Optional: build .docx from HTML before converting to PDF.
- nowo-tech/word-template-bundle: Optional: fill .docx templates before converting to PDF.
README
Found this useful? Install from Packagist (
composer require nowo-tech/word-to-pdf-bundle) and consider starring WordToPdfBundle on GitHub.
Symfony bundle that converts Microsoft Word (.docx / .doc) to PDF using LibreOffice Writer (soffice headless) for print-quality layout fidelity:
- named YAML profiles + default profile + deep merge with per-call options, or
convertWithInlineProfile(); - batch conversion via
convertMany()withPdfNaming(keep / prefix / suffix / surround / fixed / callback, or path ⇒ filename map); - runtime check that LibreOffice Writer is installed (
nowo:word-to-pdf:check); fails with install hints if missing; - works under PHP-FPM and FrankenPHP (Symfony Process /
proc_open); - Symfony-friendly export: streamed/binary responses, local path, optional Flysystem.
This bundle does not fill Word templates (see WordTemplateBundle), convert HTML to Word (see HtmlToWordBundle), or use DomPDF (DomPDF cannot preserve Word styles).
Documentation
- Installation
- Configuration
- Usage
- Contributing
- Code of Conduct
- Changelog
- Upgrading
- Release
- Security
- Engram
- Spec-driven development
- GitHub Spec Kit
Additional documentation
- GitHub Actions CI requirements
- FrankenPHP / Docker demo —
demo/symfony8(seedemo/README.md)
System requirement
LibreOffice Writer must be installed on the host / container (Composer cannot install it):
# Debian / Ubuntu sudo apt-get install -y libreoffice-writer # Alpine apk add libreoffice # Fedora / RHEL sudo dnf install -y libreoffice-writer
Verify:
php bin/console nowo:word-to-pdf:check
Quick start
composer require nowo-tech/word-to-pdf-bundle php bin/console nowo:word-to-pdf:check
# config/packages/nowo_word_to_pdf.yaml nowo_word_to_pdf: default_profile: default profiles: default: timeout: 180 export: filename: document.pdf
Prefer the shared Nowo env (demos and multi-bundle apps):
timeout: '%env(int:PROCESS_TIMEOUT)%' # PROCESS_TIMEOUT=180 in .env
use Nowo\WordToPdfBundle\Converter\WordToPdfConverterInterface; use Nowo\WordToPdfBundle\Export\ExporterInterface; use Nowo\WordToPdfBundle\Naming\PdfNaming; public function download(WordToPdfConverterInterface $converter, ExporterInterface $exporter): Response { $pdf = $converter->convert('/path/to/contract.docx'); // Batch: $converter->convertMany([$pathA, $pathB], PdfNaming::suffix(' [converted]')); return $exporter->toBinaryResponse($pdf); }
FrankenPHP worker mode
FrankenPHP worker mode: Supported (tested with LibreOffice conversion under FrankenPHP).
The demo runs under FrankenPHP. Conversion uses Symfony Process with a hard timeout (and idle timeout); on expiry the runner stops the process tree so workers are not left with orphaned LibreOffice children (REQ-RUNTIME-001). Align PHP / Caddy deadlines above the profile timeout.
Demos use FRANKENPHP_MODE (worker by default, or classic) on PHP 8.5 — see docs/DEMO-FRANKENPHP.md. Change mode in .env and recreate containers (docker compose up -d); no image rebuild.
cd demo/symfony8 && cp .env.example .env && make up # Symfony 8, port 8022
Tests and coverage
| Scope | Detail |
|---|---|
| PHPUnit | composer test — unit + integration (@group libreoffice skipped when soffice is absent). |
| PHP lines | composer coverage-check enforces 100% (PCOV). Latest measurement: PHP: 100%. |
| TS/JS | N/A (no frontend assets in this bundle). |
composer test
composer coverage-check
Development
make up make qa make release-check