jdz / pdfbuilder
Build a PDF with TCPDF and FPDI
Requires
- php: >=8.2
- jdz/data: ^2.0.4
- setasign/fpdi: ^2.6
- symfony/yaml: ^7.4
- tecnickcom/tcpdf: ^6.3
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-11 14:02:24 UTC
README
PHP library for building structured PDFs using TCPDF and FPDI.
Provides a Builder/Modelizer pattern for generating multi-page PDFs with YAML-driven configuration, automatic config inheritance, color/font management, and unit conversion utilities.
Requirements
- PHP >= 8.2
- TCPDF ^6.3
- FPDI ^2.6
- Symfony YAML ^7.4
- jdz/data ^2.0.4 (
JDZ\Utils\Data, whichBuilderandDatabuild on;getFloat()reads the measures)
Installation
composer require jdz/pdfbuilder
PDF 1.5+ support (optional)
FPDI natively handles PDF documents up to version 1.4. To import PDF 1.5+ files (those using compressed cross-references and object streams), you need the commercial FPDI PDF-Parser add-on from Setasign.
-
Purchase a license at setasign.com
-
Add the Setasign private Composer repository to your project's
composer.json:
{
"repositories": [
{
"type": "composer",
"url": "https://www.setasign.com/downloads/"
}
]
}
- Require the package (you will be prompted for your Setasign credentials):
composer require setasign/fpdi_pdf-parser
Once installed, FPDI automatically detects the parser and enables PDF 1.5+ support — no code changes needed.
Architecture
Core classes
| Class | Role |
|---|---|
Builder |
Abstract base class (implements Contract\BuilderInterface). Loads YAML modelizer configs with inheritance, registers fonts, orchestrates PDF generation. Concrete builders extend this and implement build(). Holds the sources path, target path and data (getters/setters), plus a withToc(bool) / getToc() flag a build can read to print a table of contents. |
Modelizer |
Base class for rendering a single page type. Subclasses override Page(), Header(), and Footer() to define layout. Handles margins, page breaks, and page number placeholders. |
Data |
Configuration container extending jData. Manages colors (Color), fonts (Font), and provides unit conversion methods (px2mm, px2pt, mm2px, percent2mm). |
Pdf |
FPDI/TCPDF bridge. Extends setasign\Fpdi\Tcpdf\Fpdi with custom font loading, model-based Header/Footer callbacks, and page number offset support. |
Helper |
Utility class for unit conversions, image sizing/resolution, border definition, and TOC export. |
Built-in modelizers
| Modelizer | Purpose |
|---|---|
ImageModelizer |
Renders a full-page image scaled to page width. |
PdfModelizer |
Includes pages from an existing PDF file via FPDI. |
FormAbstractModelizer |
Provides form building helpers: text fields, checkboxes, radio buttons, signatures. |
Supporting classes
| Class | Purpose |
|---|---|
Color |
RGB/Hex color with HSV conversion, lighten() and darken() methods. |
Font |
Font name, size, and style holder. |
Book |
Container for Toc and BookText in multi-page documents. |
BookText |
Multilingual text management (fr, en, it) with plural support. |
Toc |
Table of Contents with page mark tracking. |
BookToc |
Toc that prints itself into the PDF (setPdf(), setHelper(), withPrintToc(), toPdf() via Helper::exportToc()). |
Configuration
Modelizer configs are YAML files stored in a config/ directory. They support inheritance via the inherits key.
Example: modelizer.formation.yml
inherits: - base - catalogue colors: pictoNewColor: "#cc0000" pictoCpfColor: "#01a6ba" marginTop: 120 marginBottom: 62 pagePadding: 18
The base config provides defaults for all colors, fonts, and font sizes:
colors: white: "#FFFFFF" black: "#000000" textColor: "#000000" linkColor: "#0b8181" fonts: default: helvetica black: helvetica light: helvetica h1Fsize: 17 h2Fsize: 16 pFsize: 9 borderWidth: 0.1
Configs are loaded from your build() via $this->loadModelizerConfig('formation') (protected), which reads <sourcesPath>config/modelizer.<name>.yml, resolves the full inheritance chain and merges colors, fonts, and all other properties. A name without a file loads base.
Every measure (borderWidth, the *Fsize sizes, margins, paddings) is read as a float: 0.1, 7.5 and "7.5" all work. borderWidth is a line width in mm (getBorderWidth(0.1) is a tenth of it).
Usage
1. Create a Modelizer (page layout)
use JDZ\Pdf\Modelizer; class InvoiceModelizer extends Modelizer { protected bool $printHeader = true; protected bool $printFooter = true; public function Header(): void { $this->pdf->SetFont('helvetica', 'B', 14); $this->pdf->Cell(0, 10, 'INVOICE', 0, 1, 'C'); } public function Page(): void { $invoice = $this->data->get('invoice'); $this->pdf->SetFont('helvetica', '', 10); $this->pdf->Cell(0, 8, 'Client: ' . $invoice->client, 0, 1); $this->pdf->Cell(0, 8, 'Amount: ' . $invoice->amount, 0, 1); } public function Footer(): void { $this->pdf->SetY(-15); $this->pdf->SetFont('helvetica', '', 8); $this->pdf->Cell(0, 10, 'Page ' . $this->pdf->getAliasNumPage(), 0, 0, 'C'); } }
2. Create a Builder
use JDZ\Pdf\Builder; use JDZ\Pdf\Pdf; use JDZ\Pdf\Data; class InvoiceBuilder extends Builder { private object $invoiceData; public function setInvoiceData(object $data): void { $this->invoiceData = $data; } public function build(): void { $pdf = new Pdf(); $pdf->SetTitle('Invoice'); $pdf->set('izSourcesPath', $this->sourcesPath); // Load YAML config with inheritance $modelizerData = new Data(); $modelizerData->sets($this->loadModelizerConfig('invoice')); $modelizerData->set('invoice', $this->invoiceData); // Create modelizer, render page $modelizer = new InvoiceModelizer($pdf, $modelizerData); $modelizer->load(); $modelizer->toPdf(); // Write PDF to disk $pdf->Output($this->targetPath, 'F'); } }
3. Generate the PDF
use JDZ\Utils\Data as jData; $data = new jData(); $data->set('label', 'Invoice #001'); $builder = new InvoiceBuilder( sourcesPath: __DIR__ . '/resources/', targetPath: __DIR__ . '/files/invoice.pdf', data: $data ); $builder->setInvoiceData((object)[ 'client' => 'Acme Corp', 'amount' => '1 500,00 EUR', ]); $builder->build();
Custom fonts
Register fonts in your Builder's build() method before creating the Modelizer:
$pdf->set('font', (object)[ 'name' => 'montserrat', 'styles' => [null, 'B', 'I', 'BI'], ]);
Font definition files (TCPDF PHP font files) go in the folder TCPDF reads fonts from: define K_PATH_FONTS before TCPDF loads, as examples/autoload.php does (it points at examples/resources/fonts/). The examples ship Helvetica, Courier, Montserrat, and Merienda.
Color manipulation
// Get a color clone and lighten it $color = $data->getColorObject('theme'); $color->lighten(20); $lightTheme = $color->toArray(); // [r, g, b]
The Color class supports hex-to-RGB conversion, HSV transformations, and lighten()/darken() methods.
Examples
The examples/ directory contains complete working examples:
| Example | Description | Output |
|---|---|---|
cv.php |
CV / Resume | Single-page CV with photo, skills, experience |
offre.php |
Job offer | Job posting with company info and description |
formation.php |
Training course | Course sheet with programme, sessions, side panel |
catalogue.php |
Multi-page catalogue | Cover page + category separators + 10 course sheets |
invoice.php |
Invoice | Professional invoice with items table and totals |
booktoc.php |
Book with TOC | Cover + table of contents + 5 chapters with clickable links |
Run an example:
php examples/cv.php
# Output: examples/files/cv-1.pdf
Testing
vendor/bin/phpunit
Changelog
- 1.1.2 (2026-10-11) — every measure is read as a float through
jdz/data'sgetFloat()(borderWidth: 0.1was 0,px2ptof 7.5 was 7, a numeric string works);Helper::imageSize()meets a binding cap exactly (a 10 mm cap gave 9.88 mm: the box was rounded to whole pixels first), applies both caps (the width cap was ignored once the height cap applied) and converts each axis with its own resolution (they were swapped);%total%is the number of pages (it counted the placeholders);setFormFieldFulllength()stacks its inputs 17 px apart (17 then 18); an unknown modelizer loadsbase(it was an empty config, no colours, no fonts). Requiresjdz/data ^2.0.4.
License
MIT - See LICENSE for details.