Installation
composer require daif/chrome-pdf-bundle
Add to config/bundles.php:
return [
// ...
Daif\ChromePdfBundle\ChromePdfBundle::class => ['all' => true],
];
Basic Configuration
Edit config/packages/chrome_pdf.yaml:
chrome_pdf:
chrome_binary: '/usr/bin/chromium' # or '/usr/bin/google-chrome'
options:
headless: true
args: ['--no-sandbox', '--disable-gpu']
First Use Case: Generate PDF from URL
use Daif\ChromePdfBundle\Service\PdfGenerator;
class SomeController extends AbstractController
{
public function generatePdf(PdfGenerator $pdfGenerator): Response
{
$pdf = $pdfGenerator->fromUrl('https://example.com')
->saveAs('/path/to/output.pdf');
return $this->file($pdf->getPath());
}
}
First Use Case: Generate PDF from HTML
$pdf = $pdfGenerator->fromHtml('<h1>Hello World</h1>')
->saveAs('/path/to/output.pdf');
The bundle follows a fluent builder pattern for PDF generation. Typical workflow:
$pdf = $pdfGenerator
->fromUrl('https://example.com')
->setOptions(['format' => 'A4', 'margin' => '1cm'])
->setHeaders(['User-Agent' => 'MyApp/1.0'])
->setTimeout(30)
->saveAs('/tmp/output.pdf');
Dynamic PDF Generation in Controllers
public function generateInvoice(PdfGenerator $pdfGenerator, $invoiceId): Response
{
$html = $this->twig->render('invoice/pdf.html.twig', ['id' => $invoiceId]);
$pdf = $pdfGenerator->fromHtml($html)
->setOptions(['format' => 'A4', 'margin' => '0.5cm'])
->saveAs('/tmp/invoices/'.$invoiceId.'.pdf');
return $this->file($pdf->getPath());
}
Background PDF Generation with Symfony Messenger
use Daif\ChromePdfBundle\Message\GeneratePdfMessage;
$bus->dispatch(new GeneratePdfMessage(
url: 'https://example.com',
outputPath: '/tmp/output.pdf',
options: ['format' => 'A4']
));
Integration with Symfony UX Turbo
// In your Stimulus controller
connect() {
this.pdfButton.addEventListener('click', () => {
fetch('/generate-pdf', {
headers: { 'Accept': 'application/pdf' }
})
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
});
});
}
Custom Chrome Binary per Environment
Use environment variables in chrome_pdf.yaml:
chrome_pdf:
chrome_binary: '%env(CHROME_BINARY)%'
Set in .env:
CHROME_BINARY=/usr/local/bin/google-chrome
Reusing Chrome Instances For performance, reuse Chrome instances with a pool:
# config/packages/chrome_pdf.yaml
chrome_pdf:
pool:
enabled: true
max_instances: 5
Chrome Binary Not Found
ChromeBinaryNotFoundExceptionchrome_binary path in config. Test with:
which chromium-browser google-chrome
/usr/bin/google-chrome-stable).Headless Chrome Fails on Linux
chrome_pdf:
options:
args: ['--no-sandbox', '--disable-gpu', '--single-process']
args: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage']
Memory Leaks with Reused Instances
max_instances:
chrome_pdf:
pool:
enabled: true
max_instances: 3
ttl: 300 # 5 minutes
Slow PDF Generation
$pdfGenerator->fromUrl('https://slow-site.com')
->setTimeout(60); // 60 seconds
PDFs with Missing Content
waitForSelector:
$pdfGenerator->fromUrl('https://example.com')
->waitForSelector('#dynamic-content')
->saveAs('/tmp/output.pdf');
Font Rendering Issues
chrome_pdf:
options:
args: ['--disable-font-subpixel-positioning']
Environment-Specific Configs
Override configs per environment using config/packages/chrome_pdf_{env}.yaml:
# config/packages/chrome_pdf_prod.yaml
chrome_pdf:
options:
args: ['--no-sandbox', '--disable-setuid-sandbox']
Custom Chrome Flags
Pass additional flags via args:
chrome_pdf:
options:
args: [
'--disable-extensions',
'--disable-notifications',
'--disable-default-apps',
'--disable-infobars'
]
Proxy Support Configure proxy for restricted environments:
chrome_pdf:
options:
args: [
'--proxy-server=http://proxy.example.com:8080',
'--proxy-bypass-list=*.internal'
]
Custom PDF Generator Extend the base generator:
use Daif\ChromePdfBundle\Service\PdfGeneratorInterface;
class CustomPdfGenerator implements PdfGeneratorInterface
{
public function fromUrl(string $url): self
{
// Custom logic (e.g., add auth headers)
return $this;
}
// Implement other methods...
}
Register as a service:
services:
Daif\ChromePdfBundle\Service\PdfGenerator:
alias: 'App\Service\CustomPdfGenerator'
Event Listeners for PDF Generation
Listen to chrome_pdf.generate events:
use Daif\ChromePdfBundle\Event\PdfGenerateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PdfLogger implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
PdfGenerateEvent::NAME => 'onPdfGenerate',
];
}
public function onPdfGenerate(PdfGenerateEvent $event)
{
// Log or modify the PDF generation process
}
}
Custom Chrome Binary Wrapper
For unsupported Chrome versions, create a wrapper script (e.g., /usr/local/bin/chrome-wrapper):
#!/bin/bash
exec /usr/bin/google-chrome-stable --headless --disable-gpu "$@"
Then point chrome_binary to this wrapper.
Integration with Symfony Workflow Use the bundle in a Symfony workflow for multi-step PDF generation:
# config/packages/workflow.yaml
app.generate_pdf_workflow:
support:
triggered_by: 'app.generate_pdf'
places:
- reading_url
- generating_pdf
- saving_file
transitions:
read_url:
from: reading_url
to: generating_pdf
generate_pdf:
from: generating_pdf
to: saving_file
How can I help you explore Laravel packages today?