Laravel 7とSnappyでPDFを出力する


はじめに

LaravelでPDFを出力する方法です。

完成版のソースは以下に置いてあります。
https://github.com/naga3/snappy-sample

Laravelで使えるPDF出力ライブラリ

今回はバランスを考えてLaravel Snappyを選択しました。

Laravelプロジェクト作成

コチラを参考に適当なプロジェクトを作成します。Composerがインストールされていれば簡単に作成できます。

composer create-project --prefer-dist laravel/laravel snappy-sample
cd snappy-sample

Laravel Snappyのインストール

Laravel Snappyのドキュメントを見て進めて行きます。

まずwkhtmltopdfをインストールしますが、こちらもComposerで簡単に導入できます。WindowsやMacなど、バイナリが適合しない場合は上記ドキュメントを参照してください。

composer require h4cc/wkhtmltopdf-amd64 0.12.x

次にLaravel Snappy本体をインストールします。

composer require barryvdh/laravel-snappy

configファイルを作ります。

php artisan vendor:publish --provider="Barryvdh\Snappy\ServiceProvider"

configファイルにwkhtmltopdfの場所を書きます。上記のようにComposerからインストールした場合は

config/snappy.php
'binary' => base_path('vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64'),

PDF出力のテスト

正常にインストールできたかチェックしてみます。

routes/web.php
Route::get('/hello', function () {
    return PDF::loadHTML('<h1>Hello!</h1>')->inline();
});

 大丈夫そうですね。

Bladeを使ってPDFを出力する。

Snappyは、BladeにそのままHTMLを書いて出力できるので大変楽です。CSSも2くらいまでは正確に効きます。

まずRouteの部分です。

routes/web.php
Route::get('/members', function () {
    $member = Faker\Factory::create('ja_JP');
    return PDF::loadView('members', compact('member'))->inline();
});

Fakerでランダムなデータを生成してviewに渡しています。

次にテンプレートの部分です。

resources/views/members.blade.php
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <title>名簿</title>
  <style>
    table {
      border-collapse: collapse;
    }

    tr {
      page-break-inside: avoid;
    }

    th,
    td {
      border: 1px solid black;
    }
  </style>
</head>

<body>
  <h1>名簿</h1>
  <table>
    <tr>
      <th>No.</th>
      <th>氏名</th>
      <th>住所</th>
      <th>電話番号</th>
      <th>備考</th>
      @for ($no = 1; $no <= 50; $no++) <tr>
        <td>{{ $no }}</td>
        <td style="white-space: nowrap">{{ $member->name }}</td>
        <td>{{ $member->address }}</td>
        <td>{{ $member->phoneNumber }}</td>
        <td>{{ $member->realText }}</td>
    </tr>
    @endfor
  </table>
</body>

</html>

ブラウザで確認してみます。

良さそうですね。

tr要素にpage-break-inside: avoid;を適用することによって、セルの途中で改ページされなくなります。

こんな感じ。