Перед нами стояла задача создать версию страницы в PDF формате, конечно же используя как можно больше стандартных возможностей Drupal, и существующих модулей расширения с возможностью дальнейшей миграции.
Для этой задачи был взят модуль «Print» - этот модуль позволяет создавать не только стандартные «node» в виде pdf, но и версию для печати, отправку на email.
Процесс установки модуля выполняется в несколько этапов:
- Качаем по FTP или просто копируем распакованный модуль «Print» в директорию «/sites/all/modules/»
- Переходим в админку сайта модули и выбираем необходимые нам модули, в данном случае выбран: TCPDF library handler, Printer-friendly pages, PDF version, Printer-friendly pages UI
- Устанавливаем выбранные модули
TCPDF library handler — этот модуль служит для связи библиотеки «tcpdf» - с возможностями самого модуля и по сути является функцией обратного вызова, мой выбор остановился именно на ней потому что она достаточно надежна и проверена временем.
Все установлено но теперь нам нужно скачать саму библиотеку «tcpdf» иначе наш модуль не будет работать, если мы перейдет по ссылки «/admin/config/user-interface/print/pdf» то увидем сообщение которое потребует от нас загрузить эту библиотеку. Качаем исходники этой библиотечки и кладем их в директорию «/sites/all/libraries/tcpdf».
Все отлично и у нас все установлено, но не хватает кнопок для отправки на печать, для вывода нам потребуется перейди в раздел «Структура / Блоки», выбрать блок «Printer, email and PDF versions» в нужный регион.
Давайте перейдем к самому главному, это темизации вывода нашей страницы версии для печати. Для этого мы можем создать отдельный вариант отображения во вкладке настройки отображения типа материала по умолчанию, выберем в «Включить настройки для следующих способов отображения» - «Печать»
Настроим отображение необходимых полей страницы «Node».
Следующим шагом будет создание отдельно шаблона страницы «Node» печати, для этого скопируйте файл «print.tpl.php» который находится в директории «/sites/all/modules/print» в директорию с нашей темой «/sites/all/themes/название темы/templates»
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
"http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>" version="XHTML+RDFa 1.0"
dir="<?php print $language->dir; ?>">
<head>
<?php print $head; ?>
<base href='<?php print $url ?>'/>
<title><?php print $print_title; ?></title>
<?php print $scripts; ?>
<?php if (isset($sendtoprinter)) print $sendtoprinter; ?>
<?php print $robots_meta; ?>
<?php if (theme_get_setting('toggle_favicon')): ?>
<link rel='shortcut icon' href='<?php print theme_get_setting('favicon') ?>' type='image/x-icon'/>
<?php endif; ?>
<?php print $css; ?>
</head>
<body>
<div id="wrapper-page-print">
<?php if (!empty($message)): ?>
<div class="print-message"><?php print $message; ?></div>
<?php endif; ?>
<?php if ($print_logo): ?>
<div class="print-logo"><?php print $print_logo; ?></div>
<?php endif; ?>
<div class="print-site_name"><?php print theme('print_published'); ?></div>
<div class="print-breadcrumb"><?php print theme('print_breadcrumb', array('node' => $node)); ?></div>
<hr class="print-hr"/>
<?php if (!isset($node->type)): ?>
<h2 class="print-title"><?php print $print_title; ?></h2>
<?php endif; ?>
<div class="print-content"><?php print $content; ?></div>
<div class="print-footer"><?php print theme('print_footer'); ?></div>
<hr class="print-hr"/>
<?php if ($sourceurl_enabled): ?>
<div class="print-source_url">
<?php print theme('print_sourceurl', array('url' => $source_url, 'node' => $node, 'cid' => $cid)); ?>
</div>
<?php endif; ?>
<div class="print-links"><?php print theme('print_url_list'); ?></div>
<?php print $footer_scripts; ?>
</div>
</body>
</html>
Для переопрделения шаблона мы можем воспользоваться следующим патерном:
/**
* print[--format][--node--content-type[--nodeid]].tpl.php
*
* The following suggestions can be used:
* 1. print--format--node--content-type--nodeid.tpl.php
* 2. print--format--node--content-type.tpl.php
* 3. print--format.tpl.php
* 4. print--node--content-type--nodeid.tpl.php
* 5. print--node--content-type.tpl.php
* 6. print.tpl.php
**/
После как мы доработали нашу таблицу стилей и получили презентабельную печатную страницу, осталось доработать PDF версию страницы. Эта задача не такая простая и решить ее простой правкой HTML и CSS не получится так как PDF формат имеет свой собственный синтаксист, но в модуле «Print» заложена возможности переопределения стандартной функции форматирования - хук название темы_print_pdf_tcpdf_content(&$vars)
function theme_print_pdf_tcpdf_content($vars) {
$pdf = $vars['pdf'];
// set content font
$pdf->setFont($vars['font'][0], $vars['font'][1], $vars['font'][2]);
// Remove the logo, published, breadcrumb and footer from the main content
preg_match('!<body.*?>(.*)</body>!sim', $vars['html'], $matches);
$pattern = '!(?:<div class="print-(?:logo|site_name|breadcrumb|footer)">.*?</div>|<hr class="print-hr" />)!si';
$matches[1] = preg_replace($pattern, '', $matches[1]);
// Make CCK fields look better
$matches[1] = preg_replace('!(<div class="field.*?>)\s*!sm', '$1', $matches[1]);
$matches[1] = preg_replace('!(<div class="field.*?>.*?</div>)\s*!sm', '$1', $matches[1]);
$matches[1] = preg_replace('!<div( class="field-label.*?>.*?)</div>!sm', '<strong$1</strong>', $matches[1]);
// Since TCPDF's writeHTML is so bad with <p>, do everything possible to make it look nice
$matches[1] = preg_replace('!<(?:p(|\s+.*?)/?|/p)>!i', '<br$1 />', $matches[1]);
$matches[1] = str_replace(array('<div', 'div>'), array('<span', 'span><br />'), $matches[1]);
do {
$prev = $matches[1];
$matches[1] = preg_replace('!(</span>)<br />(\s*?</span><br />)!s', '$1$2', $matches[1]);
} while ($prev != $matches[1]);
@$pdf->writeHTML($matches[1]);
return $pdf;
}
Переведенный листинг выше нам не подходит и использует общее применение, так как выравнивание картинок и стилизация полей не устраивает по внешнему виду. Для решения этой задачи нужно распарсить html содержимое страницы печати и использовать API библиотеки tcpdf. В качестве парсера будем использовать билетику «PHP Simple HTML DOM Parser» его методы по своему синтаксису напоминают «jQuery» что значительно облегчает работу с библиотекой.
function sms_print_pdf_tcpdf_content(&$vars)
{
$pdf = $vars['pdf'];
$node = node_load(arg(1));
if ($node->type == 'equipment') {
$pdf->setFont($vars['font'][0], $vars['font'][1], $vars['font'][2]);
$html = str_get_html($vars['html']);
$images = $html->find('.item-img .img-responsive');
$x = 15;
$y = 20;
$w = 55;
$h = 40;
foreach ($images as $img) {
$pdf->Image($img->src, $x, $y, $w, $h, '', '', 'M', false, 300, '', false, false, 1, false, false, false);
$x = $x + $w + 2;
if ($x >= 160) {
$y = $y + $h + 2;
$x = 15;
}
}
$des = $html->find('.field-name-body .field-item', 0);
$pdf->writeHTMLCell(null, null, 15, $y + $h + 10, $des->innertext, 0, 1);
$table = $html->find('.field-name-field-specifications', 0);
$table->find('table', 0)->setAttribute('style', 'border-collapse: separate; border-spacing: 4px; width: 100%; margin-left: -4px; margin-right: -4px;');
$table->find('table thead tr', 0)->setAttribute('style', 'background-color: #144074; color: #fff;');
foreach ($table->find('table td, table th') as $td) {
$td->setAttribute('style', 'padding: 20px;');
}
foreach ($table->find('tbody tr') as $k => $tr) {
if ($k > 0) {
$tr->setAttribute('style', ' background-color: #f2f2f2; color: #3d3d3d;');
}
}
$pdf->writeHTML('<br><div><strong>' . $table->find('.field-label', 0)->innertext . '</strong>' . $table->find('.field-items', 0)->innertext . '</div>', true);
$price = $html->find('.box-price', 0);
$priceHtml = "<strong>" . $price->find('.field-name-field-price .field-label', 0)->innertext . "</strong>";
$priceHtml .= $price->find('.field-name-field-price .field-item', 0)->innertext;
$priceHtml .= $price->find('.field-name-field-currency .field-item', 0)->innertext;
$pdf->writeHTML($priceHtml, true);
$contact = $html->find('.wrapp-contact', 0);
$contactHtml = "<br/><br/><strong>" . $contact->find('.label-contact', 0)->innertext . "</strong><br/>";
foreach ($contact->find('.field') as $f) {
$contactHtml .= '<br/><span><strong>' . $f->find('.field-label', 0)->innertext . '</strong>' . $f->find('.field-item', 0)->innertext . '</span>';
}
$pdf->writeHTML($contactHtml, true);
}
return $pdf;
}
В итоге мы получили внешне PDF документ который удовлетворяет требованиям заказчика и минимальными затратами по времени.