Commentaires
Et si on mettait un peu de Symfony dans Javascript ?
Ces derniers temps, j'ai du faire pas mal de front. J'ai donc travaillé avec
Marionette.js et
Cie.
Bien que mon application JavaScript soit indépendante (cliente qui consomme
des services), elle fait partie de mon application Symfony. Il est donc
dommage de ne pas exploiter dans mon application JavaScript ce qui est
présent dans mon application Symfony.
Dans cet article je vais vous présenter ce qu'il est possible de faire.
Personnellement, j'aime bien JavaScript, mais je n'aime pas en faire. Si
pour toi c'est pareil, tape dans tes mains \o/
Routage Symfony en JavaScript
Dans notre JavaScript on a souvent besoin d'utiliser nos URLs, par exemple
pour faire des appels en Ajax. Il y a un bundle qui permet d'avoir notre
configuration de routage Symfony en Javascript !
Il s'agit du meilleur FOSJsRoutingBundle
(friendsofsymfony/jsrouting-bundle
).
Tout d'abord, on ajoute l'option expose
à l'annotation
Route
dans notre contrôleur :
<?php
/**
* @Route("/meth-cookers/{slug}", name="meth_cooker", options={"expose"=true})
*/
Ensuite on exporte les routes avec la commande
fos:js-routing:dump
:
$ php app/console fos:js-routing:dump
La commande crée un fichier JavaScript js/fos_js_routes.js
qu'il faut ajouter à nos assets, sans oublier
bundles/fosjsrouting/js/router.js
, mais c'est dans la doc du
bundle ;)
Enfin nous pouvons passer à l'utilisation dans JavaScript :
url = Routing.generate('meth_cookers', { slug: 'walter-white' });
La variable url
prend alors pour valeur
/meth-cookers/walter-white
.
Les routes sont donc définies uniquement dans Symfony, mais utilisables dans
Symfony ET dans Javascript.
Templates avec Twig JS
Johannes avait présenté Twig JS lors du
Symfony Live il y a deux ans et à vrai dire je
n'étais pas vraiment convaincu. Mais c'est tellement simple à mettre en
place et à maintenir qu'en fait j'adore l'utiliser. Il y a d'autres
solutions de Twig en JS, mais je préfère celle de Johannes qui
permet d'avoir plusieurs templates dans un même fichier JavaScript (car les
templates sont compilés), et qui, lors de cette compilation, permettent de
faire certaines choses.
Différences avec Twig PHP :
- On ne peut y passer que des objets JSON,
- Seulement quelques fonctions et les filtres,
- Twig JS compile des fichiers JavaScript à partir des templates.
Bon, tout d'abord il faut le bundle ! C'est JMSTwigJsBundle
(jms/twig-js-bundle).
Ensuite on crée ses templates comme d'habitude sauf qu'on ajoute le tag
twig_js
en début de fichier qui va permettre de définir un nom
de template. Par exemple :
{% twig_js name="LosPollosHermanos_Lab" %}
<h1>Los Pollos Hermanos meth lab</h1>
<p>Surface: {{ lab.surface }}</p>
Puis on ajoute le fichier twig.js
et nos templates dans les
assets (easy) :
{% javascripts %}
'../vendor/jms/twig-js/twig.js'
'../app/Resources/templates/LosPollosHermanos/Office.twig'
'../app/Resources/templates/LosPollosHermanos/Lab.twig'
output='js/templates.js' filter="twig_js"
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
Enfin, on fait le rendu de notre template :
Twig.render(this.template, {'lab': {'surface': 20 }});
Utilisation des variables Assetic
Assetic permet de faire quelque chose de très sympa que j'ai découvert en
lisant l'article de Johannes Schmitt intitulé
« Asset Variables in Assetic ».
Pour résumer, il est possible de charger et de générer des fichiers
JavaScript différent selon l'environnement (env
) ou selon la
locale (locale
) de l'utilisateur.
Exemple avec locale [en, fr]
pour regrouper en un fichier
JavaScript l'ensemble de mes fichiers de locale de mes bibliothèques :
{% javascripts %}
'../app/Resources/components/lib-foo/{locale}.js'
'../app/Resources/components/lib-bar/{locale}.js'
output='js/lang.{locale}.js' vars=['locale']
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
Ainsi on obtient js/lang.fr.js
(lib-foo/fr.js + lib-bar/fr.js)
et js/lang.en.js
(lib-foo/en.js + lib-bar/en.js). Les
utilisateurs n'auront que le JavaScript correspondant à leur locale.
Mais il y a mieux ! Il s'agit de générer des templates avec Twig JS traduits
en fonction de la locale
!
En effet, le filtre trans
et la locale permettent de
traduire des chaines de caractères lors de la compilation en utilisant les
traductions de Symfony !
Reprenons notre exemple de Twig JS mais en y ajoutant la locale [en, fr]
.
On met à jour le template en utilisant le filtre trans
pour
traduire nos clés :
{% twig_js name="LosPollosHermanos_Lab" %}
<h1>{{ "los_pollos.meth_lab"|trans }}</h1>
<p>{{ "los_pollos.surface"|trans }}: {{ lab.surface }}</p>
On met à jour nos assets dans la vue principale :
{% javascripts
'../app/Resources/template/LosPollosHermanos/Office.twig'
'../app/Resources/template/LosPollosHermanos/Lab.twig'
output='js/templates.{locale}.js' filter="twig_js" vars=['locale']
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
Ainsi on obtient js/templates.fr.js
et
js/templates.en.js
dont le contenu est différent selon la
locale
. Les utilisateurs n'auront que les templates compilés
correspondant à leur locale.
Attention : Cette traduction n'est effectuée que lors de la
compilation du template. Il n'est pas possible de traduire à la volée à
l'exécution de l'instruction Twig.render()
. En fait, ça le
sera peut être pour Noël ;)
Date formatée avec la locale
Pour formater une date, j'ai choisi d'utiliser Moment.js
que l'on peut installer avec bower.
Là, c'est le moment (notez le jeu de mot...) d'utiliser ce que nous avons
étudié précédemment afin de l'ajouter à nos assets :
{% javascripts
'../app/Resources/components/moment/min/moment.min.js'
'../app/Resources/components/moment/min/lang/{locale}.js'
output='js/date.{locale}.js' vars=['locale']
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
Maintenant il faut créer un filtre dans Twig JS pour qu'on puisse l'utiliser
dans les templates :
Twig.setFilter('date', function(format) {
return moment(date).format(format);
});
Facile non ? L'utilisation l'est encore plus :
{{ meth.delivery.scheduledDate|date('LL') }}
I18N : traductions Symfony en JS
William Durand a écrit un bundle pour ça :
BazingaExposeTranslationBundle
(willdurand/expose-translation-bundle) !
Par exemple, si le fichier
app/Resources/translations/messages.fr.yml
contient la
traduction suivante :
los_pollos.welcome: "Bienvenue à Los Pollos %name%, vous aimez le poulet ?"
On peut alors l'utiliser dans notre JavaScript avec l'instruction
Translator.get()
:
Translator.get('los_pollos.welcome', { "name" : "Jesse Pinkman" });
Pour obtenir Bienvenue à Los Pollos Jesse Pinkman, vous aimez le poulet ?
.
Conclusion
C'est une aberration de faire les choses en double (une fois dans Symfony,
puis une autre dans JavaScript) et grâce à ces bundles, on peut faire du
JavaScript un peu plus sereinement en s'appuyant sur ce qu'on a déjà fait
dans Symfony.
Merci à plus !