PHPackages                             sfadless/pdf - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. sfadless/pdf

ActiveLibrary[Templating &amp; Views](/categories/templating)

sfadless/pdf
============

Create PDF files from Twig templates

0.1.0(1w ago)044proprietaryPHPPHP &gt;=8.1

Since Jan 30Pushed 1w ago1 watchersCompare

[ Source](https://github.com/sfadless/pdf)[ Packagist](https://packagist.org/packages/sfadless/pdf)[ RSS](/packages/sfadless-pdf/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (2)Dependencies (11)Versions (4)Used By (0)

sfadless/pdf
============

[](#sfadlesspdf)

Generate PDF files from Twig templates on top of [mPDF](https://github.com/mpdf/mpdf).

The library renders a Twig template to HTML and converts it to PDF. An event is dispatched before rendering so you can enrich the template context. The PDF engine sits behind a `PdfRenderer` interface, so mPDF can be swapped for another implementation. At runtime the library does not depend on Symfony — the event is dispatched through the standard [PSR-14](https://www.php-fig.org/psr/psr-14/) interface.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.1
- twig/twig ^3.8
- psr/event-dispatcher ^1.0 (any PSR-14 dispatcher implementation)
- mpdf/mpdf ^8.2 (for the default renderer)

Installation
------------

[](#installation)

```
composer require sfadless/pdf
```

Quick start
-----------

[](#quick-start)

```
use Sfadless\Pdf\PdfFactory;
use Sfadless\Pdf\Model\PdfModel;
use Sfadless\Pdf\Renderer\Mpdf\MpdfRenderer;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$twig = new Environment(new FilesystemLoader(__DIR__ . '/templates'));

$factory = new PdfFactory(
    new MpdfRenderer(),
    $twig,
    new EventDispatcher(), // any PSR-14 dispatcher
);

// By default the raw PDF bytes are returned
$pdf = $factory->writePdf(new PdfModel('invoice.html.twig', [
    'number' => 'INV-001',
    'total'  => 1200,
]));

file_put_contents('invoice.pdf', $pdf);
```

`PdfModel` takes three arguments:

```
new PdfModel(
    string          $pdfTemplate,   // Twig template name
    array           $pdfParameters, // template variables
    RendererOptions $pdfOptions,    // output options (see below)
);
```

Options
-------

[](#options)

Output options are a `Sfadless\Pdf\Renderer\RendererOptions` value object passed as the third argument of `PdfModel`. Every property has a default, so you only set what you need:

PropertyMeaningTypeDefault`fileName`file name`string``document.pdf``destination`output mode`OutputDestination``OutputDestination::STRING``footer`footer HTML`?string``null``pdfBefore`path to a PDF prepended to the document`?string``null``pdfAfter`paths to PDFs appended to the document`string[]``[]````
use Sfadless\Pdf\Model\PdfModel;
use Sfadless\Pdf\Renderer\RendererOptions;

$pdf = $factory->writePdf(new PdfModel('report.html.twig', ['title' => 'Report'], new RendererOptions(
    fileName:  'report.pdf',
    footer:    '{PAGENO}',
    pdfBefore: '/path/to/cover.pdf',
    pdfAfter:  ['/path/to/appendix-1.pdf', '/path/to/appendix-2.pdf'],
)));
```

> A missing path in `pdfBefore`/`pdfAfter` results in a `RuntimeException`.

Output modes
------------

[](#output-modes)

`Sfadless\Pdf\Renderer\OutputDestination` controls what `writePdf` does:

ValueBehaviour`OutputDestination::STRING`return the PDF as a string (default)`OutputDestination::FILE`save to the `fileName` path on disk`OutputDestination::DOWNLOAD`send to the browser as a download`OutputDestination::INLINE`display in the browser inline```
use Sfadless\Pdf\Model\PdfModel;
use Sfadless\Pdf\Renderer\OutputDestination;
use Sfadless\Pdf\Renderer\RendererOptions;

$factory->writePdf(new PdfModel('invoice.html.twig', $data, new RendererOptions(
    fileName:    'invoice.pdf',
    destination: OutputDestination::DOWNLOAD,
)));
```

Enriching the context via the event
-----------------------------------

[](#enriching-the-context-via-the-event)

`Sfadless\Pdf\Event\PreRenderPdfEvent` is dispatched before rendering. A listener can add or replace template variables — handy for shared data (current user, date, settings) you don't want to pass into every `PdfModel`.

```
use Sfadless\Pdf\Event\PreRenderPdfEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;

$dispatcher = new EventDispatcher();
$dispatcher->addListener(PreRenderPdfEvent::class, function (PreRenderPdfEvent $event): void {
    $event->addParameter('generatedAt', new DateTimeImmutable());

    // the original model is available for conditional logic
    $writable = $event->getPdfWritable();
});

$factory = new PdfFactory(new MpdfRenderer(), $twig, $dispatcher);
```

In the template the variable is available as usual: `{{ generatedAt|date('d.m.Y') }}`.

Configuring mPDF
----------------

[](#configuring-mpdf)

mPDF configuration is passed to the `MpdfRenderer` constructor and proxied to `new Mpdf(...)`:

```
use Sfadless\Pdf\Renderer\Mpdf\MpdfRenderer;

$renderer = new MpdfRenderer([
    'format'        => 'A4',
    'margin_top'    => 20,
    'margin_bottom' => 20,
    'default_font'  => 'dejavusans',
]);
```

See the full list of parameters in the [mPDF documentation](https://mpdf.github.io/reference/mpdf-functions/construct.html).

Custom renderer
---------------

[](#custom-renderer)

`PdfFactory` depends only on the `Sfadless\Pdf\Renderer\PdfRenderer` interface, so mPDF can be replaced — for example with Dompdf, wkhtmltopdf or Gotenberg:

```
use Sfadless\Pdf\Renderer\PdfRenderer;
use Sfadless\Pdf\Renderer\RendererOptions;

final class DompdfRenderer implements PdfRenderer
{
    public function render(string $html, RendererOptions $options): string
    {
        // available: $options->fileName, $options->footer, $options->destination,
        //            $options->pdfBefore, $options->pdfAfter
        // ...
        return $pdfBytes;
    }
}

$factory = new PdfFactory(new DompdfRenderer(), $twig, $dispatcher);
```

Custom document model
---------------------

[](#custom-document-model)

Instead of `PdfModel` you can implement the `Sfadless\Pdf\Model\PdfWritable` interface — handy when the document is a domain entity:

```
use Sfadless\Pdf\Model\PdfWritable;
use Sfadless\Pdf\Renderer\RendererOptions;

final class Invoice implements PdfWritable
{
    public function __construct(private string $number, private float $total) {}

    public function getPdfTemplate(): string
    {
        return 'invoice.html.twig';
    }

    public function getPdfParameters(): array
    {
        return ['number' => $this->number, 'total' => $this->total];
    }

    public function getPdfOptions(): RendererOptions
    {
        return new RendererOptions(fileName: "invoice-{$this->number}.pdf");
    }
}

$pdf = $factory->writePdf(new Invoice('INV-001', 1200));
```

Tests
-----

[](#tests)

```
composer test
```

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance98

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~874 days

Total

2

Last Release

11d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ec9f56f0170a73380e6dd1533560427c727c55d4b60468bcf092a7fd519b59d6?d=identicon)[sfadless](/maintainers/sfadless)

---

Top Contributors

[![sfadless](https://avatars.githubusercontent.com/u/20106153?v=4)](https://github.com/sfadless "sfadless (2 commits)")

---

Tags

pdftwigmpdfhtml-to-pdf

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/sfadless-pdf/health.svg)

```
[![Health](https://phpackages.com/badges/sfadless-pdf/health.svg)](https://phpackages.com/packages/sfadless-pdf)
```

###  Alternatives

[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M574](/packages/shopware-core)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.7k38.9k](/packages/matomo-matomo)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.9M387](/packages/easycorp-easyadmin-bundle)[symfony/form

Allows to easily create, process and reuse HTML forms

2.8k162.1M3.4k](/packages/symfony-form)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M738](/packages/sylius-sylius)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
