Создаем класс для генерации PDF чеков с динамической высотой

от автора

в
Время чтения: 3 мин.

В веб-приложениях часто требуется генерировать 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');

Дополнительные улучшения

Чтобы сделать класс еще более полезным, можно добавить:

  1. Поддержку пользовательских стилей CSS
  2. Методы для установки ширины документа
  3. Обработку ошибок
  4. Кэширование сгенерированных PDF

Заключение

Мы создали удобный класс для генерации PDF документов с автоматическим расчетом высоты. Такой подход особенно полезен при работе с чеками и отчетами, где размер содержимого может меняться. Класс инкапсулирует всю логику работы с Dompdf, предоставляя простой и понятный API.

Это решение можно легко интегрировать в любой PHP-проект, будь то Laravel, Symfony или чистый PHP. Дальнейшее развитие класса может включать добавление поддержки колонтитулов, нумерации страниц и других полезных функций для генерации профессиональных документов.


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Сколько будет 3 + 4?