F
Filamentβ€’9mo ago
Prosp30

Download PDF using Spatie Laravel-PDF on table action

I am trying to download a PDF generated from a blade view. I tried DOMPDF and it works fine, but I would like to use Spatie's PDF which has better funcionality. I added the PDF to the table action, but the button just spins and nothing gets returned. Is there a way to convert the PDF to a stream to make it downloadable or? Action::make('download') ->action(function (Invoice $record) { return pdf()->view('pdf.invoice', ['invoice' => $record]) ->format('a4') ->name('your-invoice.pdf') ->download(); }) ->iconButton('heroicon-o-document-arrow-down') ->icon('heroicon-o-document-arrow-down') ->label('Preuzmi PDF'),
Solution:
I managed to do it `return response()->streamDownload(function () use ($record) { echo base64_decode(Pdf::view('pdf.invoice', ['invoice' => $record]) ->format('a4')...
Jump to solution
16 Replies
Prosp30
Prosp30OPβ€’9mo ago
I am trying to do it this way, but no luck. Any ideas? return response()->streamDownload(function () use ($record) { Pdf::html('<p>test</p>') ->format('a4') ->name('your-invoice.pdf'); }, 'test' . '.pdf');
toeknee
toekneeβ€’9mo ago
That's because you are not returning a file blob I believe. I end up saving to a tmp folder adn then providing the filepath for download and deleting on download
Prosp30
Prosp30OPβ€’9mo ago
That is my backup idea, I am trying to avoid it if it's possible
toeknee
toekneeβ€’9mo ago
I couldn't figure out a way quickly last time, It's how the PDF rendering engine returns the stream IIRC
Prosp30
Prosp30OPβ€’9mo ago
I'll try it today, I have an idea but I doubt it'll work
Solution
Prosp30
Prosp30β€’9mo ago
I managed to do it return response()->streamDownload(function () use ($record) { echo base64_decode(Pdf::view('pdf.invoice', ['invoice' => $record]) ->format('a4') ->footerView('pdf.invoicefooter') ->name('your-invoice.pdf') ->base64()); }, 'test' . '.pdf');
Prosp30
Prosp30OPβ€’9mo ago
@toeknee
toeknee
toekneeβ€’9mo ago
Ahhh base64x handy
Prosp30
Prosp30OPβ€’9mo ago
yeah, but it works πŸ˜„ Let me know if it works for you
ralphjsmit
ralphjsmitβ€’8mo ago
Thanks for this! The echo and base64 part were very helpful tips. For reference, I just implemented PDF download using Spatie/laravel-pdf from an action like this:
Tables\Actions\Action::make('download_order_invoice')
->icon('heroicon-o-arrow-down-tray')
->label('Download invoice')
->action(function (Order $order) {
$pdfBuilder = Pdf::view('pdfs.order-invoice', ['order' => $order])
->format(Format::A4)
->name("order-{$order->uuid}.pdf");

return response()->streamDownload(function () use ($pdfBuilder) {
echo base64_decode($pdfBuilder->download()->base64());
}, $pdfBuilder->downloadName);
}),
Tables\Actions\Action::make('download_order_invoice')
->icon('heroicon-o-arrow-down-tray')
->label('Download invoice')
->action(function (Order $order) {
$pdfBuilder = Pdf::view('pdfs.order-invoice', ['order' => $order])
->format(Format::A4)
->name("order-{$order->uuid}.pdf");

return response()->streamDownload(function () use ($pdfBuilder) {
echo base64_decode($pdfBuilder->download()->base64());
}, $pdfBuilder->downloadName);
}),
nowak
nowakβ€’8mo ago
This was very useful for me too! I just wanted to check if you know how to make the action show the pdf in the browser without downloading? I tried using ->stream() instead of ->streamDownload() like this:
Action::make('downloadPdf')
->label('Download Pdf')
->icon('heroicon-o-arrow-down-tray')
->action(function (Component $livewire) {
$records = $livewire->getTableRecords();

$pdfBuilder = Pdf::view('filament.pdf.group-orders', [
'records' => $records,
])
->landscape()
->margins(0, 0, 0, 0)
->format('a4')
->name("test.pdf");

return response()->stream(function () use ($pdfBuilder) {
echo base64_decode($pdfBuilder->base64());
}, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="test.pdf"'
]);
}),
Action::make('downloadPdf')
->label('Download Pdf')
->icon('heroicon-o-arrow-down-tray')
->action(function (Component $livewire) {
$records = $livewire->getTableRecords();

$pdfBuilder = Pdf::view('filament.pdf.group-orders', [
'records' => $records,
])
->landscape()
->margins(0, 0, 0, 0)
->format('a4')
->name("test.pdf");

return response()->stream(function () use ($pdfBuilder) {
echo base64_decode($pdfBuilder->base64());
}, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="test.pdf"'
]);
}),
But this still just downloads the pdf file.
ralphjsmit
ralphjsmitβ€’8mo ago
No idea tbh, perhaps you can look on how this is achieved in a generic Livewire component
nowak
nowakβ€’8mo ago
I ended up just creating a test route for my view in web.php:
Route::get('/test-pdf', function () {
$records = GroupOrder::get();

return view('filament.pdf.group-orders', [
'records' => $records
]);
});
Route::get('/test-pdf', function () {
$records = GroupOrder::get();

return view('filament.pdf.group-orders', [
'records' => $records
]);
});
As I just wanted to see the output without needing to download the pdf to check changes during development.
ralphjsmit
ralphjsmitβ€’8mo ago
Makes sense, I generally have a /debug route in my applications that's only available locally (and on production perhaps for admins), that's helpful sometimes a well
nowak
nowakβ€’8mo ago
Ahh yeah that sounds really helpful! Thanks for the tip!
hashim199
hashim199β€’7mo ago
i want to generate pdf on create. when the user click on create in should fetch the current and generate its pdf > ihave placed dd in the controller and view it works fine but it doesnot download the pdf 😦 protected function mutateFormDataBeforeCreate(array $data): array { $controller = new BillPanelReports(); $controller->tess($data); return $data; } class BillPanelReports extends Controller {
public function tess( $data) { //dd($data); $pdf = PDF::loadView('printbill', compact('data'));
// Download the PDF with the specified file name return $pdf->download('Bill.pdf'); } } Route::get('/print-bill/{data}', [BillPanelReports::class, 'tess'])->name('print-bill'); <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Print Bill</title> </head> <body> <h1>Print Bill</h1> <?php //dd($data['total']); ?></body> </html> Action::make('pdf') ->icon('heroicon-o-document') ->url(function (Bill $bill) {
return route('print-bill',$bill); }), but when i am using it in action it is working #β“β”Šhelp ?
Want results from more Discord servers?
Add your server