html to pdf
2016 28 Jun

Save a pdf copy of node whenever its created

Did you ever feel the need to save a node in pdf format on your server whenever a new node is published, if this is your case then you have come to the right place.

Although creating a pdf is not a problem here, that you can do it easily using any pdf creating library available in the market, by the way I used “dompdf”, but there are several other libraries available also.
Here is the code to generate a pdf of any html document
   

  $html = < HTML DOCUMENT >

   use Dompdf\Dompdf;
   $dompdf_path = libraries_get_path('dompdf');
   require_once($dompdf_path . '/autoload.inc.php');

   // Instantiate and use the dompdf class
   $dompdf = new Dompdf();
   $dompdf->loadHtml($html);

   // Setup the paper size and orientation
   $dompdf->setPaper('A4', 'landscape');

   // Render the HTML as PDF
   $dompdf->render();
   $pdfoutput = $dompdf->output();
   $filename = 'public://' . '/submission-' . $node->nid . '.pdf';
   $file_object = file_save_data($pdfoutput, $filename, FILE_EXISTS_REPLACE);

So in order to create this pdf you need that node’s html view right when that node is created, so drupal provides some hooks for that which triggers when a node is created like:
hook_node_presave($node), hook_node_insert($node).

Now at this stage this node’s database transaction is still not complete which means that you don’t have a node in database and you cannot get node_view($node); here in node presave & node insert stages.

You can do your pdf generation process only once your node is in database, but drupal does not provide any kind of ‘post save hook’, although there is a module for it https://www.drupal.org/project/hook_post_action which provides some hooks which will trigger when your node is saved.

What this module does is that it makes use of drupal_register_shutdown_function($callback = NULL); 
As the name suggest it registers a function for execution on shutdown.
You can send some extra parameters in drupal_register_shutdown_function other than callback function.

So we can register our callback function in node presave function so that our callback function will be called once the node_save process is completed. Hence we can do our pdf creation process in our callback function.

use Dompdf\Dompdf;

function HOOK_node_presave($node) {
 if ($node->type == 'article') {
    drupal_register_shutdown_function(_my_custom_callback, $node);
 }
}

function _my_custom_callback($node) {
  // do pdf creation process here
   $node_view = node_view($node, 'full');
   $html = render($node_view);

   $dompdf_path = libraries_get_path('dompdf');
   require_once($dompdf_path . '/autoload.inc.php');

   // Instantiate and use the dompdf class
   $dompdf = new Dompdf();
   $dompdf->loadHtml($html);

   // Setup the paper size and orientation
   $dompdf->setPaper('A4', 'landscape');

   // Render the HTML as PDF
   $dompdf->render();
   $pdfoutput = $dompdf->output();
   $filename = 'public://' . '/submission-' . $node->nid . '.pdf';
   $file_object = file_save_data($pdfoutput, $filename, FILE_EXISTS_REPLACE);
}

Alright so your pdf is saved in files directory of your installation, now all you need to do is to save a reference of this file in the same node so that you could know where to find the pdf file for any node.

   .
   .
   .
   $pdfoutput = $dompdf->output();

   $filename = 'public://' . '/submission-' . $node->nid . '.pdf';

   $file_object = file_save_data($pdfoutput, $filename, FILE_EXISTS_REPLACE);
   $file_object_arr = (array)$file_object;
   $file_object_arr['display'] = 1;
   $node->article_pdf[$node->language][0] = $file_object_arr;
   node_save($saved_node);
}

But wait we are saving that node again this would put a us in a loop, because that node_presave will trigger again as we are saving the same type of node again, so we must put a check there so that it registers the shutdown function only once.

Now the best way to do is using drupal_static(__FUNCTION__); it keeps the variable cached just for a full request and that's what we want.

So here we go:
 

function HOOK_node_presave($node) {
 if ($node->type == 'article') {
   $life_cycle_complete = &drupal_static(__FUNCTION__);
   if (!isset($life_cycle_complete)) {     
    drupal_register_shutdown_function(_my_custom_callback, $node);
    $life_cycle_complete = 'processed';
   }
 }
}

Cheers yes

Latest Blogs

Healthcare mobile app development

How Healthcare Mobile Apps is Booming the Healthcare Sector

No one can deny that mobile apps have revolutionized all sectors, whether eCommerce, education, or mobile healthcare apps. There is hardly any sector untouched by the blessings of mobile apps.

Read More

Mobile UX design

Top Do's & Dont's for a Perfect Mobile User Experience Design

In any situation, the first impression is considered the last impression. The same is the case in the world of mobile applications.

Read More

Mobile app development trends

15 Effective Mobile App Development Trends That Will Boost

The mobile app development industry is continuously evolving with great speed. There is indeed tough competition in this industry.

Read More

Why it is Best to Use ReactJS for Web Development

Why it is Best to Use ReactJS for Web Development

Front-end and frameworks are inevitable and essential parts of web development. As the technologies improve day by day, many new frameworks and libraries are coming to get better results.

Read More