Play 2.0 propose un nouveau moteur de template simple qui permet d’écrire des pages webs dynamiques. Directement inspiré de « Razor », l’un des moteurs de rendu d’ASP.MVC, il est à la fois simple et puissant. Venez avec moi, on va comparer Play 1.x et Play 2.0
Pour Play 2.0, lorsque Sadek Drobi et Guillaume Bort ont débuté leurs travaux avant l’été 2011, il y avait un challenge important : proposer un nouveau moteur de template.
Pour créer un moteur puissant :
– le langage doit être une composition de code HTML et de code dynamique compact et facile à lire dans la vue. Une page sans complexité accidentelle. Idéalement, le développeur ne doit pas être coupé lorsqu’il tape son code en étant obligé d’ouvrir et de fermer des marqueurs comme dans Play 1.x. Pour cela, il faut que le parser soit assez puissant pour distinguer les blocs de code et les blocs HTML.
– la syntaxe doit être facile et rapide à apprendre comme l’était Groovy dans Play 1.x. Contrairement à Grails, Play 1.x n’a pas beaucoup de possibilités du côté vue. Cette simplicité force à penser son code différemment du côté contrôleur/modèle. Il faut donc que les quelques tags soient faciles à comprendre pour un débutant.
– on ne doit pas inventer un n-ieme langage de template ou de markup, ne pas se lancer dans l’écriture d’un langage propriétaire. Idéalement, s’appuyer sur un langage puissant capable d’utiliser des closures et de manipuler les collections facilement comme Groovy ou Scala.
– le texte doit être éditable dans un éditeur de texte simple et fonctionner correctement dans un IDE
– la syntaxe doit être aussi pensé pour que les IDE puissent proposer des plugins puissants, chose difficile avec Groovy dans Play 1.x
– chaque page doit être testable de manière unitaire : la génération de la page HTML finale doit être quelque chose qui s’intègre dans le développement et que l’on peut appeler à partir d’un interpreteur SBT, sans devoir activer un controleur et mettre en marche le reste de Play 2.0.
Avec ceci en tête, Play 2.0 propose un moteur sympa. Le mieux pour t’en parler, c’est de te montrer du code.
Play 1.x et Play 2.0 sont sur un bateau
Imaginons que vous deviez coder une application pour vendre des Pizzas par Internet. Nous allons voir les différences entre l’ancien format de play et le nouveau. Je commence par une simple page avec un lien qui permet de charger une deuxième page.
Tout d’abord la version Play 1.x, on remarque que le texte du lien est encadré par une balise #{a} #{/a}. Cette balise n’est évidemment pas reconnue par votre éditeur HTML, sauf si vous utilisez le plugin Play pour IntelliJ.
#{extends 'main.html' /} #{set title:'Pizza' /} <h1>Bienvenue chez Pizza Service 1</h1> #{a @Application.listPizzas()}Liste de nos produits#{/a}
La version Play 2.0 reprend la même sémantique, mais comme vous pouvez le constater, cette fois l’écriture est plus fluide. Vous écrivez du HTML et vous utilisez simplement un marquer @ pour signaler au parser qu’il doit interpréter ce qui suit comme du code. Comment le parser sait que « vous avez terminé ? » et qu’il repasse au HTML ? C’est tout le génie de Sadek, qui a utilisé les parser combinators de Scala pour écrire cette partie. J’ai commencé à utiliser ce moteur en juin 2011. Et vraiment, il est génial.
@main("Pizza") { <h1>Bienvenue chez Pizza Service 2</h1> <a href="@routes.Application.listPizzas">Liste de nos produits</a> }
Liste des pizzas avec Play 1.x
Voyons maintenant comment itérer une liste de Pizza et afficher ligne par ligne le nom de chaque pizza. Côté serveur, nous imaginons que je retourne une List<Pizza> pizzas :
#{extends 'main.html' /} #{set title:'Pizza' /} <h1>Liste de nos pizzas</h1> #{list items:pizzas, as:'pizza'} ${pizza.name} <br/> #{/list}
Liste des pizzas avec Play 2.0
Pour la version Play 2.0, tout d’abord nous notons que le template est plus fortement typé. En effet, il déclare ligne 1 qu’il demande une liste de pizzas. Ceci permet à Play de vous notifier lorsque vous vous êtes trompé, et que votre template ne pourra pas fonctionner. Le typage fort est un principe qui permet de rendre votre code plus robuste.
L’itération de la collection ici, est présenté « à la Java ». Il y a d’autres moyens d’itérer, mais pour l’essentiel notez que c’est légèrement plus simple que l’ancienne version.
@(pizzas:List[Pizza]) @main("Pizza") { <h1>Liste de nos pizzas</h1> @for(pizza <- pizzas) { @pizza.name <br/> } }
Le Parser de template de Play 2.0 comprend la syntaxe de la boucle for, et sait aussi lorsque vous souhaitez simplement afficher du HTML, comme dans le cas de la balise <BR/> ci-dessus. Notez aussi le @pizza.name : pas de geName() qui viendrait perturber la lecture et qui rendrait le code plus lourd.
Gestion des blocs conditionnels
Voyons comment gérer maintenant le cas où la liste des Pizzas est vide. Il serait bien d’afficher un message d’information à l’utilisateur pour lui expliquer qu’il n’y a plus de Pizza non ?
Tout d’abord la version Play 1.x avec l’utilisation de la balise if et de la balise else :
#{extends 'main.html' /} #{set title:'Pizza' /} <h1>Liste des pizzas Play 1.0</h1> #{if pizzas} #{list items:pizzas, as:'pizza'} ${pizza.name}<br/> #{/list} #{/if} #{else} <strong>Désolé, nous n'avons pas de Pizzas en stock</strong> #{/else}
Ensuite la version Play 2.0, j’ai écrit du code « à la Java » pour vous montrer un exemple simple :
@(pizzas:List[Pizza]) @main("Pizza") { <h1>Liste de nos pizzas</h1> @if(pizzas.isEmpty){ <p>Pas de pizzas en ce moment</p> }else{ @for(pizza <- pizzas) { @pizza.name<br/> } } }
Un regret ici : si je veux utiliser la fonction map
de Scala sur @pizzas
à la place de la for-comprehension
, je ne peux pas utiliser getOrElse
car je me retrouve avec un scala.collection.mutable.Buffer
. Je poserai la question à Sadek à l’occasion.
Page de modèle
Lorsque vous créez une application web, il est important de pouvoir déclarer des modèles de page. Ceci vous évite de répéter dans chaque page des informations de mise en page commune comme le menu de navigation, le pied de page, etc.
Play 1.x
Avec Play 1.x la création d’un template est simple : il suffit de déclarer une page html et d’indiquer avec le tag doLayout que Play! doit insérer le code de votre page
(fichier main.html) <!DOCTYPE html> <html> <head> <title>#{get 'title' /}</title> </head> <body> #{doLayout /} </body> </html>
Pour indiquer que vous souhaitez utiliser le template « main.html », et que vous souhaitez passer « HELLO » pour le titre de la page,
#{extends 'main.html' /} #{set title:'HELLO' /} ... reste de la page ...
Play 2.0
Le principe est aussi de déclarer un template. Ce template accepte un paramètre title de type String. Ici, si la page fille ne précise pas de titre, je mets une valeur par défaut (Pizza Play 2). Le tag @content se contente d’exécuter la fonction qui génère le contenu principal de la page. Chose intéressante : vous pouvez avoir plusieurs blocs différents, mettre de la logique dans le template, bref faire tout un tas de chose que Play 1.x ne sait pas faire.
@(title: String = "Pizza Play 2")(content: Html) <!DOCTYPE html> <html> <head> <title>@title</title> </head> <body> @content </body> </html>
Conclusion
Plus concis et aussi puissant, Play 2.0 ouvre la porte du fonctionnel et du typage fort. Dans des templates Webs, cela permet de renforcer la qualité du code. Par ailleurs, chaque page est en fait compilé vers du Scala, puis du byte-code java. Ceci permet d’exécuter les pages comme de simples fonctions. Vous pouvez donc faire des tests unitaires sur une page en mockant la collection de Pizza afin de vérifier le comportement de la page. Oui tu as bien lu : tu peux faire un test sans avoir besoin de controleur et d’une base de données derrière.
Le bon père de famille devrait aussi être rassuré car le support de Servlet 3.0 est prévu dans Play 2.0. D’ici à ce que Play vienne aussi chatouiller le monde Java EE Web, on est plus très loin. Il y a tout un tas de trucs sympathiques comme le support de OAuth 1.0 et 2.0, la possibilité d’invoquer un deuxième serveur Play à partir du premier via Akka… bref pas mal de choses intéressantes.
Si vous vous posez la question d’utiliser Play 2.0 pour « un projet de la vraie vie » c’est encore un peu tôt. Personnellement j’ai travaillé du mois de mai à novembre sur Play 1.x avec Scala et le moteur que vous venez de voir : il est vraiment très simple et puissant. Vous avez sous le pied toute la puissance de Scala, surtout lorsqu’il s’agit de manipuler des collections, ou de faire des appels ré-entrant vers le controleur. Pour Play 2.0 il faudra attendre la sortie d’une version stable, prévue pour le printemps prochain. D’ici là on a déjà de quoi s’amuser cependant.
Je suis convaincu que quelques uns d’entre vous vont se mettre à faire du Scala grâce à Play 2.0. Souvenez-vous de ce petit article dans quelques mois… On en reparlera.
Référence :
Cette article est inspiré de l’article « Introducing Razor » écrit par Scott Guthrie
Merci, ça devrait rassurer ceux qui ont un peu peur du nouveau moteur de template à cause de son label Scala!
Je me pose des questions concernant l’utilisation de Play 2 ou 1.x en effet j’ai l’impression que les API ont énormément évoluée entre les deux versions conclusion pour démarrer faut-il « investir » sur Play 1.x ou attendre la version 2.0.
Après sur la 2.0 JAVA ne va t-il pas être « sacrifié » au profit de SCALA ?
@tatemilio si tu démarres et que tu n’as pas de besoins pressants pour une mise en prod il vaut peut être mieux commencer avec la 2.0 beta… par contre niveau docs tu ne trouveras pas grand chose pour le moment…
Normalement la version Java va continuer, c’est en tout cas ce qui est annoncé!
Si on utilise la version 1.2.x avec Scala, est-ce que ça sera pratiquement pareil que la version 2.0 ?
@tatemilio La version Play 1.x est la version stable du framework. La version 2.0 n’est pas encore terminée et ne le sera pas avant le printemps. Je conseille de travailler avec la version 1.x en Java, elle est très puissante et elle est maintenant très bien documenté. Il y a aussi des livres disponibles en Anglais (et je crois en Français bientôt). Le passage vers la 2.0 pourra se faire en fin d’année 2012 par exemple pour toi.
@Loic oui la version 1.x va continuer à être développé et maintenue. Zenxity et d’autres entreprises comme Lunatech ou comme la mienne ont des clients en production avec Play! 1.x.
@Jack : pour la syntaxe des pages, oui c’est presque pareil. Pour la partie Controller/Model c’est assez différent. Pour la partie Model, si tu as utilisé Anorm, c’est pareil. Les modifications ne sont pas très importantes et il est facile de porter un projet Play 1.x+play-scala 0.9.1 vers Play 2.0 beta.
Je parlais surtout de la version Java de Play 2, visiblement pas mal de personnes ont peur qu’elle disparaisse à moyen terme pour laisser la place à la version Scala, à cause du rapprochement avec TypeSafe entre autres. Je ne crois pas trop à cette hypothèse, qui a été démentie plusieurs fois : le succès de Play provient entre autre de la simplicité qu’il a amené aux developpeurs Java et aux entreprises ayant l’habitude de faire des projets en Java. Ca m’etonnerait que Zenexity laisse tomber toute cette tranche d’utilisateurs…
Sinon oui la version 1.x va être maintenue mais bon pour voir arriver de nouvelles fonctionnalités c’est sur qu’il faudra passer à la 2.0.
D’ailleurs pour ceux qui ne seraient toujours pas convaincu par les nouveaux templates de Play 2, des gens bossent sur une nouvelle version du moteur de template groovy de la V1, pour Play 2 : http://kjetland.com/blog/2011/11/playframework-new-faster-groovy-template-engine/