【Laravel】Viewの内容をPDFに出力する【日本語対応】

えび

Laravel 8でlaravel-dompdfを使用して
viewの内容をまるっとPDFにした際のメモ

composerでパッケージをインストールする

composer require barryvdh/laravel-dompdf
php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"

Laravel5.5以上の場合はconfig/app.phpの変更などは不要

PDFを日本語対応する

デフォルトだとdom-pdfでは日本語は非対応
なので日本語フォントを指定してあげる必要がある

1. storageディレクトリの中ににfontsディレクトリを作成 (権限は777)

cd storage
mkdir fonts
chmod -R 777 fonts

2. IPAフォントでフォントをダウンロード&storage/fonts以下に設置

今回サイト上ではゴシック体を使ってたからipaexgを選択した
ダウンロードしたzipを解凍するとttfファイルが入っているのでそれを入れる

3. 出力するviewのheadタグに、上記フォントの指定を追記する

もし他のviewと併用したい場合は下記のようにルーティングによって条件分岐すればOK
CSSもPDFの場合はフルパスを指定してあげる必要があるので条件分岐の中に入れてあげる

@if (request()->is('*/pdf'))
  <style type="text/css">
    @font-face {
      font-family: ipaexg;
      font-style: normal;
      font-weight: normal;
      src: url('{{ storage_path('fonts/ipaexg.ttf') }}') format('truetype');
    }
    @font-face {
      font-family: ipaexg;
      font-style: bold;
      font-weight: bold;
      src: url('{{ storage_path('fonts/ipaexg.ttf') }}') format('truetype');
    }
    body {
      font-family: ipaexg !important;
    }
   </style>
  
   <!-- PDFの場合はフルパスでCSSを指定する -->
   <link href="{{ public_path('css/app.css') }}" rel="stylesheet">
@else
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
@endif

これでPDFでも日本語CSSが使用できるようになった

PDF出力用のルーティングを追加

  • routes/web.php
Route::get('/output/pdf', [OutputController::class, 'pdf']);

これで、/output/pdfにアクセスした際にPDFを出力するようにしてみる

ControllerにPDF出力用のメソッド実装

  • OutputController.php
<?php

namespace App\Http\Controllers;

use use PDF; 

class TraineeController extends Controller
{
  public function outputPdf()
  {
    /**
     * 出力したいviewを読み込む
     * この場合、views/output/pdf.blade.phpを出力する
     * パラメータを渡したい場合、普段のview()関数と同様に第二引数に指定してあげればOK
     * PDF::loadView('output.pdf', ['message' => 'Hello']);
     */
    $pdf = PDF::loadView('output.pdf');
    // PDF出力 (引数にはPDFのファイル名を設定できる)
    return $pdf->stream('pdf_file.pdf');

    // PDFをダウンロードしたい場合はこっち
    // return $pdf->download('pdf_file.pdf');
}