Search by

nowo-tech / word-to-pdf-bundle

HecFranco

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

Statistics

Installs: 1 320

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.7.1 2026-11-12 11:09 UTC

README

CI Packagist Version Packagist Downloads License PHP Symfony GitHub stars Coverage

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() with PdfNaming (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).

FrankenPHP demos: runtime is selected with FRANKENPHP_MODE (worker default, or classic for per-request PHP / hot-reload). See docs/DEMO-FRANKENPHP.md.

FrankenPHP Friendly Worker Mode

This bundle is FrankenPHP worker mode friendly.

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

See docs/DEMO-FRANKENPHP.md.

use Nowo\WordToPdfBundle\Converter\WordToPdfConverterInterface;
use Nowo\WordToPdfBundle\Http\PdfResponseFactory;
use Nowo\WordToPdfBundle\Naming\PdfNaming;

public function download(WordToPdfConverterInterface $converter, PdfResponseFactory $responses): Response
{
    $pdf = $converter->convert('/path/to/contract.docx');
    // Batch: $converter->convertMany([$pathA, $pathB], PdfNaming::suffix(' [converted]'));

    return $responses->binaryFile($pdf); // outside HTTP: PdfWriterInterface::toBytes() / toFile() / toFlysystem()
}

Both host kinds are supported: see Standard Symfony host (zero config) and DDD / hexagonal host (framework-free PdfWriterInterface).

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

Development

make up
make qa
make release-check

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. Compatible with kernel reset false (FRANKENPHP_RESET_KERNEL unset/false, also without services_resetter; worker test WorkerKeptAliveKernelTest) — see docs/FRANKENPHP-WORKER-AUDIT.md.

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

Documentation

Additional documentation

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).
Python make test-python — pytest for the demo fixture generator demo/symfony8/bin/generate-stress-docx.py, gate 90% lines (pytest.ini). Latest measurement: Python: 99.54%.

Excluded PHP branches (@codeCoverageIgnore) are listed one by one, with the reason, in docs/COVERAGE.md.

composer test
composer coverage-check
make test-python