src/Eccube/Service/OrderPdfService.php line 32

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Service;
  13. use Eccube\Common\EccubeConfig;
  14. use Eccube\Entity\BaseInfo;
  15. use Eccube\Entity\OrderItem;
  16. use Eccube\Entity\Shipping;
  17. use Eccube\Repository\BaseInfoRepository;
  18. use Eccube\Repository\OrderPdfRepository;
  19. use Eccube\Repository\OrderRepository;
  20. use Eccube\Repository\ShippingRepository;
  21. use Eccube\Twig\Extension\EccubeExtension;
  22. use Eccube\Twig\Extension\TaxExtension;
  23. use setasign\Fpdi\Tcpdf\Fpdi;
  24. /**
  25.  * Class OrderPdfService.
  26.  * Do export pdf function.
  27.  */
  28. class OrderPdfService extends Fpdi
  29. {
  30.     /** @var OrderRepository */
  31.     protected $orderRepository;
  32.     /** @var ShippingRepository */
  33.     protected $shippingRepository;
  34.     /** @var OrderPdfRepository */
  35.     protected $orderPdfRepository;
  36.     /** @var TaxRuleService */
  37.     protected $taxRuleService;
  38.     /**
  39.      * @var EccubeConfig
  40.      */
  41.     protected $eccubeConfig;
  42.     /**
  43.      * @var EccubeExtension
  44.      */
  45.     protected $eccubeExtension;
  46.     /**
  47.      * @var TaxExtension
  48.      */
  49.     protected $taxExtension;
  50.     // ====================================
  51.     // 定数宣言
  52.     // ====================================
  53.     /** ダウンロードするPDFファイルのデフォルト名 */
  54.     public const DEFAULT_PDF_FILE_NAME 'nouhinsyo.pdf';
  55.     /** FONT ゴシック */
  56.     public const FONT_GOTHIC 'kozgopromedium';
  57.     /** FONT 明朝 */
  58.     public const FONT_SJIS 'kozminproregular';
  59.     // ====================================
  60.     // 変数宣言
  61.     // ====================================
  62.     /** @var BaseInfo */
  63.     public $baseInfoRepository;
  64.     /** 購入詳細情報 ラベル配列
  65.      * @var array
  66.      */
  67.     protected $labelCell = [];
  68.     /*** 購入詳細情報 幅サイズ配列
  69.      * @var array
  70.      */
  71.     protected $widthCell = [];
  72.     /** 最後に処理した注文番号 @var string */
  73.     protected $lastOrderId null;
  74.     // --------------------------------------
  75.     // Font情報のバックアップデータ
  76.     /** @var string フォント名 */
  77.     protected $bakFontFamily;
  78.     /** @var string フォントスタイル */
  79.     protected $bakFontStyle;
  80.     /** @var string フォントサイズ */
  81.     protected $bakFontSize;
  82.     // --------------------------------------
  83.     // lfTextのoffset
  84.     protected $baseOffsetX 0;
  85.     protected $baseOffsetY = -4;
  86.     /** ダウンロードファイル名 @var string */
  87.     protected $downloadFileName null;
  88.     /** 発行日 @var string */
  89.     protected $issueDate '';
  90.     /**
  91.      * OrderPdfService constructor.
  92.      *
  93.      * @param EccubeConfig $eccubeConfig
  94.      * @param OrderRepository $orderRepository
  95.      * @param ShippingRepository $shippingRepository
  96.      * @param TaxRuleService $taxRuleService
  97.      * @param BaseInfoRepository $baseInfoRepository
  98.      * @param EccubeExtension $eccubeExtension
  99.      * @param TaxExtension $taxExtension
  100.      *
  101.      * @throws \Exception
  102.      */
  103.     public function __construct(EccubeConfig $eccubeConfigOrderRepository $orderRepositoryShippingRepository $shippingRepositoryTaxRuleService $taxRuleServiceBaseInfoRepository $baseInfoRepositoryEccubeExtension $eccubeExtensionTaxExtension $taxExtension)
  104.     {
  105.         $this->eccubeConfig $eccubeConfig;
  106.         $this->baseInfoRepository $baseInfoRepository->get();
  107.         $this->orderRepository $orderRepository;
  108.         $this->shippingRepository $shippingRepository;
  109.         $this->taxRuleService $taxRuleService;
  110.         $this->eccubeExtension $eccubeExtension;
  111.         $this->taxExtension $taxExtension;
  112.         parent::__construct();
  113.         // 購入詳細情報の設定を行う
  114.         // 動的に入れ替えることはない
  115.         // 20240406 商品コードを非表示にしたいので文章を変更
  116.         //$this->labelCell[] = '商品名 / 商品コード';
  117.         $this->labelCell[] = '商品名';
  118.         $this->labelCell[] = '数量';
  119.         $this->labelCell[] = '単価';
  120.         $this->labelCell[] = '金額(税込)';
  121.         $this->widthCell = [110.31221.724.5];
  122.         // Fontの設定しておかないと文字化けを起こす
  123.         $this->SetFont(self::FONT_SJIS);
  124.         // PDFの余白(上左右)を設定
  125.         $this->SetMargins(1520);
  126.         // ヘッダーの出力を無効化
  127.         $this->setPrintHeader(false);
  128.         // フッターの出力を無効化
  129.         $this->setPrintFooter(true);
  130.         $this->setFooterMargin();
  131.         $this->setFooterFont([self::FONT_SJIS''8]);
  132.     }
  133.     /**
  134.      * 注文情報からPDFファイルを作成する.
  135.      *
  136.      * @param array $formData
  137.      *                        [KEY]
  138.      *                        ids: 注文番号
  139.      *                        issue_date: 発行日
  140.      *                        title: タイトル
  141.      *                        message1: メッセージ1行目
  142.      *                        message2: メッセージ2行目
  143.      *                        message3: メッセージ3行目
  144.      *                        note1: 備考1行目
  145.      *                        note2: 備考2行目
  146.      *                        note3: 備考3行目
  147.      *
  148.      * @return bool
  149.      */
  150.     public function makePdf(array $formData)
  151.     {
  152.         // 発行日の設定
  153.         $this->issueDate '作成日: '.$formData['issue_date']->format('Y年m月d日');
  154.         // ダウンロードファイル名の初期化
  155.         $this->downloadFileName null;
  156.         // データが空であれば終了
  157.         if (!$formData['ids']) {
  158.             return false;
  159.         }
  160.         // 出荷番号をStringからarrayに変換
  161.         $ids explode(','$formData['ids']);
  162.         foreach ($ids as $id) {
  163.             $this->lastOrderId $id;
  164.             // 出荷番号から出荷情報を取得する
  165.             /** @var Shipping $Shipping */
  166.             $Shipping $this->shippingRepository->find($id);
  167.             if (!$Shipping) {
  168.                 // 出荷情報の取得ができなかった場合
  169.                 continue;
  170.             }
  171.             // テンプレートファイルを読み込む
  172.             $Order $Shipping->getOrder();
  173.             if ($Order->isMultiple()) {
  174.                 // 複数配送の時は読み込むテンプレートファイルを変更する
  175.                 $userPath $this->eccubeConfig->get('eccube_html_admin_dir').'/assets/pdf/nouhinsyo_multiple.pdf';
  176.             } else {
  177.                 $userPath $this->eccubeConfig->get('eccube_html_admin_dir').'/assets/pdf/nouhinsyo.pdf';
  178.             }
  179.             $this->setSourceFile($userPath);
  180.             // PDFにページを追加する
  181.             $this->addPdfPage();
  182.             // タイトルを描画する
  183.             $this->renderTitle($formData['title']);
  184.             // 店舗情報を描画する
  185.             $this->renderShopData();
  186.             // 注文情報を描画する
  187.             $this->renderOrderData($Shipping);
  188.             // メッセージを描画する
  189.             $this->renderMessageData($formData);
  190.             // 出荷詳細情報を描画する
  191.             $this->renderOrderDetailData($Shipping);
  192.             // 備考を描画する
  193.             $this->renderEtcData($formData);
  194.         }
  195.         return true;
  196.     }
  197.     /**
  198.      * PDFファイルを出力する.
  199.      *
  200.      * @return string|mixed
  201.      */
  202.     public function outputPdf()
  203.     {
  204.         return $this->Output($this->getPdfFileName(), 'S');
  205.     }
  206.     /**
  207.      * PDFファイルをサーバーに保存する.
  208.      *
  209.      * @return string|mixed
  210.      */
  211.     public function outputSavePdf($filename$option)
  212.     {
  213.         return $this->Output($filename$option);
  214.     }
  215.     /**
  216.      * PDFファイル名を取得する
  217.      * PDFが1枚の時は注文番号をファイル名につける.
  218.      *
  219.      * @return string ファイル名
  220.      */
  221.     public function getPdfFileName()
  222.     {
  223.         if (!is_null($this->downloadFileName)) {
  224.             return $this->downloadFileName;
  225.         }
  226.         $this->downloadFileName self::DEFAULT_PDF_FILE_NAME;
  227.         if ($this->PageNo() == 1) {
  228.             $this->downloadFileName 'nouhinsyo-No'.$this->lastOrderId.'.pdf';
  229.         }
  230.         return $this->downloadFileName;
  231.     }
  232.     /**
  233.      * フッターに発行日を出力する.
  234.      */
  235.     public function Footer()
  236.     {
  237.         $this->Cell(00$this->issueDate00'R');
  238.     }
  239.     /**
  240.      * 作成するPDFのテンプレートファイルを指定する.
  241.      */
  242.     protected function addPdfPage()
  243.     {
  244.         // ページを追加
  245.         $this->AddPage();
  246.         // テンプレートに使うテンプレートファイルのページ番号を取得
  247.         $tplIdx $this->importPage(1);
  248.         // テンプレートに使うテンプレートファイルのページ番号を指定
  249.         $this->useTemplate($tplIdxnullnullnullnulltrue);
  250.         $this->setPageMark();
  251.     }
  252.     /**
  253.      * PDFに店舗情報を設定する
  254.      * ショップ名、ロゴ画像以外はdtb_helpに登録されたデータを使用する.
  255.      */
  256.     protected function renderShopData()
  257.     {
  258.         // 基準座標を設定する
  259.         $this->setBasePosition();
  260.         // ショップ名
  261.         $this->lfText(12558$this->baseInfoRepository->getShopName(), 8'B');
  262.         //郵便番号
  263.         $this->lfText(12163"\u{3012}"' ' mb_substr($this->baseInfoRepository->getPostalCode(), 03) . ' - ' mb_substr($this->baseInfoRepository->getPostalCode(), 34), 8);
  264.         // 都道府県+所在地
  265.         $text $this->baseInfoRepository->getPref().$this->baseInfoRepository->getAddr01();
  266.         $this->lfText(12566$text8);
  267.         $this->lfText(12569$this->baseInfoRepository->getAddr02(), 8);
  268.         // 電話番号
  269.         $text 'TEL: '.$this->baseInfoRepository->getPhoneNumber();
  270.         $this->lfText(12572$text8); // TEL・FAX
  271.         // メールアドレス
  272.         if (strlen($this->baseInfoRepository->getEmail01()) > 0) {
  273.             $text 'Email: '.$this->baseInfoRepository->getEmail01();
  274.             $this->lfText(12575$text8); // Email
  275.         }
  276.         // インボイス登録番号
  277.         if (!empty($this->baseInfoRepository->getInvoiceRegistrationNumber())) {
  278.             $text '登録番号: '.$this->baseInfoRepository->getInvoiceRegistrationNumber();
  279.             $this->lfText(12579$text8);
  280.         }
  281.         // user_dataにlogo.pngが配置されている場合は優先的に読み込む
  282.         $logoFile $this->eccubeConfig->get('eccube_html_dir').'/user_data/assets/pdf/logo.png';
  283.         if (!file_exists($logoFile)) {
  284.             $logoFile $this->eccubeConfig->get('eccube_html_admin_dir').'/assets/pdf/logo.png';
  285.         }
  286.         $this->Image($logoFile1244640);
  287.     }
  288.     /**
  289.      * メッセージを設定する.
  290.      *
  291.      * @param array $formData
  292.      */
  293.     protected function renderMessageData(array $formData)
  294.     {
  295.         $this->lfText(2770$formData['message1'], 8); // メッセージ1
  296.         $this->lfText(2774$formData['message2'], 8); // メッセージ2
  297.         $this->lfText(2778$formData['message3'], 8); // メッセージ3
  298.     }
  299.     /**
  300.      * PDFに備考を設定数.
  301.      *
  302.      * @param array $formData
  303.      */
  304.     protected function renderEtcData(array $formData)
  305.     {
  306.         // フォント情報のバックアップ
  307.         $this->backupFont();
  308.         $this->Cell(010''01'C'0'');
  309.         // 行頭近くの場合、表示崩れがあるためもう一個字下げする
  310.         if (270 <= $this->GetY()) {
  311.             $this->Cell(010''01'C'0'');
  312.         }
  313.         $this->SetFont(self::FONT_GOTHIC'B'9);
  314.         $this->MultiCell(06'< 備考 >''T'2'L'0'');
  315.         $this->SetFont(self::FONT_SJIS''8);
  316.         $this->Ln();
  317.         // rtrimを行う
  318.         $text preg_replace('/\s+$/us'''$formData['note1']."\n".$formData['note2']."\n".$formData['note3']);
  319.         $this->MultiCell(04$text''2'L'0'');
  320.         // フォント情報の復元
  321.         $this->restoreFont();
  322.     }
  323.     /**
  324.      * タイトルをPDFに描画する.
  325.      *
  326.      * @param string $title
  327.      */
  328.     protected function renderTitle($title)
  329.     {
  330.         // 基準座標を設定する
  331.         $this->setBasePosition();
  332.         // フォント情報のバックアップ
  333.         $this->backupFont();
  334.         // 文書タイトル(納品書・請求書)
  335.         $this->SetFont(self::FONT_GOTHIC''15);
  336.         $this->Cell(010$title02'C'0'');
  337.         $this->Cell(066''02'R'0'');
  338.         $this->Cell(50''00'R'0'');
  339.         // フォント情報の復元
  340.         $this->restoreFont();
  341.     }
  342.     /**
  343.      * 購入者情報を設定する.
  344.      *
  345.      * @param Shipping $Shipping
  346.      */
  347.     protected function renderOrderData(Shipping $Shipping)
  348.     {
  349.         // 基準座標を設定する
  350.         $this->setBasePosition();
  351.         // フォント情報のバックアップ
  352.         $this->backupFont();
  353.         // =========================================
  354.         // 購入者情報部
  355.         // =========================================
  356.         $Order $Shipping->getOrder();
  357.         // 購入者郵便番号(3012は郵便マークのUTFコード)
  358.         $text "\u{3012}" ' ' mb_substr($Shipping->getPostalCode(), 03) . ' - ' mb_substr($Shipping->getPostalCode(), 34);
  359.         $this->lfText(2243$text10);
  360.         // 購入者都道府県+住所1
  361.         // $text = $Order->getPref().$Order->getAddr01();
  362.         $text $Shipping->getPref().$Shipping->getAddr01();
  363.         $this->lfText(2747$text10);
  364.         $this->lfText(2751$Shipping->getAddr02(), 10); // 購入者住所2
  365.         // 購入者氏名
  366.         if (null !== $Shipping->getCompanyName()) {
  367.             // 会社名
  368.             $text $Shipping->getCompanyName();
  369.             $this->lfText(2757$text11);
  370.             // 氏名
  371.             $text $Shipping->getName01().' '.$Shipping->getName02().' 様';
  372.             $this->lfText(2763$text11);
  373.         } else {
  374.             $text $Shipping->getName01().' '.$Shipping->getName02().' 様';
  375.             $this->lfText(2759$text11);
  376.         }
  377.         // =========================================
  378.         // お買い上げ明細部
  379.         // =========================================
  380.         $this->SetFont(self::FONT_SJIS''10);
  381.         // ご注文日
  382.         $orderDate $Order->getCreateDate()->format('Y/m/d H:i');
  383.         if ($Order->getOrderDate()) {
  384.             $orderDate $Order->getOrderDate()->format('Y/m/d H:i');
  385.         }
  386.         $this->lfText(25125$orderDate10);
  387.         // 注文番号
  388.         $this->lfText(25135$Order->getOrderNo(), 10);
  389.         // 総合計金額
  390.         if (!$Order->isMultiple()) {
  391.             $this->SetFont(self::FONT_SJIS'B'15);
  392.             $paymentTotalText $this->eccubeExtension->getPriceFilter($Order->getPaymentTotal());
  393.             $this->setBasePosition(12095.5);
  394.             $this->Cell(57''00''0'');
  395.             $this->Cell(678$paymentTotalText02'R'0'');
  396.             $this->Cell(045''02''0'');
  397.         }
  398.         // フォント情報の復元
  399.         $this->restoreFont();
  400.     }
  401.     /**
  402.      * 購入商品詳細情報を設定する.
  403.      *
  404.      * @param Shipping $Shipping
  405.      */
  406.     protected function renderOrderDetailData(Shipping $Shipping)
  407.     {
  408.         $arrOrder = [];
  409.         // テーブルの微調整を行うための購入商品詳細情報をarrayに変換する
  410.         // =========================================
  411.         // 受注詳細情報
  412.         // =========================================
  413.         $i 0;
  414.         $isShowReducedTaxMess false;
  415.         $Order $Shipping->getOrder();
  416.         /* @var OrderItem $OrderItem */
  417.         foreach ($Shipping->getOrderItems() as $OrderItem) {
  418.             if (!$Order->isMultiple() && !$OrderItem->isProduct()) {
  419.                 continue;
  420.             }
  421.             // class categoryの生成
  422.             $classCategory '';
  423.             /** @var OrderItem $OrderItem */
  424.             if ($OrderItem->getClassCategoryName1()) {
  425.                 $classCategory .= ' [ '.$OrderItem->getClassCategoryName1();
  426.                 if ($OrderItem->getClassCategoryName2() == '') {
  427.                     $classCategory .= ' ]';
  428.                 } else {
  429.                     $classCategory .= ' * '.$OrderItem->getClassCategoryName2().' ]';
  430.                 }
  431.             }
  432.             // product
  433.             $productName $OrderItem->getProductName();
  434.             //購入明細の送料が商品部分に表示されるため非表示にしたい。
  435.             if($productName == "送料"){
  436.                 continue;
  437.             }
  438.             if (null !== $OrderItem->getProductCode()) {
  439.                 // 20240404 非表示にするためコメントアウト
  440.                 //$productName .= ' / '.$OrderItem->getProductCode();
  441.             }
  442.             if ($classCategory) {
  443.                 $productName .= ' / '.$classCategory;
  444.             }
  445.             if ($this->taxExtension->isReducedTaxRate($OrderItem)) {
  446.                 $productName .= ' ※';
  447.                 $isShowReducedTaxMess true;
  448.             }
  449.             $arrOrder[$i][0] = $productName;
  450.             // 購入数量
  451.             $arrOrder[$i][1] = number_format($OrderItem->getQuantity());
  452.             // 税込金額(単価)
  453.             $arrOrder[$i][2] = $this->eccubeExtension->getPriceFilter($OrderItem->getPrice());
  454.             // 小計(商品毎)
  455.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($OrderItem->getTotalPrice());
  456.             ++$i;
  457.         }
  458.         if (!$Order->isMultiple()) {
  459.             // =========================================
  460.             // 小計
  461.             // =========================================
  462.             $arrOrder[$i][0] = '';
  463.             $arrOrder[$i][1] = '';
  464.             $arrOrder[$i][2] = '';
  465.             $arrOrder[$i][3] = '';
  466.             ++$i;
  467.             $arrOrder[$i][0] = '';
  468.             $arrOrder[$i][1] = '';
  469.             $arrOrder[$i][2] = '商品合計';
  470.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Order->getSubtotal());
  471.             ++$i;
  472.             $arrOrder[$i][0] = '';
  473.             $arrOrder[$i][1] = '';
  474.             $arrOrder[$i][2] = '送料';
  475.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Order->getDeliveryFeeTotal());
  476.             ++$i;
  477.             $arrOrder[$i][0] = '';
  478.             $arrOrder[$i][1] = '';
  479.             $arrOrder[$i][2] = '手数料';
  480.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Order->getCharge());
  481.             ++$i;
  482.             $arrOrder[$i][0] = '';
  483.             $arrOrder[$i][1] = '';
  484.             $arrOrder[$i][2] = '値引き';
  485.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Order->getTaxableDiscount());
  486.             ++$i;
  487.             $arrOrder[$i][0] = '';
  488.             $arrOrder[$i][1] = '';
  489.             $arrOrder[$i][2] = '';
  490.             $arrOrder[$i][3] = '';
  491.             ++$i;
  492.             $arrOrder[$i][0] = '';
  493.             $arrOrder[$i][1] = '';
  494.             $arrOrder[$i][2] = '合計';
  495.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Order->getTaxableTotal());
  496.             ++$i;
  497.             $arrOrder[$i][0] = '';
  498.             $arrOrder[$i][1] = '';
  499.             $arrOrder[$i][2] = '';
  500.             $arrOrder[$i][3] = '';
  501.             foreach ($Order->getTaxFreeDiscountItems() as $Item) {
  502.                 ++$i;
  503.                 $arrOrder[$i][0] = '';
  504.                 $arrOrder[$i][1] = '';
  505.                 $arrOrder[$i][2] = $Item->getProductName();
  506.                 $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Item->getTotalPrice());
  507.             }
  508.             ++$i;
  509.             $arrOrder[$i][0] = '';
  510.             $arrOrder[$i][1] = '';
  511.             $arrOrder[$i][2] = '請求金額';
  512.             $arrOrder[$i][3] = $this->eccubeExtension->getPriceFilter($Order->getPaymentTotal());
  513.             if ($isShowReducedTaxMess) {
  514.                 ++$i;
  515.                 $arrOrder[$i][0] = '※は軽減税率対象商品です。';
  516.                 $arrOrder[$i][1] = '';
  517.                 $arrOrder[$i][2] = '';
  518.                 $arrOrder[$i][3] = '';
  519.             }
  520.         }
  521.         // PDFに設定する
  522.         $this->setFancyTable($this->labelCell$arrOrder$this->widthCell);
  523.         // インボイス対応
  524.         $this->backupFont();
  525.         $this->SetLineWidth(.3);
  526.         $this->SetFont(self::FONT_SJIS''6);
  527.         $this->Cell(00''01'C'0'');
  528.         // 行頭近くの場合、表示崩れがあるためもう一個字下げする
  529.         if (270 <= $this->GetY()) {
  530.             $this->Cell(00''01'C'0'');
  531.         }
  532.         $width array_reduce($this->widthCell, function ($n$w) {
  533.             return $n $w;
  534.         });
  535.         $this->SetX(20);
  536.         $message '';
  537.         foreach ($Order->getTotalByTaxRate() as $rate => $total) {
  538.             $message .= '('.$rate.'%対象: ';
  539.             $message .= $this->eccubeExtension->getPriceFilter($total);
  540.             $message .= ' 内消費税: '.$this->eccubeExtension->getPriceFilter($Order->getTaxByTaxRate()[$rate]).')'.PHP_EOL;
  541.         }
  542.         $this->MultiCell($width4$message0'R'0'');
  543.         $this->restoreFont();
  544.     }
  545.     /**
  546.      * PDFへのテキスト書き込み
  547.      *
  548.      * @param int    $x     X座標
  549.      * @param int    $y     Y座標
  550.      * @param string $text  テキスト
  551.      * @param int    $size  フォントサイズ
  552.      * @param string $style フォントスタイル
  553.      */
  554.     protected function lfText($x$y$text$size 0$style '')
  555.     {
  556.         // 退避
  557.         $bakFontStyle $this->FontStyle;
  558.         $bakFontSize $this->FontSizePt;
  559.         $this->SetFont(''$style$size);
  560.         $this->Text($x $this->baseOffsetX$y $this->baseOffsetY$text);
  561.         // 復元
  562.         $this->SetFont(''$bakFontStyle$bakFontSize);
  563.     }
  564.     /**
  565.      * Colored table.
  566.      *
  567.      * @param array $header 出力するラベル名一覧
  568.      * @param array $data   出力するデータ
  569.      * @param array $w      出力するセル幅一覧
  570.      */
  571.     protected function setFancyTable($header$data$w)
  572.     {
  573.         // フォント情報のバックアップ
  574.         $this->backupFont();
  575.         // 開始座標の設定
  576.         $this->setBasePosition(0149);
  577.         // Colors, line width and bold font
  578.         $this->SetFillColor(216216216);
  579.         $this->SetTextColor(0);
  580.         $this->SetDrawColor(000);
  581.         $this->SetLineWidth(.3);
  582.         $this->SetFont(self::FONT_SJIS'B'8);
  583.         $this->SetFont('''B');
  584.         // Header
  585.         $this->Cell(57''00''0'');
  586.         $count count($header);
  587.         for ($i 0$i $count; ++$i) {
  588.             $this->Cell($w[$i], 7$header[$i], 10'C'1);
  589.         }
  590.         $this->Ln();
  591.         // Color and font restoration
  592.         $this->SetFillColor(235235235);
  593.         $this->SetTextColor(0);
  594.         $this->SetFont('');
  595.         // Data
  596.         $fill 0;
  597.         $writeRow = function($row$cellHeight$fill$isBorder) use($w) {
  598.             $i 0;
  599.             $h 0;
  600.             foreach ($row as $col) {
  601.                 // 列の処理
  602.                 // TODO: 汎用的ではない処理。この指定は呼び出し元で行うようにしたい。
  603.                 // テキストの整列を指定する
  604.                 $align = ($i == 0) ? 'L' 'R';
  605.                 // セル高さが最大値を保持する
  606.                 if ($h >= $cellHeight) {
  607.                     $cellHeight $h;
  608.                 }
  609.                 // 最終列の場合は次の行へ移動
  610.                 // (0: 右へ移動(既定)/1: 次の行へ移動/2: 下へ移動)
  611.                 $ln = ($i == (count($row) - 1)) ? 0;
  612.                 $this->MultiCell(
  613.                     $w[$i], // セル幅
  614.                     $cellHeight// セルの最小の高さ
  615.                     !$isBorder $col ''// 文字列
  616.                     $isBorder 0// 境界線の描画方法を指定
  617.                     $align// テキストの整列
  618.                     $fill// 背景の塗つぶし指定
  619.                     $ln // 出力後のカーソルの移動方法
  620.                 );
  621.                 $h $this->getLastH();
  622.                 $i++;
  623.             }
  624.             return $cellHeight;
  625.         };
  626.         foreach ($data as $row) {
  627.             // 行の処理
  628.             $h 4;
  629.             $this->Cell(5$h''00''0'');
  630.             if ((277 $this->getY()) < ($h 4)) {
  631.                 $this->checkPageBreak($this->PageBreakTrigger 1);
  632.             }
  633.             $x $this->getX();
  634.             $y $this->getY();
  635.             // 1度目は文字だけ出力し、行の高さ最大を取得
  636.             $h $writeRow($row$h$fillfalse);
  637.             $this->setXY($x$y);
  638.             // 2度目に最大の高さに合わせて、境界線を描画
  639.             $writeRow($row$h$filltrue);
  640.             $fill = !$fill;
  641.         }
  642.         $h 4;
  643.         $this->Cell(5$h''00''0'');
  644.         $this->Cell(array_sum($w), 0'''T');
  645.         $this->SetFillColor(255);
  646.         // フォント情報の復元
  647.         $this->restoreFont();
  648.     }
  649.     /**
  650.      * 基準座標を設定する.
  651.      *
  652.      * @param int $x
  653.      * @param int $y
  654.      */
  655.     protected function setBasePosition($x null$y null)
  656.     {
  657.         // 現在のマージンを取得する
  658.         $result $this->getMargins();
  659.         // 基準座標を指定する
  660.         $actualX is_null($x) ? $result['left'] : $x;
  661.         $this->SetX($actualX);
  662.         $actualY is_null($y) ? $result['top'] : $y;
  663.         $this->SetY($actualY);
  664.     }
  665.     /**
  666.      * Font情報のバックアップ.
  667.      */
  668.     protected function backupFont()
  669.     {
  670.         // フォント情報のバックアップ
  671.         $this->bakFontFamily $this->FontFamily;
  672.         $this->bakFontStyle $this->FontStyle;
  673.         $this->bakFontSize $this->FontSizePt;
  674.     }
  675.     /**
  676.      * Font情報の復元.
  677.      */
  678.     protected function restoreFont()
  679.     {
  680.         $this->SetFont($this->bakFontFamily$this->bakFontStyle$this->bakFontSize);
  681.     }
  682. }