Создание PDF-файлов с помощью CakePHP

Для генерации PDF-файлов посредством CakePHP, рекомендуется использовать плагин CakePdf.
При его помощи довольно просто сгенерировать PDF из HTML, преобразовывать в файлы для загрузки, е-mail и т.д.
Установка
Во-первых, нужно решить какой движок вы будете использовать.
WkHtmlToPdf самая быстрая утилита, однако все будет зависеть от интерфейса командной строки (CLI) и правильной установки бинарных файлов. На разных операционных системах она будет работать по-разному, а может и вообще не работать.
При использовании исполняемых файлов в UNIX и Windows, проблем быть не должно.
Нужно просто скачать exe-файл для вашей системы тут
Далее подключите его в настройке конфигурации CakePdf:
Configure::write('CakePdf.binary', YOUR_PATH_TO . 'wkhtmltopdf\wkhtmltopdf.exe');
Если предварительно скомпилированные файлы для UNIX все же не работают, и команда apt-get install wkhtmltopdf не помогает, то вам необходимо скомпилировать их вручную.
Не забудьте также изменить путь к файлу, если он установлен не по умолчанию
Configure::write('CakePdf.binary', YOUR_PATH_TO . 'wkhtmltopdf/bin/wkhtmltopdf');
Обычно я выбираю библиотеку DomPdf, так как она достаточно надежная. И несмотря на то, что код PHP более медленный чем нативный подход, она работает со всеми операционными системами и настройками без необходимости установки дополнительных зависимостей. Если для вас действительно важна скорость, тогда вам следует пересмотреть вопрос использования внутренних библиотек сервера. Но для меня, генерация счет-фактур и прочего, не является критической по времени и обычно выполняется асинхронно в фоновом режиме через оболочки.
В DomPdf есть важный параметр "enable remote", если в PDF-файлах используются изображения.
define('DOMPDF_ENABLE_REMOTE', true);
Для CakePdf не забудьте данную часть настроек, она может выглядеть таким образом:
$config['CakePdf'] = array( 'engine' => 'CakePdf.DomPdf', 'options' => ..., 'margin' => ..., 'orientation' => 'portrait', );
Посмотрите официальную документацию там есть все, что нужно знать по части установки.
Дополнительная настройка
Рекомендуемым способом является использование настройки CakePlugin::load('CakePdf', array('bootstrap' => true, 'routes' => true)); которая должна будет автоматически переключать классы просмотра.
Если вы не хотите, чтобы плагин загружал bootstrap/routes и предпочитаете делать это вручную, вам необходимо самостоятельно указать все ссылки с расширением .pdf до CakePdf плагина PdfView.
public $components = array(
'RequestHandler' => array(
'viewClassMap' => array('pdf' => 'CakePdf.Pdf')
)
);
Также это полезно если вам нужно перезаписать/расширить PdfView класс, по какой-либо причине
Пропустить файлы маршрутизации плагина практично, если настройки расширений уже установлены в ваших маршрутах.
Router::parseExtensions();
Router::setExtensions(array('json', 'xml', 'rss', 'pdf')); // We just add pdf to the already defined ones
В таком случае вы можете просто обновить конфигурацию APP/Config/routes.php:
Применение
В официальной документации уже все точно определено, поэтому я не буду рассматривать все детально. Краткий пример:
public function view($id) {
$this->pdfConfig = array(
'filename' => 'invoice',
'download' => (bool)$this->request->query('download')
);
$invoice = $this->Invoice->find('first', array('conditions' => array('id' => $id)));
$this->set(compact('invoice');
}
Если вы используете мой Tools плагин, можете просто применить $invoice = $this->Invoice->get($id).
Убедитесь в том, что у вас есть базовый PDF макет в /View/Layouts/pdf/default.ctp и шаблон представления для PDF в /View/Invoices/pdf/view.ctp.
Если вы предоставите доступ без расширения (/invoices/view/1), операция будет в состоянии отобразить обычную HTML-страницу со счетом-фактурой в табличной форме.
Если вы подключаете с расширением /invoices/view/1.pdf, то он автоматически переключит класс представления в PdfView и отобразит его в виде PDF-файла:
$this->Html->link('View PDF', array(
'action' => 'view', $id, 'ext' => 'pdf'
));
Обратите внимание на хитрость с download , используя для этого строку запроса. Если подключаться с помощью ?download=1 произойдет загрузка файла, вместо простого отображения.
$this->Html->link('Download PDF', array(
'action' => 'view', $id, 'ext' => 'pdf', '?' => array('download' => 1)
));
Рекомендации
URL-ссылки и пути
Для того чтобы все движки работали с вашими URL-ссылками и изображениями, выводимыми вспомогательными приложениями и, следовательно, с неструктурированными абсолютными URL-адресами (/controller/action/ и /img/foo.jpg), это небольшое изменение будет весьма полезным в вашем AppHelper:
/**
* Overwrite to make URLs absolute for PDF content.
*
* @param mixed $url
* @param bool $full
* @return string
*/
public function url($url = null, $full = false) {
if (!empty($this->request->params['ext']) && $this->request->params['ext'] === 'pdf') {
$full = true;
}
return parent::url($url, $full);
}
/**
* Overwrite to make paths for assets absolute so they can be found by the PDF engine.
*
* @param string $path
* @param array $options
* @return string
*/
public function assetUrl($path, $options = array()) {
if (!empty($this->request->params['ext']) && $this->request->params['ext'] === 'pdf') {
$options['fullBase'] = true;
}
return parent::assetUrl($path, $options);
}
Таким образом они станут абсолютными, полностью включая основу (схема+домен) в контексте PDF.