Symfony2 : Générer des pdf avec dompdf

Symfony2 : Générer des pdf avec dompdf
1 novembre 2016 No Comments Non classé,Outils, frameworks et développement Renaud M.G.

Suivez ce tutoriel et découvrez comment générer facilement des documents PDF avec Symfony2.

Pour commencer, partons du besoin : générer des documents pdf dans un projet Symfony 2. Pour savoir quel package utiliser nous allons faire une petite recherche. Dans ce domaine, Google c’est bien mais ça ne vaut pas packagist qui est fait pour ça.

Capture d'écran d'une recherche sur packagist.org

Recherche du terme “pdf” sur packagist.org

Comme vous le voyez sur la capture ci-dessus, 2 packages sortent du lot : dompdf et knp-snappy. J’ai choisi dompdf pour 2 raisons : il a quand même 50% d’étoiles en plus sur le site et knp-snappy utilise wkhtmltopdf qui est excellent mais peut être un cauchemar à mettre en place, alors que dompdf n’utilise aucune dépendance de ce type.

Installation du bundle dompdf

Passons maintenant aux choses sérieuse. Comme tout package supporté par Composer, l’installation de dompdf est ultra simple :

composer require dompdf/dompdf
Installer dompdf avec Composer
composer require dompdf avec Symfony2

composer require dompdf/dompdf

Si les pré-requis sont remplis, tout se fait tout seul. A propos des pré-requis, ils sont assez nombreux, mais assez courants :

  • PHP version 5.3.0 ou supérieur
  • DOM extension
  • GD extension
  • MBString extension
  • php-font-lib
  • php-svg-lib

Il est aussi possible de mettre en place un OPcache (OPcache, XCache, APC…) et/ou les extensions IMagick ou GMagick pour améliorer les performances. Pour plus de détails rendez-vous ici.

Tout s’est bien passé ? Vous n’avez plus rien à faire, même pas besoin de modifier votre fichier AppKernel.php.

Exemple simple : hello world

Allons-y doucement et commençons par un exemple tout simple : nous allons afficher une simple chaîne de caractères dans un document A4 tout blanc. Simple comme bonjour.

<?php
//   On importe la classe Dompdf
use Dompdf\Dompdf;
//...
class TestController extends Controller
{
	public function toPdfAction() {
		// On  crée une instance de Dompdf
		$dompdf = new Dompdf();
		//  On  ajoute le texte à afficher
		$dompdf->loadHtml('Hello world');        
		// On fait générer le pdf  à Dompdf ...
		$dompdf->render();
		//  et on l'affiche dans un   objet Response
		return new Response ($dompdf->stream());
	}
  // ...
          
Génération d'un fichier pdf simple avec Symfony2 et dompdf

Je pense que les commentaires du code parlent d’eux-même. Nous allons pouvoir passer aux choses sérieuses et attaquer un exemple réel

Exemple réel : un pdf à partir d’un template twig

Afficher un texte noir sur fond blanc c’est un bon début mais ça ne sert pas à grand chose. Maintenant nous allons générer un pdf avec un en-tête et un pied de page et nous allons y afficher les détails d’un objet.

Premièrement, occupons-nous du contrôleur :

<?php 
// On inclue  dompdf et  la classe qui permet de gérer ses options
use Dompdf\Options;
use Dompdf\Dompdf;
//...

class ObjectController extends Controller
{
  public function toPdfAction($objectId) {
    // On récupère l'objet à afficher (rien d'inconnu jusque là)
    $objectsRepository = $this->getDoctrine()->getRepository('TestBundle:Object');
    $object = $objectsRepository->findOneById($objectId);        
    // On crée une  instance pour définir les options de notre fichier pdf
    $options = new Options();
    // Pour simplifier l'affichage des images, on autorise dompdf à utiliser 
    // des  url pour les nom de  fichier
    $options->set('isRemoteEnabled', TRUE);
    // On crée une instance de dompdf avec  les options définies
    $dompdf = new Dompdf($options);
    // On demande à Symfony de générer  le code html  correspondant à 
    // notre template, et on stocke ce code dans une variable
    $html = $this->renderView(
      'TestBundle:Object:pdfTemplate.html.twig', 
      array('object' => $object)
    );
    // On envoie le code html  à notre instance de dompdf
    $dompdf->loadHtml($html);        
    // On demande à dompdf de générer le  pdf
    $dompdf->render();
    // On renvoie  le flux du fichier pdf dans une  Response pour l'utilisateur
    return new Response ($dompdf->stream());
}
Exemple de controleur Symfony2 permettant de générer un pdf à partir d'un template

Ensuite, voyons un exemple de template qui peut être utilisé :

<html>
  <head>
    <style>
      /* On commence par définir les propriétés de la page : les marges en haut
       * et en bas permettront d'insérer un en-tête et un pied de page */
      @page {
        margin: 50px 0 25px 0;
      }
      /* La position fixed permet de placer les éléments sur toutes les pages
       * du document pdf, le reste n'est que décoration */
      #header, #footer {
        position: fixed; 
        left: 0px;
        right: 0px;
        color: #fff;
        background-color: #000;
      }
      #header {
        top: -50px;
        height: 50px;
      }
      #footer {
        bottom: -25px;
        height: 25px;
      }
      /* Pour améliorer un peu la lisibilité on ajoute une marge au corps de
       * texte. Ca aurait pu être fait en agrandissant les marges au niveau
       * de la page mais je trouve qu'utiliser un div dédié pour le contenu
       * est cohérent */
      #content { 
        margin: 25px;
      }
      /* On teste quelques d'options css différentes */
      h1 { text-transform: uppercase; text-align: center; font-weight: bold}
      h2 {font-style: italic; font-weight: bold; border: solid 1px #ccc; }
      /* On met même en place un système de colonnes pour tester les float */
      .col-25, .col-75 { float: left; }
      .col-25 { width: 25%; }
      .col-75 { width: 75%; }
      .row { clear: both; }
    </style>
  </head>
  <body>
    <!-- On commence par ajouter le header et le footer pour qu'ils soient 
      visibles sur toutes les pages. Si on les ajoute après avoir rempli plus
      d'une page, ils ne seront insérés qu'après le saut de page -->
    <div id="header">
      <!-- Grâce aux options définies dans le contrôleur on peut insérer des 
        images à partir de leur url absolue -->
      <img src="{{ app.request.getSchemeAndHttpHost() ~ asset('/bundles/test/img/logo.png') }}" alt="logo">
    </div>
    <div id="footer">Texte du footer</div>
    <!-- Maintenant on rempli le document -->        
    <div id="content">
      <h1>{{object.title}}</h1>
      <h2>{{object.subtitle}}</h2>
      {% for prop in object.properties %}
        <div class="row">
          <div class="col-25"><h3>{{prop.name}}</h3></div>
          <div class="col-75">{{prop.value}}</div>
        </div>
      {% endfor %} 
    </div>       
  </body>
</html>
Exemple de template twig permettant de générer un document pdf

Que retenir de tout ceci ?

Un petit exemple vaut plus qu’un long discours et je suis persuadé que c’est le cas ici. Vous voyez que c’est à peu près aussi simple de générer un fichier pdf que d’envoyer un email avec SwiftMailer. Vous voyez aussi que contrairement à d’autres outils, dompdf supporte des propriétés css assez sympa. En fait, quasiment toutes les propriétés css 2.1 sont supportées et, même si la doc indique que les float peuvent produire un résultat différent de celui attendu, j’ai voulu les inclure dans mon exemple pour vous montrer que si on reste raisonnable le résultat est plus que correct. Finalement il ne vous reste plus qu’à implémenter vos propres codes pour vous faire votre propre avis… et à venir le partager dans les commentaires ci-dessous.



Source : dompdf sur Github

A propos de l'auteur

Leave a reply

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *