src/Eccube/Service/OrderPdfService.php line 178

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