I was under a lot of pressure to quickly implement PDF reports in my CakePHP application. Luckily I came across this excellent tutorial.
dompdf is an HTML to PDF converter written in PHP. It is a style-driven renderer: it will download and read external stylesheets, inline style tags, and the style attributes of individual HTML elements. It also supports most presentational HTML attributes.
I am going to add some flesh to the original and give some additional information based on my implementation.
- Starting point:
- I am working on a WAMP stack
- I have a standard CakePHP applications set-up
- I have a Customer in my app (you can naturally adapt to suit)
- Download dompdf and place the extracted files in
/app/Vendor - Add the following code to /app/Config/routes.php
Router::parseExtensions('pdf');
- In your controller, we have to load RequestHandler component so CakePHP can parse the .pdf extension. The post mentions adding it to AppController which makes sense but states that this is not recommended. It did not work for me, so I ended up adding it to the relevant Controllers
class CustomersController extends AppController { // you may already have components in the array - just add 'RequestHandler' public $components = array('RequestHandler'); // the rest of your code }
- Create a new folder in
/app/View/Layouts called - Add your new Layout,
default.ctp:<?php require_once(APP . 'Vendor' . DS . 'dompdf' . DS . 'dompdf_config.inc.php'); spl_autoload_register('DOMPDF_autoload'); $dompdf = new DOMPDF(); $dompdf->set_paper = 'A4'; $dompdf->load_html(utf8_decode($content_for_layout), Configure::read('App.encoding')); $dompdf->render(); echo $dompdf->output();
- Create a new action in our Customer controller. You actually don’t need to do this: if you call the methods that already exist you will get the data you want to proceed, but it does provide for better control on the output for PDF file, eg. the ability to increase the memory allocation.
public function view_pdf() { // increase memory limit in PHP ini_set('memory_limit', '512M'); $this->set(compact('customers', $this->Customer->find('all'))); }
- Duplicate our Customer
view.ctp
, rename it toview_pdf.ctp
to reflect the action name, and place it in a newpdf
folder inapp/View/Customer
.<?php echo $this->element('pdf-head'); // NB: footer must be at the beginning of the file... echo $this->element('pdf-foot'); // here is the body of your content as such echo $this->Html->tag('h2', $customer['Customer']['name']); // get all you HTML goodness in here - just make certain it is well-formed! // tables, in-line css - it all works echo '</body>'; echo '</html>';
- Here he mentions battling with css files — I managed to get that working — more later!
- Create a link to your PDF:
<?php // I am a big fan of opening things like this in a new tab, hence the target attribute echo $this->Html->link('PDF Export', array('controller' => 'customers', 'action' => 'view_pdf', 'ext' => 'pdf'), array( "class"=>"pdf_report", "target"=>"_blank" )); ?>
- To get my View code a bit more organised, I created two Elements:
pdf-head.ctp
<!DOCTYPE html> <html> <head> <?php define("APPLICATIONTIMEFORMAT", "Y-m-d"); // this standard CakePHP does NOT work echo $this->Html->meta('icon'); echo $this->Html->css('pdf'); echo $this->fetch('meta'); echo $this->fetch('css'); ?> <title>stylus PDF</title> // but this does... <link rel="stylesheet" type="text/css" href="<?php echo APP.'webroot'.DS.'css'.DS.'pdf.css'; ?>" media="all" /> </head> <body id="pdf"> // your logo is in the standard CakePHP location: /app/webroot/img <?php echo $this->Html->image("logo.gif", array('fullBase' => true, "id"=>"logo")); ?>
pdf-foot.ctp
<div id="pdf_footer" style="A_CSS_ATTRIBUTE:all;"> <table> <tr> <td id="copyright">Copyright © <?php echo date("Y"); ?> stylus</td> <td id="printdate">Printed: <?php echo date(APPLICATIONTIMEFORMAT); ?></td> </tr> </table> </div>
- One of the issues I had was getting images into my PDF — I wanted a logo at the top right of each page. Note the fullBase attribute in my
pdf-head.ctp
Element! (This answer on StackOverflow nailed it for me: http://stackoverflow.com/a/29224050/4779449) - Please also note the footer funkiness: the odd order of the include is required to repeat the footer content at the bottom of each page (if that is what you are after).
Thanks again to the author of the original post: http://www.syahzul.com/cakephp/how-to-generate-pdf-in-cakephp-2-x-with-dompdf/
Please note that I have already hit a short-coming of dompdf: it’s inability to handle large file sizes.
Hello, I am new to cakephp. in my trying to implement cakepdf am have this error:
wkhtmltopdf binary is not found or not executable: C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe
please can you help.
First and foremost, the obvious question: is there an executable called wkhtmltopdf.exe in the path C:\Program Files\wkhtmltopdf\bin\
Take a look at https://github.com/friendsofcake/cakepdf for output pdf files. Supports multiple pdf engines (Including DomPDF), and isn’t “hacky” in the way that it outputs the pdf data. Also supports cakephp 2.x and 3.x.
Solution for your problem with DomPDF and large files is to not use DomPDF 🙂 If you use the CakePDF plugin, you can use a fantastic tool called WkHTMLToPdf (http://wkhtmltopdf.org/) which is a fantastic command line tool that uses the native webkit rendering engine to render your html into a pdf file. It is lightning quick and supports massive files (I’ve made a +100MB pdf with it before)
Hi, do you know if it’s already possible to integrate the dompdf 0.6.2 or 0.7 on cakephp 3.1 ??? Thanks.
I can’t see why it wouldn’t be. Are you experiencing problems?
I’m facing problems with images extensions like png. When I switched to JPG, everything seems fine.
Try using the https://github.com/friendsofcake/cakepdf plugin. That definitely works with CakePHP 3.1