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

Featured blog

web-personalization

Personalized Content is a Proven Entity !!

Irrespective of how big a business icon or brand you are, increasing the relevance of your website will always be critical to your success.

Read More

Git Hooks

Git hooks for better codes

We are programmers and we are always on the lookout for ways to improve our code. A good and structured way of coding defines the completeness of a programmer.

Read More

Drupal ,varnish cache

Hard time with Drupal, Varnish Cache and Cookies

Using a reverse proxy server in front of a web server is usually needed for every big site and it is a very good thing to do so as reverse proxy server will handle all the anonymous traff

Read More

Say no to captcha

Say no to captcha - Various Spam Protection Methods

Maintaining high traffic websites have their own merits and demerits, the most annoying thing about them is SPAM.

Read More