Генерация PDF — частая задача в веб-разработке. Отчёты, счета, договоры, прайсы — всё это нужно превращать в красивые файлы. В Yii2 это можно сделать разными способами. Но какой выбрать, чтобы не наступить на грабли? В этой статье разберём три популярных подхода: через Dompdf, mpdf и TCPDF. Покажу примеры, сравню их и дам советы, как не сойти с ума при отладке.

Почему для Yii2 стоит использовать расширения, а не писать велосипед?

Yii2 — это фреймворк, который любит готовые решения. Вместо того чтобы вручную подключать библиотеки и настраивать рендеринг, можно взять готовое расширение из Composer. Почему это удобно? Во-первых, расширения уже интегрированы с Yii2 — они используют его компоненты, настройки и пути. Во-вторых, они решают типовые проблемы: кодировка, шрифты, разрывы страниц. В-третьих, вы получаете поддержку сообщества. Если что-то сломалось — скорее всего, кто-то уже нашёл решение.

Я рекомендую использовать расширения kartik-v/yii2-mpdf или miloschuman/yii2-dompdf. Они проверены временем и имеют хорошую документацию.

Обзор трёх популярных библиотек: Dompdf, mpdf, TCPDF

Чтобы выбрать подходящую библиотеку, нужно понимать их сильные и слабые стороны. Я составил таблицу, которая поможет сориентироваться.

БиблиотекаПлюсыМинусыКогда использовать
DompdfПростая установка, поддержка CSS, быстро работает с простыми макетамиПлохо поддерживает float, flexbox, сложные таблицы; медленная на больших объёмахДля простых документов с минимальной вёрсткой
mpdfОтличная поддержка CSS, вложенных таблиц, Unicode, шрифтов; гибкая настройкаТребователен к памяти, большой размер библиотекиДля сложных отчётов, счетов, книг с оглавлением
TCPDFЛёгкий, быстрый, не требует дополнительных библиотек; хорош для простых текстовых документовСлабая поддержка CSS, вёрстка через PHP-методы (неудобно для дизайна)Для текстовых PDF с минимумом оформления

Установка и настройка расширения для mpdf в Yii2

Начнём с самого популярного варианта — mpdf. Устанавливаем через Composer:

composer require kartik-v/yii2-mpdf

После установки нужно настроить компонент в конфигурации приложения. Откройте файл config/web.php и добавьте:

'components' => [
    'pdf' => [
        'class' => 'kartik\mpdf\Pdf',
        'mode' => 'utf-8',
        'format' => 'A4',
        'orientation' => 'P',
        'destination' => 'I',
        'cssFile' => '@app/web/css/pdf.css',
        'options' => [
            'title' => 'Мой документ',
            'subject' => 'Отчёт',
        ],
    ],
],

Разберём параметры:

  • mode — кодировка. Всегда ставьте utf-8, чтобы не было проблем с русскими буквами.
  • format — размер страницы. Можно использовать A4, Letter, Legal или кастомный массив.
  • orientation — ориентация: P (portrait) или L (landscape).
  • destination — что делать с PDF: I (inline — показать в браузере), D (download — скачать), F (file — сохранить на сервере), S (string — вернуть строку).
  • cssFile — путь к CSS-файлу, который будет применён к HTML перед генерацией.

Теперь можно генерировать PDF в контроллере.

Пример генерации PDF с помощью mpdf

Допустим, у нас есть действие actionInvoice в контроллере. Мы хотим сгенерировать счёт на основе данных из модели Order.

public function actionInvoice($id)
{
    $order = Order::findOne($id);
    if (!$order) {
        throw new NotFoundHttpException('Заказ не найден');
    }

    $content = $this->renderPartial('invoice', [
        'order' => $order,
    ]);

    $pdf = new Pdf([
        'mode' => 'utf-8',
        'format' => 'A4',
        'orientation' => 'P',
        'destination' => 'I',
        'content' => $content,
        'cssFile' => '@app/web/css/pdf.css',
        'options' => [
            'title' => 'Счёт №' . $order->id,
        ],
    ]);

    return $pdf->render();
}

Обратите внимание: мы используем renderPartial, а не render. Это важно, чтобы в PDF не попал лишний HTML-каркас (хедер, футер, скрипты). В представлении invoice.php пишем обычный HTML с CSS-классами. Например:

<div class="invoice">
    <h1>Счёт № <?= $order->id ?></h1>
    <p>Дата: <?= $order->created_at ?></p>
    <table class="items">
        <tr>
            <th>Товар</th>
            <th>Цена</th>
        </tr>
        <?php foreach ($order->items as $item): ?>
        <tr>
            <td><?= $item->name ?></td>
            <td><?= $item->price ?></td>
        </tr>
        <?php endforeach; ?>
    </table>
    <p class="total">Итого: <?= $order->total ?></p>
</div>

После этого в браузере откроется PDF с готовым счётом.

Лайфхак: Если PDF отображается пустым или с ошибками, проверьте, не выводится ли лишний пробел или символ перед <?php в представлении. Часто проблема в невидимых пробелах после закрывающего тега ?>. Используйте ob_clean() перед рендерингом, чтобы очистить буфер.

Как добавить водяные знаки и колонтитулы

В mpdf можно легко добавить водяной знак или номер страницы. Для этого используйте методы объекта mPDF после создания экземпляра. Вот пример с водяным знаком:

$pdf = new Pdf([
    'mode' => 'utf-8',
    // ... другие настройки
]);

$mpdf = $pdf->getApi();
$mpdf->SetWatermarkText('Черновик', 0.2);
$mpdf->showWatermarkText = true;
$mpdf->watermark_font = 'DejaVuSans';

return $pdf->render();

Для колонтитулов используйте HTML-разметку в свойствах setHeader и setFooter:

$mpdf->setHeader('<div style="text-align: right;">Страница {PAGENO}</div>');
$mpdf->setFooter('<div style="text-align: center;">ООО "Моя компания"</div>');

Переменная {PAGENO} автоматически заменится на номер текущей страницы. Это удобно для отчётов.

Правило: всегда тестируйте PDF на реальных данных

Кажется очевидным, но многие забывают. PDF, сгенерированный на тестовых данных с короткими строками, может выглядеть отлично. А на реальных данных — разъехаться. Особенно это касается таблиц с длинным текстом. Поэтому правило простое: всегда проверяйте генерацию на данных, максимально приближенных к боевым. Используйте длинные названия товаров, большие числа, переносы строк. И только после этого выкатывайте в продакшн.

Что в итоге

Мы разобрали, как генерировать PDF в Yii2 с помощью mpdf. Установили расширение, настроили компонент, создали действие в контроллере и добавили водяные знаки. Вы узнали, чем отличаются Dompdf, mpdf и TCPDF, и в каких случаях их использовать. Теперь вы сможете создавать счета, отчёты и другие документы без лишней головной боли. Главное — помните про лайфхак с очисткой буфера и тестируйте на реальных данных.

Студия WNDER