Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Dompdf Bundle Laravel Package

nmalo/dompdf-bundle

A Laravel bundle integrating Dompdf for generating PDFs from HTML and Blade views, with bundle configuration and service wiring for downloading or streaming PDF documents. Review its compatibility and maintenance status before adopting it in production.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify the fork before you commit to it. This package is a low-traffic fork of sliknl/dompdf-bundle targeting Symfony 2, which reached end of life in November 2019. With 0 stars and 0 dependents, treat it as a vendored artifact rather than a maintained dependency. If you have any latitude, prefer pulling dompdf/dompdf directly and wrapping it yourself — it is the same work and avoids an unmaintained middle layer. Continue below only if this fork is already in your stack or is a hard constraint.

Minimal steps

  1. Install the bundle (the package is unlikely to resolve cleanly from Packagist as nmalo/dompdf-bundle; if it fails, add it as a VCS repository):

    composer require nmalo/dompdf-bundle
    

    If Composer cannot find it, add to composer.json:

    "repositories": [
      { "type": "vcs", "url": "https://github.com/nmalo/DompdfBundle" }
    ]
    

    Then composer require nmalo/dompdf-bundle:"dev-master".

  2. Register the bundle in app/AppKernel.php. Open vendor/nmalo/dompdf-bundle/ and read the top-level *Bundle.php file first — the fork may retain the original Slik\DompdfBundle namespace or rename it to Nmalo\DompdfBundle. Use whatever class the file actually declares:

    $bundles = [
        // ...
        new Slik\DompdfBundle\SlikDompdfBundle(), // verify class name in vendor
    ];
    
  3. Create app/config/config.yml defaults (config key is likely slik_dompdf — confirm in DependencyInjection/Configuration.php):

    slik_dompdf:
        base_path: "%kernel.root_dir%/../web"
        defaults:
            dpi: 300
            defaultFont: DejaVu Sans
    
  4. First use case — a controller that returns a PDF response:

    public function invoicePdfAction($html)
    {
        /** @var \Slik\DompdfBundle\Wrapper\DompdfWrapper $dompdf */
        $dompdf = $this->get('slik_dompdf');
    
        $html = $this->renderView('AcmeBundle:Invoice:pdf.html.twig', ['html' => $html]);
    
        return new Response(
            $dompdf->getPdf($html),
            200,
            ['Content-Type' => 'application/pdf']
        );
    }
    

Where to look first

  • vendor/nmalo/dompdf-bundle/DependencyInjection/Configuration.php — the real config keys and defaults.
  • vendor/nmalo/dompdf-bundle/Resources/config/services.yml — the service ID you should inject (verify whether it’s slik_dompdf, slik_dompdf.wrapper, or a renamed nmalo_dompdf).
  • vendor/nmalo/dompdf-bundle/Wrapper/DompdfWrapper.php — read getPdf() and getOutput() to see how options are merged. This is the only file most apps will ever touch.

Implementation Patterns

Inject the wrapper, do not call the container. Symfony 2 supports constructor injection even without autowiring, so declare your own service:

services:
    acme.invoice_pdf:
        class: Acme\Bundle\AppBundle\Service\InvoicePdf
        arguments: ['@slik_dompdf', '@templating']

In InvoicePdf::__construct, type-hint the wrapper (or take ContainerInterface only if the bundle predates a stable wrapper class). This keeps your code testable and makes it trivial to swap the bundle out later.

Render the Twig template to a string, then generate. Two-stage always — it lets the same template be reused for HTML previews and makes debugging far easier:

public function generate(Invoice $invoice): string
{
    $html = $this->templating->render(
        'AcmeBundle:Invoice:pdf.html.twig',
        ['invoice' => $invoice]
    );

    return $this->dompdf->getPdf($html);
}

Stream vs. download vs. persist. Use getPdf() in the controller, set Content-Disposition: attachment; filename="invoice-{$id}.pdf" for downloads. To persist, write the returned string to disk:

file_put_contents(
    $this->get('kernel')->getRootDir().'/../web/pdf/invoice-'.$invoice->getId().'.pdf',
    $dompdf->getPdf($html)
);

Do this in a background job if the PDF is large — DomPDF is CPU-heavy and synchronous.

Customizing options per request. The bundle wrapper typically exposes getPdf($html, array $options = []). Pass DomPDF options inline when you need to override the bundle defaults:

$dompdf->getPdf($html, [
    'isRemoteEnabled' => true,          // images/links over HTTP
    'isHtml5ParserEnabled' => true,
    'defaultFont' => 'DejaVu Sans',
]);

Only override what you must; the config defaults exist for the common case.

Email attachments. Swift_Message::attach() needs a Swift_Attachment, so wrap the returned string:

$message->attach(
    \Swift_Attachment::newInstance($dompdf->getPdf($html), 'invoice.pdf', 'application/pdf')
);

This pattern pairs well with queue-driven sending — generate the PDF in a worker, not a web request.

Testing. Because the wrapper is a plain service, mock it in unit tests:

$mock = $this->getMockBuilder(DompdfWrapper::class)->disableOriginalConstructor()->getMock();
$mock->method('getPdf')->willReturn('%PDF-1.4 ...');

For integration tests, call DomPDF directly and assert on %PDF magic bytes and page count via a parser, rather than snapshotting the full binary.

Integration tip — build a thin service layer. Wrap the bundle behind your own InvoicePdfGenerator interface. The bundle is a fork with 0 stars and a 2013-era API; you want to be able to delete it in one file if it breaks.

Gotchas and Tips

Symfony 2 is EOL. This bundle's namespace, AppKernel registration, and config layout are all pre-Symfony-3. If you're migrating, budget for a rewrite: the upstream sliknl/dompdf-bundle has a maintained successor ecosystem around dompdf 2.x, and the fork here is unlikely to track that. Confirm dompdf/dompdf version compatibility before assuming DomPDF 2.x is supported — historically SlikNL pinned dompdf 0.6.*, which has known security issues (see the 2020 advisory on dompdf/dompdf < 0.8.6).

Fork hygiene. Read composer.json and CHANGELOG in the vendor directory. With 0 dependents there is no community to surface regressions; pin an exact commit hash in composer.lock and vendor a copy if you need reproducibility.

base_path is the single most common failure point. Relative image paths, CSS url(), and @font-face sources resolve against this. It must be an absolute filesystem path pointing at the document root, not a URL and not a trailing-slash path that doesn’t exist. Symptom: PDF renders with blank images or unstyled HTML.

slik_dompdf:
    base_path: "%kernel.root_dir%/../web"

Remote resources are off by default. If your HTML fetches images over HTTP, isRemoteEnabled: true must be set — and consider SSRF: DomPDF does not validate schemes or hosts strictly, so never render user-supplied HTML with this on.

Fonts must be installed locally. DomPDF will not use system fonts unless they are registered. Point font_dir / font_cache at an existing, writable directory under app/cache. Cache misses on the first run make it look like the font isn’t working — clear app/cache/dompdf/ and retry.

CSS support is 2013-era. DomPDF supports CSS 2.1 and only a sliver of CSS 3. Flexbox and CSS Grid render flat. Stick to tables, floats, and position for layout. This is the most common reason a PDF looks nothing like the browser preview — it’s the library, not your Twig template.

getOutput() vs. getPdf(). The wrapper typically exposes both: getOutput() streams via output(), getPdf() returns a string. Some forks return a resource from getOutput(). In a controller returning a Response, use the string variant — passing a stream as Response content throws.

Memory ceiling. Large HTML (tens of MB) or high dpi will exhaust the default PHP memory limit. Raise it in the worker, not in php.ini, and prefer dpi: 96–150 unless print quality demands otherwise. Also set a timeout (DomPDF option) so a runaway render doesn’t stall the request.

Debugging a bad PDF. There is no error channel: if DomPDF can’t parse the HTML it silently produces a blank or partial page. Write the HTML to a file before rendering, and inspect the DOM with html5lib or a browser before blaming DomPDF.

Extension points. Don’t patch vendor/. The sanctioned extension points are: (1) subclass DompdfWrapper and redefine the service, (2) decorate the service (Symfony 2 does not have the modern decoration syntax, so re-declare the service ID with a parent: if supported, otherwise an explicit class), (3) post-process the returned PDF string with setasign/fpdi or setasign/fpdf for watermarking/merging. Keep all three in your own bundle so a Composer update can’t surprise you.

Modernization path. If you can influence the roadmap, the migration is small: drop the bundle, require dompdf/dompdf directly, register a DompdfFactory service, and move the slik_dompdf config block into your own dompdf.yaml. The wrapper is ~30 lines of code. This assessment’s biggest risk finding is that the bundle is not maintained and offers no capability you cannot reproduce in a single service class.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console