zaynasheff / document-generator
Generate DOCX documents and PDF packages from Microsoft Word templates.
Requires
- php: ^7.4 || ^8.0
- illuminate/support: ^8.83 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- phpoffice/phpword: ^1.4
- setasign/fpdf: ^1.8
- setasign/fpdi: ^2.6
Requires (Dev)
- ext-zip: *
- larastan/larastan: ^3.7
- laravel/pint: ^1.24
- orchestra/testbench: ^10.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5
README
Generate DOCX, PDF, and merged PDF packages from Microsoft Word templates using PHPWord and LibreOffice.
Document Generator is a Laravel package that provides a fluent API for generating documents from DOCX templates, converting them to PDF, generating multiple documents in a single operation, and merging them into one PDF package.
Contents
- Features
- Installation
- Configuration
- Basic Usage
- Package Generation
- API Reference
- Testing
- Contributing
- License
Features
- Generate DOCX documents from Microsoft Word templates
- Replace template placeholders
- Generate PDF documents using LibreOffice
- Generate multiple documents in a single operation
- Merge generated PDF documents into a single package
- Custom output filenames
- Fluent and expressive API
- Laravel auto-discovery
- Configurable LibreOffice executable
- PHPUnit tested
- PHPStan (max level)
- Laravel Pint
- GitHub Actions ready
Requirements
- PHP 7.4 or higher
- Laravel 8+
- LibreOffice (required only for PDF generation)
Installation
Install the package using Composer.
composer require zaynasheff/document-generator
Publish the configuration file.
php artisan vendor:publish --tag=document-generator-config
Configuration
Set the LibreOffice executable in your .env.
Default:
DOCUMENT_GENERATOR_OFFICE_BINARY=soffice DOCUMENT_GENERATOR_OFFICE_PROFILE= DOCUMENT_GENERATOR_TIMEOUT=60
macOS
DOCUMENT_GENERATOR_OFFICE_BINARY=/Applications/LibreOffice.app/Contents/MacOS/soffice
Linux
DOCUMENT_GENERATOR_OFFICE_BINARY=/usr/bin/soffice
Windows
DOCUMENT_GENERATOR_OFFICE_BINARY="C:\Program Files\LibreOffice\program\soffice.exe"
If LibreOffice is available in your system PATH, simply use:
DOCUMENT_GENERATOR_OFFICE_BINARY=soffice
DOCUMENT_GENERATOR_OFFICE_PROFILE is optional. It can be used in Docker, PHP-FPM or other headless environments where LibreOffice cannot initialize its default user profile.
Example:
DOCUMENT_GENERATOR_OFFICE_PROFILE="/tmp/document-generator-profile"
Configuration File
return [ 'libreoffice' => [ 'binary' => env( 'DOCUMENT_GENERATOR_OFFICE_BINARY', 'soffice' ), 'timeout' => env( 'DOCUMENT_GENERATOR_TIMEOUT', 60 ), 'profile' => env( 'DOCUMENT_GENERATOR_OFFICE_PROFILE', ), ] ];
Basic Usage
Generate both DOCX and PDF.
use Zaynasheff\DocumentGenerator\DocumentGenerator; $result = DocumentGenerator::make() ->template( storage_path('templates/contract.docx') ) ->values([ 'FIRST_NAME' => 'John', 'LAST_NAME' => 'Anderson', 'CITY' => 'Berlin', ]) ->docx() ->pdf() ->output( storage_path('documents') ) ->generate();
Generate DOCX Only
Generate a Microsoft Word document without creating a PDF.
$result = DocumentGenerator::make() ->template($template) ->values($values) ->docx() ->output($output) ->generate();
Generate PDF Only
Generate only a PDF document.
$result = DocumentGenerator::make() ->template($template) ->values($values) ->pdf() ->output($output) ->generate();
Generate DOCX and PDF
Generate both formats in a single operation.
$result = DocumentGenerator::make() ->template($template) ->values($values) ->docx() ->pdf() ->output($output) ->generate();
Custom Output Filename
By default the generated filename is based on the template filename.
Use name() to specify your own filename.
$result = DocumentGenerator::make() ->template($template) ->values($values) ->name('contract_001') ->pdf() ->output($output) ->generate();
Generated files:
contract_001.docx
contract_001.pdf
Generation Result
The generate() method returns a GenerationResult.
$result->hasDocx(); $result->docxPath(); $result->hasPdf(); $result->pdfPath();
Example:
if ($result->hasPdf()) { return response()->download( $result->pdfPath() ); }
Multiple Placeholder Values
Template placeholders are passed as an associative array.
$result = DocumentGenerator::make() ->template($template) ->values([ 'FIRST_NAME' => 'John', 'LAST_NAME' => 'Anderson', 'CITY' => 'Berlin', 'EMAIL' => 'john@example.com', 'PHONE' => '+1 555 123 45 67', ]) ->pdf() ->output($output) ->generate();
Supported Placeholder Types
The following value types are supported:
- string
- integer
- float
- boolean
- null
Example:
->values([ 'NAME' => 'John', 'AGE' => 35, 'BALANCE' => 1500.75, 'ACTIVE' => true, 'COMMENT' => null, ])
Package Generation
Generate multiple documents in a single operation.
use Zaynasheff\DocumentGenerator\DocumentPackage; $package = DocumentPackage::make(); $package->output( storage_path('documents') ); $package ->addDocument() ->template( storage_path('templates/contract.docx') ) ->values([ 'FIRST_NAME' => 'John', 'LAST_NAME' => 'Anderson', ]) ->name('contract') ->pdf(); $package ->addDocument() ->template( storage_path('templates/invoice.docx') ) ->values([ 'FIRST_NAME' => 'John', ]) ->name('invoice') ->pdf(); $result = $package->generate();
Generated files:
documents/
contract.docx
contract.pdf
invoice.docx
invoice.pdf
Merge PDF
Automatically merge all generated PDF files into a single document.
$package = DocumentPackage::make(); $package ->output( storage_path('documents') ) ->name('package') ->mergePdf(); $package ->addDocument() ->template($contractTemplate) ->values($contractValues) ->name('contract') ->pdf(); $package ->addDocument() ->template($invoiceTemplate) ->values($invoiceValues) ->name('invoice') ->pdf(); $result = $package->generate();
Generated files:
documents/
contract.docx
contract.pdf
invoice.docx
invoice.pdf
package.pdf
Multiple Copies
Generate multiple copies of the same document.
$package = DocumentPackage::make(); $package ->output(storage_path('documents')); $package ->addDocument() ->template($template) ->values($values) ->name('contract') ->copies(3) ->pdf(); $result = $package->generate();
Generated files:
contract.pdf
contract_2.pdf
contract_3.pdf
Copies are generated in the specified order and are automatically included in merged PDF packages.
Blank Pages
Insert blank pages between generated documents when creating a merged PDF.
use Zaynasheff\DocumentGenerator\DocumentPackage; $package = DocumentPackage::make(); $package ->output(storage_path('documents')) ->name('contracts') ->mergePdf(); $package ->addDocument() ->template($template1) ->values($values1) ->pdf(); $package->addBlankPage(); $package ->addDocument() ->template($template2) ->values($values2) ->pdf(); $result = $package->generate();
Blank pages are supported only when PDF merging is enabled.
If a blank page is added without calling mergePdf(), a DocumentGeneratorException will be thrown.
Package Result
Package generation returns a PackageResult.
$result->count(); $result->results(); $result->hasMergedPdf(); $result->mergedPdfPath();
Example:
if ($result->hasMergedPdf()) { return response()->download( $result->mergedPdfPath() ); }
Complete Package Example
use Zaynasheff\DocumentGenerator\DocumentPackage; $package = DocumentPackage::make(); $package ->output( storage_path('documents') ) ->name('contracts') ->mergePdf(); $package ->addDocument() ->template( storage_path('templates/contract.docx') ) ->values([ 'FIRST_NAME' => 'John', 'LAST_NAME' => 'Anderson', 'CITY' => 'Berlin', ]) ->name('contract') ->pdf(); $package ->addDocument() ->template( storage_path('templates/invoice.docx') ) ->values([ 'FIRST_NAME' => 'John', 'AMOUNT' => '1500 €', ]) ->name('invoice') ->pdf(); $result = $package->generate(); if ($result->hasMergedPdf()) { return response()->download( $result->mergedPdfPath() ); }
Current Capabilities
✅ DOCX generation
✅ PDF generation
✅ Custom output filenames
✅ Multiple document generation
✅ PDF package generation
✅ Merged PDF packages
✅ Fluent API
✅ Laravel auto-discovery
Why Document Generator?
Document Generator focuses on simplicity and readability.
$result = DocumentPackage::make() ->output($output) ->name('contracts') ->mergePdf(); $result ->addDocument() ->template($contract) ->values($contractData) ->pdf(); $result ->addDocument() ->template($invoice) ->values($invoiceData) ->pdf(); $result = $result->generate();
The package hides all low-level details of DOCX generation, PDF conversion and PDF merging behind a clean, fluent API.
API Reference
DocumentGenerator
template(string $template)
Sets the DOCX template file.
->template($template)
values(array $values)
Sets template placeholder values.
->values([ 'FIRST_NAME' => 'John', 'LAST_NAME' => 'Smith', ])
name(string $name)
Sets the output filename without extension.
->name('contract')
docx()
Enables DOCX generation.
->docx()
pdf()
Enables PDF generation.
->pdf()
output(string $directory)
Sets the output directory.
->output(storage_path('documents'))
generate()
Generates the requested document(s).
$result = DocumentGenerator::make() ->template($template) ->values($values) ->pdf() ->output($output) ->generate();
DocumentPackage
addDocument()
Adds a document to the package.
$package->addDocument();
output(string $directory)
Sets the package output directory.
$package->output( storage_path('documents') );
name(string $name)
Sets the merged PDF filename.
$package->name('contracts');
Produces:
contracts.pdf
mergePdf()
Enables automatic PDF merging.
$package->mergePdf();
generate()
Generates the complete package.
$result = $package->generate();
GenerationResult
$result->hasDocx(); $result->docxPath(); $result->hasPdf(); $result->pdfPath();
PackageResult
$result->count(); $result->results(); $result->hasMergedPdf(); $result->mergedPdfPath();
Error Handling
All package exceptions extend:
Zaynasheff\DocumentGenerator\Exceptions\DocumentGeneratorException
Example:
use Zaynasheff\DocumentGenerator\Exceptions\DocumentGeneratorException; try { $result = DocumentGenerator::make() ->template($template) ->pdf() ->output($output) ->generate(); } catch (DocumentGeneratorException $exception) { report($exception); }
Testing
Run PHPUnit.
composer test
Run PHPStan.
composer analyse
Run Laravel Pint.
composer format:test
Run the complete quality pipeline.
composer quality
Automatically fix coding style.
composer fix
Contributing
Contributions are welcome.
Before opening a Pull Request, please make sure all quality checks pass.
composer quality
Please follow the existing coding style and architecture.
Roadmap
The following features are planned for future releases.
- Blank pages inside document packages
- Multiple document copies
- ZIP package generation
- Watermarks
- Page numbering
- Digital signatures
License
The MIT License (MIT).
Made with ❤️ for the Laravel community.