Laravel8でPDFを出力する(laravel-dompdf)

laravelでPDFファイルを出力

laravel環境でPDF出力する案件がありましたので、対応方法をご紹介

上記はLaravel-adminの画面ですが、もちろん普通にLaravelで利用できます。

確認済みのLaravelのバージョンは8.Xです。
6.X以降であれば問題なく動作するはずです。

LaravelでPDF出力する方法

パッケージが一番手っ取り早い。有名どころでは下記の2つ

  • laravel-dompdf
  • Snappy

はじめはSnappyで取り組んでいたのですが、一部うまくいかない部分があったのでlaravel-dompdfへ方針転換

それらを比較するとこんな感じ

larave-dompdfsnappy
インストールの手間×
機能
日本語対応××

snappyの方が高機能、らしい。いまのところlarava-dompdfでも不満か感じません。

どちらも海外プラグインのため日本語化するのはパッケージインストール以外に作業が必要です。これが面倒。でも大事な作業なのでがんばりましょう。

Laravel-dompdfのインストール

コマンドこの通り

$ composer require barryvdh/laravel-dompdf
Using version ^0.8.5 for barryvdh/laravel-dompdf

インストールが完了したら、サービスプロバイダとエイリアスに登録する必要があります。

両方とも「config/app.php 」ファイルに追記していきます。

まずはサービスプロバイダ部分

    'providers' => [
 ・
 ・
 ・
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
        Barryvdh\DomPDF\ServiceProvider::class,


次にエイリアス部分

 
  'aliases' => [
 ・
 ・
 ・
        Illuminate\View\ViewServiceProvider::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
        'PDF' => Barryvdh\DomPDF\Facade::class,


これでインストールと準備が完了しました。

PDFの呼び出し

呼び出し方はbladeテンプレートを呼び出す方法とほとんど同じです。

route設定

まずはroute.phpにパスとコントローラの設定を記述します。今回は顧客氏名などをPDFに出力する必要があったので、パラメータとしてcustomer_idを渡しています。

下記のサンプルはlarave-admin側にコントローラを設定する方法になります。パスにご注意ください。

    $router->get('/pdf/dl/{customer_id}', 'PdfController@index')->name('pdf.dl');
    $router->get('/pdf/view/{customer_id}', 'PdfController@view')->name('pdf.view');

コントローラ設定

namespace App\Admin\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Customer;
use Barryvdh\DomPDF\Facade as PDF;
use Carbon\Carbon;
use Encore\Admin\Layout\Content;


class PdfController extends Controller
{
    public function index($customer_id)
    {
        $customer = Customer::whereId($customer_id)->first();
        $date = new Carbon();

        $pdf=PDF::loadView('admin.nouhin',compact('customer','date'));
        return $pdf->download('納品書.pdf'); //こちらがダウンロード用機能
    }

    public function view($customer_id)
    {
        $customer = Customer::whereId($customer_id)->first();
        $date = new Carbon();

        return view('admin.nouhin',compact('customer','date')); //こちらがブラウザ表示用機能
    }
}

indexがPDFをダウンロードする機能、viewがブラウザ上にそのままPDFを開く機能としています。

Using $this when not in object context エラー

注意事項というより私がはまったこと。

IDE補完機能で「PDF」の宣言に対するインポートをuse宣言していたのですが、気付かぬうちに下記になっていました。

use Barryvdh\DomPDF\PDF;

正しくは上のサンプルにもある通り、Facadeを利用する必要があります。

use Barryvdh\DomPDF\Facade as PDF;

これに気付かず数時間無駄にしました、、

『Error Using $this when not in object context』というエラーに遭遇したらインポート宣言を見直してみてください。

use Barryvdh\DomPDF\PDF
ではなく
use Barryvdh\DomPDF\Facade as PDF;
です!!

日本語化

ここまででPDFの出力は完了したかと思います。しかし、出力されたPDFを見ると

?????

のように文字化けしているはずです。海外製プラグインなのでそのままでは日本語が表示できません。

下記の手順で日本語対応が必要です。

load_font.phpダウンロード

IPAフォントをダウンロードします。

IPAフォントダウンロード

明朝とゴシック2つの書体があります。2書体パックをダウンロードしておいた方が後で手間がないかと思います。

ダウンロードしたらLaravelをインストールしたディレクトリ直下にtempなどの適当なディレクトリを作成し保存します。

tempフォルダを作成

フォントファイルインストール

$ php load_font.php ipaexg temp/ipaexg.ttf

ゴシックフォントをインストールする場合は「ipaexg」の2か所を「ipaexm」に書き換えてください。

フォントのコピー

load_font.phpを実行してvendor/dompdf/dompdf/lib/fontsディレクトリに作成された、ipagexf.ttf, ipagexg.ufm, dompdf_font_family_cache.phpをstorage/fontsにコピーします。

Bladeテンプレートでフォントを指定

設定が完了したらPDF出力用のテンプレートを修正していきます。このBladeテンプレートでインストールしたフォントをCSSで指定します。

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>PDF</title>
<style>
body {
font-family: ipaexg;
}
</style>
</head>
<body>
    <h1>PDFテスト&amp;lt;/h1>
</div>
</body>
</html>

これで日本語のPDFが出力されるようになりました。

Undefined offset: 12239 エラーが出力される場合

フォントファイルの相性なのか、エラーが出る場合があります。フォントファイルを変更してみましょう。

私はMigMixというフォントを利用させて頂き解消しました。

MigMixダウンロード

小ネタ

PDFでQRコードを表示する場合の記述

<img src="data:image/png;base64, {{ base64_encode(QrCode::format('png')->size(100)->generate('Make me into an QrCode!')) }} ">

まとめ

LaravelからPDF出力する場合にはlarave-dompdfを利用することで対応できるました。日本語化が少し手間ですが、一度慣れてしまえば大丈夫そうです。

HTMLのテンプレートをベースに手軽にPDF出力できるので、ぜひ利用してみてください。

コメントを残す