Deblan blog

Générer des PDF dans Symfony2

La génération de PDF fait souvent partie des cahiers des charges de projets de moyenne et grande envergure. Il existe quelques outils comme HTML2PDF qui repose sur FPDF ou TCPDF. Cependant, bien qu'ils soient puissants et fonctionnels, leur utilisation peut très vite devenir complexe quand il s'agit de mettre en forme précisément les contenus.

C'est pourquoi nous avons décidé d'utiliser Wkhtmltopdf. Ce petit bijou a la particularité de reposer sur un moteur de rendu Webkit. Le javascript est interprété et des plugins additionnels (comme Flash) peuvent être ajoutés. En plus de ça, il interprète extrêmement bien le CSS et toutes les balises HTML sont prises en compte.

Bon, trêve de bavardage, voici comment l'installer et l'utiliser.

Je travail avec Debian Wheezy, que ce soit sur mon poste de développement ou sur les serveurs en production. Vous devrez donc adapter la suite de l'article à votre système.

Installation de Wkhtmltopdf
Coté système
$ su - 
# aptitude update
# aptitude install wkhtmltopdf

Wkhtmltopdf a besoin d'un serveur X pour fonctionner. Comme les serveurs n'en disposent pas, nous allons installer xvfb qui permet d'en créer un virtuel.

# aptitude install xvfb

Il faut ensuite préparer un wrapper pour lancer wkhtmltopdf via xvfb :

# cat > /usr/bin/wkhtmltopdf.sh << EOF
#!/bin/sh

xvfb-run -a wkhtmltopdf "$@"
EOF
# chmod +x /usr/bin/wkhtmltopdf.sh
Coté Symfony2

KNP Labs a développé un bundle dédié à wkhtmltopdf. Ke vais passer par composer pour l'intégrer au framework :

$ cd /chemin/vers/le/projet
$ ./composer.phar require knplabs/knp-snappy-bundle

Activons à présent le bundle dans AppKernel.php :

$bundles = array(
    /* ... */
    new Knp\Bundle\SnappyBundle\KnpSnappyBundle(),
)

Il est nécessaire de le configurer en indiquant le chemin de wkhtmltopdf. Dans le fichier app/config/config.yml, ajoutez ces lignes :

knp_snappy:
    pdf:
        enabled:    true
        binary:     /usr/bin/wkhtmltopdf.sh
        options:    []

Videz le cache et lisez la doc pour savoir comme il fonctionne. Un truc intéressant à savoir : il utilise des feuilles de styles dédiées à l'impression.

Une astuce pour gérer la pagination

Bien qu'il soit ultra puissant, il n'y a pas d'outil pour gérer la pagination. Wkhtmltopdf va récupérer du code HTML et convertir le tout en PDF. En fonction de la taille de la page (qui est paramétrable) et de son format (portait ou paysage), il va enquiller le contenu et générer une page quand il sera nécessaire de le faire. Si vous souhaitez faire des sauts de page, vous devrez faire un peu de javascript. Voici la démarche que j'ai employée pour un projet.

J'ai découpé le contenu en différentes divisions portants la classe "print-page". Chaque division représente un contenu qui doit nécessairement être affiché en début de page. Dans mon projet, j'ai utilisé un rendu en A4 paysage et la zone représentant le contenu fait 1340px de largeur pour 934px de hauteur. Il suffit à présent de modifier la hauteur des divisions en calculant le nombre de pages nécessaires à leur affichage.

// Dépend de jQuery

var page_height   = 934;
var $print_pages  = $('.print-page');

$print_pages.each(function(i, v) {
	var $content    = $(this);	
	var height      = $content.height();
	var pages_count = 1;
	var newheight   = pages_count * page_height;

	while(height - 20 > newheight) {
		pages_count++;
		newheight = pages_count * page_height;
	}
	
	$content.css({height: newheight});
});

Il est également important d'indiquer des largeurs à vos contenus car j'ai eu quelques problèmes de génération avant de le faire.


  • doudou
    • ,
    • Faut pas oublier de l'add au kernel aussi ^^'
  • fabirus
    • ,
    • et si nous voulons utiliser ce bundle sur un serveur de production qui tourne sur php, quelle est la solution
      merci,
      cordialement.
  • Simon
    • ,
    • Vous pouvez installer wkhtmltopdf et xvfb-run sur le serveur (car vous avez un accès root) ou vous intégrez wkhtmltopdf et xvfb-run dans votre projet.
  • Arsene
    • ,
    • Comment faire alors pour l integrer dans son projet symfony2
  • Simon
    • ,
    • Après avoir installé le bundle, vous devez télécharger la version compilée de wkhtmltopdf et de la placer dans votre arborescence symfony (dans ./bin par exemple). Il ne restera qu'à modifier "binary: /usr/bin/wkhtmltopdf.sh" avec quelque chose comme : "binary: %kernel.root_dir%/../bin/wkhtmltopdf.sh" (modulo la création du script shell)
  • Issa
    • ,
    • Bonjour,

      savez vous si je peux faire de la fusion de pdf avec cette outil ?

      et comment je peux positioner des élements sur une page pour ensuite réaliser une fusion avec un fichier pdf template ?
  • Simon
    • ,
    • Bonjour Issa,

      Pour la fusion de PDF, je te recommande chaudement fpdi qui fait extrêmement bien le boulot :) Je l'ai d’ailleurs récemment utilisé en plus de wkhtmltopdf.

      Si tu veux plus d'infos, n'hésites pas.
  • Nama Seydou
    • ,
    • Salut,
      jutilise knp snapy Bundle,
      je vux creer des recu pdf a partir de ce bundle
      voici le Code l'action de mon controller
      public function pdfAction(scolariteEtudiant $scolariteEtudiant) {
      //tout ceci est en comentaire
      /* $html = $this->renderView('scolariteetudiant/showpdf.html.twig', array('scolariteEtudiant' => $scolariteEtudiant));
      // $html = $this->renderView('MyBundle:Foo:bar.html.twig', array(
      //'some' => $vars
      // ));

      return new Response(
      $this->get('knp_snappy.pdf')->getOutputFromHtml($html), 200, array(
      'Content-Type' => 'application/pdf',
      'Content-Disposition' => 'attachment; filename="recu.pdf"',
      'orientation' => 'Landscape'
      )
      );*/
      //jusque là
      $this->get('knp_snappy.pdf')->generateFromHtml(
      $this->renderView(
      'scolariteetudiant/showpdf.html.twig',
      array(
      'scolariteEtudiant' => $scolariteEtudiant
      )
      ),
      '../../../../application/pdf/recu.pdf'
      );
      }
      j'ai déjà installer wkhtmltopdf et xvfb mais on m'affiche l'erreur suivante
      "Warning: mkdir(): Permission non accordée"
      pourtant le chemin est crée et j'ai même donné les droits au dossier 'application/pdf"
  • Simon
    • ,
    • Êtes-vous sur du chemin correspondant à "../../../../application/pdf/" ?
  • Nama Seydou
    • ,
    • oui oui,
      ce path a créer le dossier application et a son sein le dossier pdf a l'endroit indiqué dans l'application, mais c'etait seulement en mode lecture, dc j'ai fait un chmod 777 -R sur le dossier. mais ca na rien changer à l'erreur
  • Simon
    • ,
    • Peut-être que ce n'est pas de ce dossier dont il est question alors. J'essayerais de trouver la ligne qui renseigne le chemin du répertoire et je regarderais quel répertoire il veut créer.

Ajouter un commentaire

Vous pouvez utiliser du markdown.Afficher l'aide.