Huge export XLS | CSV | XML | JSON streamed via Symfony2

Ceci est une introduction

Ouais le titre est en anglais, mais bon vous avez compris quand même ? Sinon ça doit être dur la documentation en anglais surtout quand il n’y a que ça. Je fais une intro mais franchement personne la lit hein ? Je veux dire la plupart du temps on cherche une bonne soluce, on va direct checker le code en scrollant et puis on regarde si c’est pas trop la galère et si c’est propre.

Enfin bref, faire un export XLS/CSV on l’a tous fait. Une requête SQL, le header qui va bien et en avant Guingamp ! Mais que ce passe t’il quand la table en question fait plus de 100K lignes ? Je vais vous le dire : PHP va faire la gueule, c’est loin d’être une soluce adaptée cette histoire ! Ho et puis amusez vous à utiliser Doctrine2 pour appeler une table aussi grosse sans limit, non sérieusement essayez c’est rigolo !

Woot ! Du stream comme sur DPStream !

Enfin pas exactement, mais l’idée est la même.

En quelques mots voilà comment ça se passe : d’abord on accède à la base de données,  on prépare notre requête SQL, on utilise les solutions d’itérations et d’écriture de données du bundle Exporter de Sonata Project (super bien foutu) et enfin on envoie tout via la fonction de Symfony : StreamedResponse.

 

Pour ce faire on commence par installer le bundle Sonata-project exporter qui va nous aider dans tout le process du traitement de la donnée

Dans le composer.json

Un petit coup de composer update !

Enfin le controller :

 

Itérateur ? Fonction anonyme ? WTF

urkel

 

 

 

 

 

 

 

 

Bon c’est clairement un petit paragraphe pour ceux qui ne sont pas familiés avec ça.
Un itérateur est un design pattern qui permet de parcourir un objet de la même manière qu’un foreach. Sauf qu’il s’agit d’un foreach un peu plus évolué. Ici ce qui nous intéresse c’est  qu’il traite le gros paquet de données qu’on lui envoie en plein de petits paquets !
Concrètement au lieu de faire le gros bourrin à tous charger d’un coup dans la mémoire de PHP -au point de le faire tomber dans les pommes-, il va s’en occuper proprement bout par bout. Pour en savoir plus sur ce design pattern.

Il y a beaucoup à dire sur les fonctions anonymes ou fermeture(closure en anglais). Très simplement ce sont des petites fonctions qu’on utilise à la volée quand on en a besoin. Le mot clé use est là pour importer dans cette fonction des variables qui existent de base seulement dans le contexte de la méthode export(contexte parent). Ces petites fonctions sont donc accessibles à la volée avec des données importées d’un autre contexte. Bah tiens ça tombe bien c’est exactement ce dont a besoin pour le bon fonctionnement de la fonction de stream de Symfony ! Plus d’infos sur cette méthode.

 

Épilogue

Cette solution est inspirée du fonctionnement d’export de SonataAdmin. Le but étant de partager une solution robuste est très utile avec l’avantage ici d’une totale liberté sur les données exportées via une requête SQL. Vous pouvez mettre toute les requêtes que vous voulez, elle seront traitées en streaming et proprement formatées dans votre excel.
De plus cette solution n’a aucune dépendance à part le petit bundle exporter, on n’est donc pas obligé d’installer toute la solution admin de sonata pour en profiter sur n’importe quel projet !

Ceci dit je vous invite fortement à aller checker les bundles du Sonata Project si vous ne connaissez pas, ça vaut vraiment le détour.