Installation:
composer require nucleos/dompdf-bundle
Ensure Nucleos\DompdfBundle\NucleosDompdfBundle::class is added to config/bundles.php.
First Use Case: Generate a PDF from a Twig template in a controller:
use Nucleos\DompdfBundle\Service\DompdfService;
class PdfController extends AbstractController
{
public function generatePdf(DompdfService $dompdfService): Response
{
$html = $this->renderView('pdf/template.html.twig', [
'data' => $this->fetchData(),
]);
$pdf = $dompdfService->generate($html, 'filename.pdf');
return new BinaryFileResponse($pdf, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="filename.pdf"',
]);
}
}
Key Files:
config/packages/nucleos_dompdf.yaml (default config)templates/pdf/ (store Twig templates here)src/Service/DompdfService.php (customize if needed)Twig Integration: Use Twig templates for dynamic PDFs:
{# templates/pdf/invoice.html.twig #}
<html>
<body>
<h1>{{ invoice.title }}</h1>
<table>
{% for item in invoice.items %}
<tr><td>{{ item.name }}</td><td>{{ item.price }}</td></tr>
{% endfor %}
</table>
</body>
</html>
Streaming Large PDFs:
$dompdfService->stream($html, 'report.pdf');
Customizing Options:
# config/packages/nucleos_dompdf.yaml
nucleos_dompdf:
default_options:
'defaultFont': 'DejaVu Sans'
'isRemoteEnabled': true
'isHtml5ParserEnabled': true
Dependency Injection:
Inject DompdfService into services for reusable PDF logic:
class InvoiceService {
public function __construct(private DompdfService $dompdf) {}
public function generateInvoicePdf(Invoice $invoice): string {
$html = $this->renderInvoiceTwig($invoice);
return $this->dompdf->generate($html, 'invoice.pdf');
}
}
Queueing PDF Jobs: Use Symfony Messenger to offload PDF generation:
use Nucleos\DompdfBundle\Message\GeneratePdfMessage;
$bus->dispatch(new GeneratePdfMessage(
$html,
'queued_report.pdf',
new \DateTimeImmutable()
));
Memory Limits:
memory_limit. Increase it temporarily:
ini_set('memory_limit', '512M');
stream() instead of generate() for large files to avoid memory spikes.Font Issues:
DejaVu Sans) are installed on the server. Configure in nucleos_dompdf.yaml:
nucleos_dompdf:
fonts:
- '%kernel.project_dir%/vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ttf'
CSS Inlining:
<style>
@import url('https://fonts.googleapis.com/css?family=Roboto');
body { font-family: 'Roboto', sans-serif; }
</style>
Debugging:
nucleos_dompdf:
debug: true
var/log/dev.log for rendering issues.Caching:
nucleos_dompdf:
options:
'isRemoteEnabled': false
'isPhpEnabled': false
Reuse PDF Logic: Create a base service for common PDF operations:
class BasePdfService {
public function __construct(private DompdfService $dompdf) {}
protected function renderWithLayout(string $template, array $data): string {
return $this->dompdf->render($this->renderView(
'pdf/layouts/base.html.twig',
['content' => $this->renderView($template, $data)]
));
}
}
Dynamic Filenames:
Use uniqid() to avoid filename collisions:
$filename = 'report_' . uniqid() . '.pdf';
Testing:
Mock DompdfService in PHPUnit:
$this->dompdf
->expects($this->once())
->method('generate')
->with($html, 'test.pdf')
->willReturn(file_get_contents(__DIR__ . '/fixtures/test.pdf'));
Headless Chrome Rendering: For complex layouts, pre-render HTML with Puppeteer and pass it to Dompdf:
$html = $puppeteer->render('https://example.com/complex-page');
$pdf = $dompdfService->generate($html, 'complex.pdf');
Extension Points:
DompdfService to add pre/post-processing:
class CustomDompdfService extends DompdfService {
public function generate(string $html, string $filename): string {
$html = $this->addWatermark($html);
return parent::generate($html, $filename);
}
}
config/services.yaml:
services:
Nucleos\DompdfBundle\Service\DompdfService: '@custom_dompdf_service'
How can I help you explore Laravel packages today?