В веб-приложениях часто требуется генерировать PDF документы — чеки, отчеты, счета. Сегодня мы создадим удобный класс на PHP для этой задачи с использованием библиотеки Dompdf, который будет автоматически подстраивать высоту документа под его содержимое.
Устанавливаем зависимости
Прежде чем начать, убедитесь, что установлен пакет Dompdf:
composer require dompdf/dompdf
Создаем базовую структуру класса
Создадим файл ReceiptPdf.php
и начнем с объявления класса и свойств:
use Dompdf\Dompdf;
use Dompdf\FrameDecorator\AbstractFrameDecorator;
class ReceiptPdf
{
private string $html;
private int $width = 226; // Ширина чека по умолчанию
private int $height = 300; // Начальная высота
// Далее будут методы класса
}
Добавляем метод для установки HTML
Создадим метод, который будет принимать HTML-контент для преобразования в PDF:
public function withHtml(string $html): self
{
$this->html = $html;
return $this;
}
Реализуем расчет высоты содержимого
Самый интересный и полезный метод — автоматический расчет высоты документа:
private function calcHeight(string $html): void
{
$this->height = 1; // Сбрасываем высоту
$dompdf = new Dompdf();
$dompdf->setPaper([0, 0, $this->width, 1000]);
// Устанавливаем callback для расчета высоты
$dompdf->setCallbacks([
'calcHeight' => [
'event' => 'end_frame',
'f' => function (AbstractFrameDecorator $infos) {
$frame = $infos->get_frame();
if (strtolower($frame->get_node()->nodeName) === 'body') {
$box = $frame->get_padding_box();
$this->height = $box['h'] + 10; // Добавляем небольшой отступ
}
}
]
]);
$dompdf->loadHtml($html);
$dompdf->render();
}
Основной метод генерации PDF
Теперь реализуем главный метод, который будет создавать PDF документ:
public function generatePdf(): string
{
$this->calcHeight($this->html);
$dompdf = new Dompdf();
$dompdf->setPaper([0, 0, $this->width, $this->height]);
$dompdf->loadHtml($this->html);
$dompdf->render();
return $dompdf->output();
}
Добавляем удобные методы для работы с PDF
Сделаем наш класс более практичным, добавив методы для сохранения и вывода PDF:
// Сохраняем PDF в файл
public function saveToFile(string $filename): bool
{
return file_put_contents($filename, $this->generatePdf()) !== false;
}
// Отправляем PDF в браузер для просмотра
public function stream(string $filename = 'receipt.pdf')
{
return response($this->generatePdf())
->header('Content-Type', 'application/pdf')
->header('Content-Disposition', "inline; filename=\"{$filename}\"");
}
// Инициируем загрузку PDF
public function download(string $filename = 'receipt.pdf')
{
return response($this->generatePdf())
->header('Content-Type', 'application/pdf')
->header('Content-Disposition', "attachment; filename=\"{$filename}\"");
}
Пример использования класса
Вот как можно использовать наш класс в реальном проекте:
// Создаем HTML содержимое
$html = '
<html>
<head>
<style>
@page { margin: 0; padding: 0; }
body { font-family: DejaVu Sans, Arial; padding: 10px; }
h1 { color: #333; font-size: 18px; }
.item { margin-bottom: 5px; }
.total { font-weight: bold; margin-top: 10px; }
</style>
</head>
<body>
<h1>Чек покупки</h1>
<div class="item">Товар 1 - 1000 руб.</div>
<div class="item">Товар 2 - 1500 руб.</div>
<div class="total">Итого: 2500 руб.</div>
</body>
</html>';
// Генерируем и скачиваем PDF
$pdf = new ReceiptPdf();
$pdf->withHtml($html)->download('my_receipt.pdf');
Дополнительные улучшения
Чтобы сделать класс еще более полезным, можно добавить:
- Поддержку пользовательских стилей CSS
- Методы для установки ширины документа
- Обработку ошибок
- Кэширование сгенерированных PDF
Заключение
Мы создали удобный класс для генерации PDF документов с автоматическим расчетом высоты. Такой подход особенно полезен при работе с чеками и отчетами, где размер содержимого может меняться. Класс инкапсулирует всю логику работы с Dompdf, предоставляя простой и понятный API.
Это решение можно легко интегрировать в любой PHP-проект, будь то Laravel, Symfony или чистый PHP. Дальнейшее развитие класса может включать добавление поддержки колонтитулов, нумерации страниц и других полезных функций для генерации профессиональных документов.
Добавить комментарий