acucchieri/tcpdf-bundle
Symfony bundle integrating TCPDF for quick PDF generation and delivery. Build PDFs via a TCPDF-based PdfBuilder and output inline, as download, attachment/base64, string, or save to disk. Includes MultiCell row helper for table-like layouts.
Installation:
composer require acucchieri/tcpdf-bundle
Ensure Composer is installed globally.
Enable the Bundle:
Add to config/bundles.php (Symfony 4.3+):
return [
// ...
AC\TcpdfBundle\ACTcpdfBundle::class => ['all' => true],
];
(Note: Update from AppKernel.php to config/bundles.php for modern Symfony versions.)
First PDF Generation:
Inject PdfBuilder into a controller/service:
use AC\TcpdfBundle\Pdf\PdfBuilder;
public function generatePdf(PdfBuilder $pdfBuilder)
{
$pdf = $pdfBuilder->create();
$pdf->AddPage();
$pdf->SetFont('helvetica', 'B', 16);
$pdf->Cell(0, 10, 'Hello, TCPDF in Symfony!', 0, 1, 'C');
return $pdf->output('example.pdf', 'D'); // 'D' = download
}
Generate a simple invoice PDF with dynamic data:
$pdf = $pdfBuilder->create();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, "Invoice #{$invoice->id}", 0, 1, 'L');
$pdf->Ln(10);
$pdf->writeHTML("<table><tr><td>Item</td><td>Price</td></tr></table>", true, false, true, false, '');
return $pdf->output('invoice_{$invoice->id}.pdf', 'D');
Dependency Injection:
Always inject PdfBuilder into controllers/services for reusability:
public function __construct(private PdfBuilder $pdfBuilder) {}
Reusable PDF Templates: Create a service to encapsulate PDF logic:
// src/Service/PdfGenerator.php
class PdfGenerator {
public function __construct(private PdfBuilder $pdfBuilder) {}
public function generateReport(array $data): string {
$pdf = $this->pdfBuilder->create();
$pdf->AddPage();
$pdf->writeHTML($this->renderReportHtml($data));
return $pdf->output('report.pdf', 'S'); // 'S' = send to browser
}
}
Dynamic Content Injection:
Use TCPDF’s methods (Cell(), writeHTML(), MultiCell()) with Symfony’s twig:
$html = $this->twig->render('pdf/report.html.twig', ['data' => $data]);
$pdf->writeHTML($html);
Streaming Large PDFs: For memory efficiency, stream directly to response:
$response = new StreamedResponse(function () use ($pdf) {
echo $pdf->Output('large_report.pdf', 'D');
});
return $response;
Twig Integration: Extend Twig with TCPDF filters for reusable PDF components:
// src/Twig/PdfExtension.php
class PdfExtension extends \Twig\Extension\AbstractExtension {
public function getFilters() {
return [
new \Twig\TwigFilter('pdf_table', [$this, 'renderTable']),
];
}
}
Use in Twig:
{{ data|pdf_table }}
Event-Driven PDFs: Trigger PDF generation via Symfony events (e.g., post-order confirmation):
// src/EventListener/OrderListener.php
class OrderListener {
public function __construct(private PdfGenerator $pdfGenerator) {}
public function onOrderConfirmed(OrderEvent $event) {
$this->pdfGenerator->generateInvoice($event->getOrder());
}
}
Configuration:
Override TCPDF defaults in config/packages/ac_tcpdf.yaml:
ac_tcpdf:
default:
format: 'a4'
orientation: 'P'
unit: 'mm'
font_size: 10
font: 'helvetica'
Bundle Registration:
config/bundles.php (not AppKernel.php).ACTcpdfBundle is in the registerBundles() array.ClassNotFoundException → Verify Composer autoload (composer dump-autoload).Memory Limits:
Output() with streaming:
$pdf->Output('large_file.pdf', 'D', true); // Force download + streaming
ini_set('memory_limit', '512M')) or optimize content.Font Paths:
helvetica.php). Ensure they’re copied to vendor/tecnickcom/tcpdf/fonts/.$pdf->SetFont('dejavusans', '', 12, '', true);
Caching Issues:
php bin/console cache:clear
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
TCPDF Errors:
$pdf->setErrorAction('error');
$pdf->SetErrorHandler('myErrorHandler');
var/log/dev.log) for TCPDF exceptions.Output Issues:
AddPage() is called before content.writeHTML() (e.g., <table> must close).Symfony Response Conflicts:
output() with Symfony’s Response:
// Wrong:
return $pdf->output('file.pdf', 'D'); // Returns string, not Response
// Correct:
return new Response($pdf->Output('file.pdf', 'S'), 200, ['Content-Type' => 'application/pdf']);
Custom TCPDF Classes:
Extend PdfBuilder to add methods:
// src/Pdf/CustomPdfBuilder.php
class CustomPdfBuilder extends PdfBuilder {
public function addLogo(string $path, float $width = 30) {
$this->Image($path, 10, 10, $width);
}
}
Bind to Symfony’s container:
# config/services.yaml
services:
App\Pdf\CustomPdfBuilder:
tags: ['ac_tcpdf.pdf_builder']
Hooks for Pre/Post Processing: Use Symfony’s compiler passes to modify TCPDF behavior:
// src/DependencyInjection/Compiler/PdfPass.php
class PdfPass implements CompilerPassInterface {
public function process(ContainerBuilder $container) {
$definition = $container->findDefinition('ac_tcpdf.pdf_builder');
$definition->addMethodCall('setCustomHeader', ['My Header']);
}
}
Dynamic Font Loading: Load fonts dynamically from a database:
$pdf->AddFont('custom_font', '', 'custom_font.php', true);
PdfBuilder instances for repeated use:
# config/services.yaml
services:
App\Service\PdfGenerator:
arguments:
$pdfBuilder: '@ac_tcpdf.pdf_builder'
$pdf->startTransaction();
foreach ($largeData as $item) {
$pdf->Cell(0, 5, $item->name);
$pdf->endTransaction();
$pdf->startTransaction();
}
How can I help you explore Laravel packages today?