
Laravel: генеруємо pdf з html
28.02.2019 05:46 | Laravel
Припускаю, що кожен розробник стикається з необхідністю генерувати pdf-файли. Тому пропоную коротко розглянути один з варіантів реалізації даного функціоналу в Laravel.
Версія фреймворку на момент написання статті - 5.7.
Винаходити велосипед не будемо, скористаємося пакетом barryvdh/dompdf.
Інсталяція:
composer require barryvdh/laravel-dompdf
Відкриваємо config/app.php
і додаємо ServiceProvider
в масив провайдерів, заодно в цьому ж файлі додамо аліас:
...
'providers' => [
/*
* Package Service Providers...
*/
Barryvdh\DomPDF\ServiceProvider::class,
],
...
'aliases' => [
...
'PDF' => Barryvdh\DomPDF\Facade::class,
]
Створимо роут для завантаження в routes/web.php
:
Route::get('invoices/download', 'InvoiceController@download');
і відповідний контролер:
php artisan make:controller InvoiceController
Оскільки мета статті показати як генерується pdf, я не буду створювати моделі, а прямо в методі контролера напишу фейкові дані (і то не всі). Код контролера:
<?php
namespace App\Http\Controllers;
use PDF;
class InvoiceController extends Controller
{
public function download()
{
$products = [
['title' => 'Product 1', 'price' => 10.99, 'quantity' => 1, 'totals' => 10.99],
['title' => 'Product 2', 'price' => 14.99, 'quantity' => 2, 'totals' => 29.98],
['title' => 'Product 3', 'price' => 500.00, 'quantity' => 1, 'totals' => 500.00],
['title' => 'Product 4', 'price' => 6.99, 'quantity' => 3, 'totals' => 20.97],
];
$total = collect($products)->sum('totals');
$pdf = PDF::loadView('pdf.invoice', compact('products', 'total'));
return $pdf->download('invoice.pdf');
}
}
Залишилося лише представлення - в директорії views
створимо піддиректорію pdf
, і в ній файл invoice.blade.php
. Однак, тут нас очікує сюрприз - пакет не підтримує зовнішні стилі (принаймні, я не знайшов спосіб змусити його розуміти Bootstrap). В кінцевому підсумку довелося використовувати табличну верстку і прописувати стилі інлайн:
<!DOCTYPE html>
<html>
<head>
<title>Invoice Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div style="width: 100%; max-width: 960px; margin: auto">
<table width="100%">
<tr style="border-bottom: 1px solid #000000">
<td><h2>Invoice</h2></td>
<td style="text-align: right"><h3>Order # 12345</h3></td>
</tr>
<tr>
<td style="padding-bottom: 16px;">
<strong>Billed To:</strong><br>
John Smith<br>
1234 Victory Avenue<br>
Apt. 5D<br>
Sunfield, ST 54321
</td>
<td style="text-align: right; padding-bottom: 16px;">
<strong>Shipped To:</strong><br>
John Smith<br>
1234 Victory Avenue<br>
Apt. 5D<br>
Sunfield, ST 54321
</td>
</tr>
<tr>
<td>
<strong>Payment Method:</strong><br>
Visa ending **** 4242<br>
jsmith@email.com
</td>
<td style="text-align: right">
<strong>Order Date:</strong><br>
March 7, 2014<br><br>
</td>
</tr>
<tr>
<td colspan="2">
<h3>Order summary</h3>
</td>
</tr>
<tr>
<td colspan="2">
<table width="100%" cellpadding="0" cellspacing="0" border="1">
<thead>
<tr style="background-color: #eee">
<th style="text-align: left; padding: 5px 10px;">Item</th>
<th style="text-align: center; padding: 5px 10px;">Price</strong></th>
<th style="text-align: center; padding: 5px 10px;">Quantity</th>
<th style="text-align: right; padding: 5px 10px;">Totals</th>
</tr>
</thead>
<tbody>
@foreach ($products as $product)
<tr>
<td style="text-align: left; padding: 5px 10px;">{{ $product['title'] }}</td>
<td style="text-align: center; padding: 5px 10px;">{{ $product['price'] }}</td>
<td style="text-align: center; padding: 5px 10px;">{{ $product['quantity'] }}</td>
<td style="text-align: right; padding: 5px 10px;">{{ $product['totals'] }}</td>
</tr>
@endforeach
<tr>
<td colspan="2"></td>
<td style="text-align: center; padding: 5px 10px;"><strong>Totals</strong></td>
<td style="text-align: right; padding: 5px 10px;">{{ $total }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
</body>
</html>
Ось, власне, і все. Коли в адресному рядку будете вводити <your-host-name>/invoices/download
, завантажуватиметься файл invoice.pdf
.
Успіхів!