CakePHP で簡易なPDFを作成する

CakePHP 2.0 で、簡易的ではあるが PDF を作成する方法を2つ試してみた。

  1. View (PdfViewクラス) を作成する方法
  2. View レイアウト (pdf.ctp) を作成する方法 [オススメ]

HTML から PDF が生成できるのであれば、CakePHP の View の変更で HTML/PDF を切り替えできれば便利なのではないかと考えた。例えば、プレビュー時は HTML で、最終的には PDF で出力するなどの機能が作れる。

http://d.hatena.ne.jp/okinaka/20101019/1287454452
で、mPDF を使って PDF を作成することを確認した。

mPDF の設定

2つの方法ともに、とりあえず mPDF が使えるようにする必要がある。

  1. http://www.mpdf1.com/mpdf/download から最新の mPDF をダウンロード (現在は v5.3)。
  2. app/Vendor/mpdf53 以下に mPDF 5.3 を配置。
  3. 下記のディレクトリに apache ユーザに書き込み権限を与える。一時ファイル作成に利用されるらしい。
    • app/Vendor/mpdf53/tmp
    • app/Vendor/mpdf53/graphic_cache
  4. デフォルトでは日本語フォントが無効になっているので有効にする。

app/Vendor/mpdf53/config.php:

<?php
$this->useAdobeCJK = true;

(その1)View クラスを作成する方法

PDF専用の View クラスを作成する。

app/View/PdfView.php:

<?php
App::uses('View', 'View');

class PdfView extends View {

  public $response = null;

  public function __construct($controller = null) {
     parent::__construct($controller);
     if (is_object($controller) && isset($controller->response)) {
         $this->response = $controller->response;
     } else {
         $this->response = new CakeResponse;
     }
  }

  public function render($view = null, $layout = null) {
    $html = parent::render($view, $layout);
    $this->response->type('pdf');

    $debug = Configure::read('debug');
    Configure::write('debug', 0); // 一時的にデバッグモードを解除(Notice の出力抑制)

    App::import('Vendor', 'mpdf53/mpdf');
    $mpdf = new mPDF('ja', 'A4'); // A4横の場合は、'A4-L'を指定
    $mpdf->writeHTML($html);
    $out = $mpdf->Output('', 'S');

    Configure::write('debug', $debug);
    return $out;
  }
}

コントローラ内で、以下のように記述して、普通にテンプレートを作成すればよい。

<?php
  $this->viewClass = "Pdf";

最初はこの方法が良いと考えていたのだが、イマイチしっくりこなかった。

(その2) View レイアウトを作成する方法

上記の例では View クラスを実装したが、レイアウトとして定義して使うのもありかもしれない。

app/View/Layouts/pdf.ctp:

<?php
Configure::write('debug', 0);
App::import('Vendor', 'mpdf53/mpdf');
$mpdf = new mPDF('ja', 'A4');
$mpdf->writeHTML($content_for_layout);
$mpdf->Output();

コントローラ内で、pdfレイアウトを指定する。

<?php
  $this->response->type('pdf'); // Content-Type を指定
  $this->render(null, 'pdf');  // レイアウトを指定

通常、PDFのヘッダやフッタなどレイアウトに関わる部分は、HTMLとは違うものになるので、こちらの方法の方が、統一感があってよい感じがする。

他の実装例:
http://bakery.cakephp.org/articles/kalileo/2010/06/08/creating-pdf-files-with-cakephp-and-tcpdf