CakePHPとTCPDFを使ってPDFを作成する

元記事はこちら

By kalileo

CakePHP 1.2 では、PDFを作成するのがより簡単になりました。このチュートリアルでは、簡単にPDFファイルを作成するために、CakePHPと、強力なツールであるTCPDFをどのように連携させるかを示します。


TCPDFはPDFドキュメントを生成するためのオープンソースのPHPのクラスです。FPDF[のプロジェクト]が止まってしまっても続いていますし、加えてUTF-8のUnicode対応でRTL言語にも対応しています。特に英語圏でない国に住む人々にとってはUTF-8のUnicode対応は課題であったことでしょう。

ステップ1:TCPDFのダウンロードとインストール

  1. http://www.tcpdf.orgにアクセスし、TCPDFの最新バージョンをダウンロードする
  2. app/vendorsのような、ベンダーディレクトリにアーカイブを解凍する。「tcpdf」ディレクトリが作成され、tcpdf.phpなどのファイルが抽出されます。最低でも「tcpdf/config」「tcpdf/fonts」 は必要です。
  3. TCPDFの設定を行う。TCPDFのドキュメントを参照します。最低でも「tcpdf/config/tcpdf_config.php」は調整する必要があります。

ステップ2:TCPDFを拡張して、ヘッダとフッタをカスタマイズする

TCPDFにはデフォルトのヘッダとフッタ、「header()」と「footer()」のメソッドが定義されており、必要に応じて上書きできるようになっています。TCPDFを拡張して、アプリケーションから拡張したTCPDFクラスを呼び出すように実装します。

「app/vendors」で、xtcpdf.phpを作成し、以下の内容にします。

<?php 
App::import('Vendor','tcpdf/tcpdf'); 
 
class XTCPDF  extends TCPDF 
{ 
 
    var $xheadertext  = 'PDF created using CakePHP and TCPDF'; 
    var $xheadercolor = array(0,0,200); 
    var $xfootertext  = 'Copyright © %d XXXXXXXXXXX. All rights reserved.'; 
    var $xfooterfont  = PDF_FONT_NAME_MAIN ; 
    var $xfooterfontsize = 8 ; 
 
 
    /** 
    * Overwrites the default header // デフォルトのheader()関数を上書き
    * set the text in the view using // ビューの文字列は以下のようにして設定します。
    *    $fpdf->xheadertext = 'YOUR ORGANIZATION'; 
    * set the fill color in the view using // ビューの塗りつぶしの色は以下のようにして設定します。
    *    $fpdf->xheadercolor = array(0,0,100); (r, g, b) 
    * set the font in the view using // ビューのフォントは以下のようにして設定します。
    *    $fpdf->setHeaderFont(array('YourFont','',fontsize)); 
    */ 
    function Header() 
    { 
 
        list($r, $b, $g) = $this->xheadercolor; 
        $this->setY(10); // shouldn't be needed due to page margin, but helas, otherwise it's at the page top
        $this->SetFillColor($r, $b, $g); 
        $this->SetTextColor(0 , 0, 0); 
        $this->Cell(0,20, '', 0,1,'C', 1); 
        $this->Text(15,26,$this->xheadertext ); 
    } 
 
    /** 
    * Overwrites the default footer // デフォルトのfooter()を上書き
    * set the text in the view using // ビューの文字列は以下のようにして設定します。
    * $fpdf->xfootertext = 'Copyright © %d YOUR ORGANIZATION. All rights reserved.'; 
    */ 
    function Footer() 
    { 
        $year = date('Y'); 
        $footertext = sprintf($this->xfootertext, $year); 
        $this->SetY(-20); 
        $this->SetTextColor(0, 0, 0); 
        $this->SetFont($this->xfooterfont,'',$this->xfooterfontsize); 
        $this->Cell(0,8, $footertext,'T',1,'C'); 
    } 
} 
?>

当然ながら、”YOUR ORGANIZATION”(組織名)などは自分のものに調整し、コードはお好きなように調整してください。詳細はTCPDFのドキュメントを参照してください。

ステップ3:PDFのためのレイアウトを作成する

デフォルトのレイアウトは使用できません。PDFファイルをHTMLのコードで挟むことになるからです。レイアウトファイルを以下の内容で作成し、「app/views/layouts/pdf.ctp」として保存します。

<?php 
header("Content-type: application/pdf"); 
echo $content_for_layout; 
?>

ステップ4:コントローラを作成する

コントローラにはPDFを出力するメソッドを用意するでしょう。ここでは私が以前に作った実際のアプリケーションで、不動産のデータと画像を含むきれいなPDFを印刷したときのものを例にします。

    function viewPdf($id = null) 
    { 
        if (!$id) 
        { 
            $this->Session->setFlash('Sorry, there was no property ID submitted.'); 
            $this->redirect(array('action'=>'index'), null, true); 
        } 
        Configure::write('debug',0); // こうしておかないとデバッグモードで動作できません。
 
        $id = intval($id); 
 
        $property = $this->__view($id); // ここでデータベースから値を取得し、ビューにセットします。
 
        if (empty($property)) 
        { 
            $this->Session->setFlash('Sorry, there is no property with the submitted ID.'); 
            $this->redirect(array('action'=>'index'), null, true); 
        } 
 
        $this->layout = 'pdf'; //レイアウトファイル「pdf.ctp」を使用します。
        $this->render(); 
    }

必要に応じて調整してください。重要な部分はレンダリング前にPDFレイアウトを選択するということです。

        $this->layout = 'pdf'; //レイアウトファイル「pdf.ctp」を使用します。
        $this->render();

ステップ5:ビューを作成する

ここでマジックが起こります。CakePHPでは、vendorをビューから直接ロードでき、ヘルパーを作成する必要がないからです。TCPDFライブラリは大きくてインクラスだけで現在9600行ほどのコードがありますが、PDFの作成に実際に使用するとき、tcpdf.phpだけがロードされます。vendorは外部のヘルパーのように動作します。注意:意図されたものかどうかは筆者は知りませんが、考えれば考えるほどこの方法が気に入ります。とてもエレガントで効率的で、CakePHPの力と柔軟性を示しています。

色々言うよりも、コードを見たほうが早いですね。

訳者注:これは上記の例で作成している場合、「view_pdf.ctp」という名称で保存します。

ビューテンプレート:

<?php 
App::import('Vendor','xtcpdf');  
$tcpdf = new XTCPDF(); 
$textfont = 'freesans'; // 見た目もいいし、きれいで、「dejavusans」よりスリムです。 
//日本語フォントの指定についてはこの記事の末尾を参照してください。
 
$tcpdf->SetAuthor("KBS Homes & Properties at http://kbs-properties.com"); 
$tcpdf->SetAutoPageBreak( false ); 
$tcpdf->setHeaderFont(array($textfont,'',40)); 
$tcpdf->xheadercolor = array(150,0,0); 
$tcpdf->xheadertext = 'KBS Homes & Properties'; 
$tcpdf->xfootertext = 'Copyright © %d KBS Homes & Properties. All rights reserved.'; 
 
// ページを追加(最近のバージョンのtcpdfで必要になった)
$tcpdf->AddPage(); 
 
// ページの内容の位置を決めプリントする。
// 例:
$tcpdf->SetTextColor(0, 0, 0); 
$tcpdf->SetFont($textfont,'B',20); 
$tcpdf->Cell(0,14, "Hello World", 0,1,'L'); 
// ... 
// など。
// TCPDF の例を参照。
 
echo $tcpdf->Output('filename.pdf', 'D'); 
 
?>

簡単でしょ!これで全部です。

以下のQ&AはFPDFヘルパーに関心のあるユーザ向けです。

FPDFじゃだめなの?

私が使わないのは、Unicode対応していないことが大きな理由です。Dievolution blogに掲載されている、FPDFのCellメソッドをハックする方法で限定的にUnicode対応にすることはできますが、であれば、TCPDFじゃだめなの?ということになります。ハックは不要だし、TCPDFの作者Nicola Asuniはとてもアクティブで、ほぼ毎週新しいアップデートをリリースしています。

更新:FPDFは現在Unicode対応になったようですが、筆者はテストしていません。開発もきちんと進んでいるようです。

bakeryにあるFPDFヘルパーはどうなの?

そのヘルパーを何度も使いました。CakePHP1.1でうまく動作しました。1.2betaか1.2RCあたりでうまく動作しなくなりました。私見ですがうまく実装されていないのでしょう。

FPDFクラスを直接継承しているのですが、HelperはHelperクラスを継承すべきです。例えばAppHelperクラスです。

FPDFヘルパーの実装方法は以下のとおりです。CakePHP1.1で動く 動いていましたが、正しくありません。

class FpdfHelper extends FPDF

以下は正しい記述方法ですが、これでは動作しません。

class FpdfHelper extends AppHelper

CakePHP 1.2の開発のどこかで、ヘルパーの初期化の際に第一引数を配列で受け取るように変更されたのでしょう。AppHelperを継承するヘルパーはそれを適切に取り扱うはずでしたが、FPDFはその配列を第一引数:ページの向きとして取り扱っているようです。

ハックしたFPDFヘルパーはCakePHP 1.2でも動作しますか?

はい、動作します。しかし、先に示したようにその必要はなく解決になりません。FPDFメソッドの一行目(私のバージョンだと78行目です)に以下のFPDFコードを追加すればいいんです。

if (is_array($orientation)) return;

以下のようになります。

function FPDF($orientation='P',$unit='mm',$format='A4') 
{ 
    if (is_array($orientation)) return; 
    ...

ヘルパーの初期化を無視できますが、FPDFヘルパーのsetup()メソッドのように、あとで呼び出したときでも正しく動作します。

$this->FPDF($orientation, $unit, $format);

このFPDFハックがCakePHP1.2で必要なくなるのはなぜ?

FPDF も TCPDF も外部ライブラリで、CakePHPのVendorsに統合できます。CakePHP 1.2からはVendorsのインクルード方法が変わり、

vendor("fpdf/fpdf")

から

App::import('Vendor','fpdf/fpdf');
- TCPDFの場合は -  
App::import('Vendor','tcpdf/tcpdf');

になりました。

この変更は大したものではないです。それでも、ビューからTCPDFを使用するためには、以下のようなラップするクラスが必要です。

ヘルパークラス:

<?php 
App::import('Vendor','xtcpdf'); 
 
class TcpdfHelper extends AppHelper { 
    var $pdf; 
    function setup() { 
        $this->pdf = new XTCPDF(); 
    } 
} 
?>

そして、$tcpdf->pdf->hoge() のようにしてビューから呼び出すことができます。

幸運にもこれは必要ありません。CakePHP 1.2 RC2から App::import を直接ビューで使用できるからです。上記を参照してください 🙂

(翻訳終わり)

訳者より

日本語対応させるためには、フォント指定部分で日本語を表示できるフォントを指定する必要があります。
たとえば、小塚ゴシックMを使うには「kozgopromedium」と指定します。
小塚明朝Rを使うには「kozminproregular」と指定します。

3 thoughts on “CakePHPとTCPDFを使ってPDFを作成する”

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です