PDFフレームワークをちょっと試してみた。

SugarCRMv5.5からSugarPDFフレームワークが新しく導入されました。SugarCRMv5.2以前まではPDFで帳票出力などを行いたい場合、EclipseBirtを使ったり、TCPDFなどのPDFを作成するためのライブラリを用意し、ごりごりとロジックを書く必要がありました。ようやくその苦行から解き放たれることができるかも!ってことで個人的にはv5.5で一番うれしい新機能です。そんなわけで、簡単なPDF出力サンプルをつくってみたのでメモがてらにまとめてみます。
まずは、SugarPDFフレームワークの内容を簡単にまとめると

  • ライブラリにTCPDFを利用
  • PDF表示については、既存のSugarMVCフレームワークを利用
  • PDFをデザインするためのSugarpdfは、TCPDFの単なるラッパ

という感じで、レイアウトに神経使ったりマルチバイトの折り返しと格闘したりという苦行からの開放はなさそうです(笑)。ただ、ビューの一部としてPDFを選択できることになったので、カスタマイズ時には純粋にレイアウトに没頭でき、Sugarシステムに閉じて使うことで外部連携に苦心することはなくなりそうです。

ContactsのDetailViewの内容をPDF出力するサンプル。

今回作成したサンプルは図のようなものになります。Contacts(取引先担当者)に作成したデータをDetailViewからPDF出力するものです。PDF側の出力サンプルがかなりの手抜きですが、まぁ流れをつかむだけということで・・・

Step1 フォントファイルの追加

SugarCRMインストール後のtcpdfにはフォントファイルが削除された状態となっています。よって、出力時に必要となるフォントファイルを'include/tcpdf/fonts'配下に配置する必要あります。今回はTCPDFライブラリ本体をダウンロードし、include/tcpdf/fonts配下のフォントファイルをすべてコピーしました。

  • TCPDFのウェブサイト:TECNICK.COM
  • 上記サイトのDOWNLOADからtcpdf_4_8_x.zipをダウンロードし、解凍後Sugarシステムにコピーします。

Step2 PDFテンプレートの作成

テンプレートといっても、Smartyで利用するようなテンプレートではなく、Sugarpdfクラスを継承したクラスでpreDisplay()関数とdisplay()関数を、PDF出力用の関数を利用して実装します。このとき、作成するクラス名、ファイル名、配置場所には以下のルールがあります。

クラス名

Sugarpdf<テンプレート名>となります。今回はContactsモジュールでPDF出力を行うので、テンプレート名をsampleとするとクラス名は'ContactsSugarpdfsample'となります。

ファイル名

sugarpdf.<テンプレート名>.phpとなります。今回はテンプレート名をsampleとしたので、'sugarpdf.sample.php'となります。

配置場所

modules//sugarpdf もしくは custom/modules//sugarpdf 配下に配置します。今回は後述のdetailviewdefs.php等もすべてcustom配下で作成したので、配置場所は 'custom/modules/Contacts/sugarpdf/sugarpdf.sample.php' となりました。

ロジック
<?php
    if(!defined('sugarEntry') || !sugarEntry) die ("good by");
    require_once('include/Sugarpdf/Sugarpdf.php');

    class ContactsSugarpdfsample extends Sugarpdf {
        function preDisplay() {
            parent::preDisplay();
        }

        function display() {
            global $mod_strings;
            $this->addPage();
            $this->setFont(PDF_FONT_NAME_MAIN, ''. PDF_FONT_SIZE_MAIN);
            $this->fileName = "sample.pdf";

            $this->Cell(0, 0, "Contacts : " . $this->bean->full_name, 0, 1, 'L', 0, null, true);

            require_once("custom/modules/Contacts/metadata/pdfconfig.php");
            $count = 1;
            $next = 0;
            foreach($pdfLayout as $fieldName => $labelName) {
                $label = '';
                $next = ($count % 2 == 0) ? 1 : 0;
                if($fieldName !== 'EMPTY') $label = $mod_strings[$labelName];
                $this->MultiCell(45, 15, $label, 1, 'L', 0, 0, '', '', true);
                $this->MultiCell(45, 15, $this->bean->$fieldName, 1, 'L', 0, $next, '', '', true);
                $count++;
            }
        }
    }

ロジック中のCell()とMultiCell()でデータ出力を行っています。引数の詳細についてはTCPDFのマニュアルを参照してください。ロジック中の'pdfconfig.php'は以下のようなフィールド名とラベル名をマッピングした連想配列です。空セルを出力したい場合にはフィールド名に'EMPTY'をつけました。

<?php
$pdfLayout = array(
    'name'        => 'LBL_NAME',
    'EMPTY' => '',
    'phone_work'  => 'LBL_OFFICE_PHONE',
    'account_name'=> 'LBL_ACCOUNT_NAME',
    'phone_mobile'=> 'LBL_MOBILE_PHONE',
    'lead_source' => 'LBL_LEAD_SOURCE',
);

Step3 ContactsのDetailViewにPDF出力用のボタンを配置

SugarMVCフレームワークは、以下のURLパラメータを受け取ったときにSugarPDFフレームワークを利用します。
module=<モジュール名>&action=sugarpdf&sugarpdf=<テンプレート名>
今回のサンプルでは、モジュール名:Contacts, テンプレート名:sampleとなるように、ボタン側でパラメータをセットします。

custom/modules/Contacts/metadata/detailviewdefs.phpに以下のhidden属性とcustomCodeを記述します。

'templateMeta' => array('form' => array('hidden'=>'<input type="hidden" name="sugarpdf" value="">',
                                        'buttons'=>array('EDIT', 'DUPLICATE', 'DELETE', 'FIND_DUPLICATES',
                                                        array('customCode' => '<input title="PDF" class="button" onclick="this.form.return_module.value=\'Contacts\'; this.form.return_action.value=\'DetailView\'; this.form.return_id.value=\'{$fields.id.value}\'; this.form.action.value=\'sugarpdf\'; this.form.module.value=\'Contacts\'; this.form.module_tab.value=\'Contacts\'; this.form.sugarpdf.value=\'sample\';" type="submit" name="Output PDF" value="PDF">'
),

                                                        ),
                                       ),

hidden要素で'sugarpdf'を用意し、ボタンクリック時にテンプレート名を値として渡しています。同様にactionの値が'sugarpdf'となるように設定します。


以上の3ステップ(実際には2ステップ?)でPDF出力を行うことが出来ます。PDFテンプレートの作成まわりはTCPDFをかなり使い込まないと思ったようなテンプレートを出力するのは難しそうですが、今までにくらべるとPDF出力がぐっと楽になりました。