Создание 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.