Zend_Pdf. Таблицы (Zend_Pdf_Table). UTF-8

Рано или поздно, но всем приходится делать вывод данных в PDF. Всевозможная отчетность, бланки, да и просто сохранение каких-то отобранных пользователем данных - без PDF в таком случае не обойтись.
Zend_Pdf предоставляет возможности формирования таких документов, однако встроенных возможностей все же недостаточно.
Поэтому я стала рассматривать варианты сторонних библиотек. Основными кандидатами были:
  1. TCPDF
  2. Dompdf

Несмотря на то, что другие варианты тоже были, они отмелись практически сразу же.

Dompdf

Дольше всего я возилась с Dompdf, и этот вариант был бы лучшим и на нем я бы остановилась, если бы он смог обрабатывать большой объем информации за приемлемое время. Однако приведу пример его использования:

Шаг 1. Скачиваем последнюю версию здесь и помещаем в папку library вашего проекта.

Шаг 2. Подключаем библиотеку.
Поскольку преимущество данной библиотеки - конвертация html в PDF, мне не хотелось писать обработчик для каждого экшна. Также запроса на создание PDF у меня отправляется ajax'ом, поэтому в init нужного контроллера добавила строки:

if ($this->_getParam('pdf')) {
            $this->_helper->getHelper("layout")->disableLayout();
            $front = Zend_Controller_Front::getInstance();
            $front->registerPlugin(new Application_Plugin_Pdf());
            $this->view->pdf = true;
}

Здесь мы подключаем плагин Application_Plugin_Pdf, в котором и происходят все магические действия. В плагине у меня определено всего одно действие - dispatchLoopShutdown(). Согласно документации dispatchLoopShutdown() вызывается после выхода Zend_Controller_Front из его цикла диспетчеризации, т.е. мы получаем уже сформированный view.

         $body = $this->getResponse()->getBody(); // получаем view
         $html =
         '<html><head>
                <meta http-equiv="Content-Type" content="charset=utf-8" /> // ДА! эта библиотека поддерживает русский язык!
                <title>Test</title> 
                </head><body>'. 
                '<script type="text/php">
if ( isset($pdf) ) {
// здесь можно добавить header и footer для каждой страницы (например, вывод нумерации или логотипа) и все, что вашей душе угодно
}
                </script>
                '.
                $body
                .
            '</body></html>';

        $dompdf = new DOMPDF();
        $dompdf->set_paper("a4", "portrait");  
        $dompdf->load_html($html);
        $dompdf->render();
        $pdf = $dompdf->output();


        $filename = 'tmp/test.pdf';

        file_put_contents($filename, $pdf);
        $this->getResponse()->clearBody();
        $this->getResponse()->appendBody($filename);

На этом моя радость закончилась. При тестировании Dompdf не оправдал возложенных на него надежд.
Повторно рассматривать TCPDF я не стала и решила все-таки вновь вернуться к расширению самого Zend - Zend_Pdf_Table.

Zend_Pdf_Table

С первого раза отношения с этой библиотекой у меня не сложились. Но я так просто не сдалась.
Итак, что делаем:

Шаг 1. Скачиваем библиотеку здесь и помещаем в папку library нашего проекта.

Шаг 2. Минус этой библиотеки, с которым я только начинаю бороться - невозможность брать уже готовый сформированный view для формирования из него PDF. Т.е. для каждого отчета, видимо, необходимо писать свой обработчик.
Подключаем в нужном экшне библиотеку и пользуемся!

Шаг 3. Чтобы PDF стал писать по-русски, я добавила четвертый (почему-то опущенный) параметр в вызовах функции drawText класса Cell - $page->drawText($line,$this->_getTextPosX($posX), $this->_getTextPosY($page,$y_inc), 'UTF-8');


Производительность Zend_Pdf_Table радует. Однако не хватает ее возможностей:
  1. невозможно установить rowspan
  2. нет возможности вынести в header таблицы несколько строк.
Но на этом я не останавливаюсь и продолжу борьбу!

UPD1
При использовании UTF-8 для правильного расчета ширины столбцов необходимо изменить функцию _getTextWidth() класса Page:

    private function _getTextWidth($text) {
            $text = iconv('UTF-8', 'UTF-16BE//IGNORE', $text);
            $em = $this->_font->getUnitsPerEm ();
            $characters = array();
            for ($i = 0; $i < strlen($text); $i++) {
                $characters[] = (ord($text[$i++]) << 8) | ord($text[$i]);
            }
            $glyphs = $this->_font->glyphNumbersForCharacters($characters);
            $widths = $this->_font->widthsForGlyphs($glyphs);
            $stringWidth = (array_sum($widths) / $em) * $this->_fontSize;
            return $stringWidth;
   }

Комментарии

Популярные сообщения