BackBone Models & Play!> Models jouent ensemble
Objectifs :
Nous allons voir comment faire discuter des modĂšles Backbone avec des modĂšles Play!> (version 1) et persister les donnĂ©es client cĂŽtĂ© serveur. Câest simple, mais concentrez vous quand mĂȘme.
Prérequis :
- avoir installé Playframework : http://www.playframework.org/
- Télécharger Backbone : http://documentcloud.github.com/backbone/
- TĂ©lĂ©charger Underscore : http://documentcloud.github.com/underscore/ (câest une dĂ©pendance de Backbone.js)
- TĂ©lĂ©charger la derniĂšre version de jQuery (optionnel) : http://jquery.com/ (câest aussi une dĂ©pendance de Backbone.js, mais cela fonctionnerait aussi avec Zepto)
- Utiliser un navigateur âĂ baseâ de Webkit (Chrome, Safari) ou Firefox : il faut une console digne de ce nom pour suivre ce tuto.
Préparation :
Tout dâabord, il faut crĂ©er une application Play. Donc positionnez vous dans un rĂ©pertoire et tapez la commande suivante :
play new bookmarks
Cela va donc créer un répertoire bookmarks
.
Aller dans public/javascripts
et copier dans le répertoire :
- jquery.js
- underscore.js
- backbone.js
Ensuite, aller dans app/views/main.html
et changer les includes javascript :
<script src="@{'/public/javascripts/jquery.js'}" type="text/javascript" charset="${_response_encoding}"></script>
<script src="@{'/public/javascripts/underscore.js'}" type="text/javascript" charset="${_response_encoding}"></script>
<script src="@{'/public/javascripts/backbone.js'}" type="text/javascript" charset="${_response_encoding}"></script>
Câest bon, vous ĂȘtes prĂȘts. On commence.
CrĂ©ation dâun modĂšle et dâune collection BackBone :
Aller dans app/views/Application
, et modifier index.html
:
# {extends 'main.html' /}
# {set title:'Home' /}
<script type="text/javascript">
window.Bookmark = Backbone.Model.extend({
url : 'bb/bookmark',
defaults : {
id: null,
label : "",
website : ""
}
});
window.Bookmarks = Backbone.Collection.extend({
model : Bookmark,
url : 'bb/bookmarks'
});
</script>
Un modÚle Backbone possÚde plusieurs méthodes. Nous allons nous concentrer sur celles-ci :
save()
destroy()
fetch()
et en ce qui concerne la collection Backbone :
fetch()
Lorsque ces mĂ©thodes sont appelĂ©es, câest lâobjet Backbone.sync
qui est appelĂ©/utilisĂ© et se charge de faire des requĂȘtes au serveur si la propriĂ©tĂ© url
des modÚles et collections est renseignée. Donc dans notre cas (et nous allons le vérifier plus loin), Backbone.sync
enverra les requĂȘtes de ce type au serveur :
POST
ouPUT
poursave()
DELETE
pourdestroy()
GET
pourfetch()
Un petit tour cÎté Play!>
Nous allons donc crĂ©er les mĂ©thodes qui rĂ©pondrons aux requĂȘtes de Backbone.sync
.
Aller dans le fichier conf/routes
et ajouter les routes suivantes :
GET /bb/bookmark Application.getBookmark
POST /bb/bookmark Application.postBookmark
PUT /bb/bookmark Application.putBookmark
DELETE /bb/bookmark Application.deleteBookmark
GET /bb/bookmarks Application.allBookmarks
Aller ensuite dans controllers/Application.java
et ajouter les méthodes suivantes :
public class Application extends Controller {
public static void index() {
render();
}
/* GET */
public static void getBookmark(String model) {
System.out.println("getBookmark : "+model);
}
/* POST */
public static void postBookmark(String model) {
System.out.println("postBookmark : "+model);
}
/* PUT */
public static void putBookmark(String model) {
System.out.println("putBookmark : "+model);
}
/* DELETE */
public static void deleteBookmark(String model) {
System.out.println("deleteBookmark : "+model);
}
/* GET */
public static void allBookmarks() {
System.out.println("allBookmarks");
}
}
1er essai :
- Lancez lâapplication Bookmarks :
play run bookmarks
- se connecter Ă lâapplication : http://localhost:9000/
- ouvrir la console du navigateur
-
tapez les commandes suivantes :
b1 = new Bookmark({label:"K33g'sBlog",website:"www.k33g.org"}); b1.save(); //pas mis de callback pour le moment
Console du navigateur :
Console du terminal (cÎté Play) :
Et lĂ câest le drame !
on sâaperçoit que câest la mĂ©thode postBookmark qui est appelĂ©e, mais par contre rien (null
en fait) nâest retournĂ© dans la console serveur. En fait Backbone nâenvoie pas ce que lâon souhaite Ă la mĂ©thode Play!> (en fait Play attend une chaĂźne JSON qui contienne une variable de mĂȘme nom que le paramĂštre des mĂ©thodes du contrĂŽleur).
MĂȘme pas mal !. Nous allons donc re-Ă©crire/surcharger Backbone.sync
. ⊠Et on va faire simple.
Surcharge de Backbone.sync :
Dans public/javascripts, créer un nouveau fichier : backbone.sync.js
:
(function() {
Backbone.sync = function(method, model, options) {
// sympa pour comprendre ce qu'il se passe
console.log(method, model, options);
var methodMap = {
'create': 'POST',
'update': 'PUT',
'delete': 'DELETE',
'read': 'GET'
}, dataForServer = null;
if(model.models) {//c'est une collection
dataForTheServer:null
} else {//c'est un modĂšle
dataForServer = { model : JSON.stringify(model.toJSON()) }; // Remarquez l'utilisation de "model"
}
return $.ajax({
type: methodMap[method],
url: model.url,
data: dataForServer,
dataType: 'json',
error: function (dataFromServer) { //vérifier que cela retourne une erreur
options.error(dataFromServer);
},
success: function (dataFromServer) {
options.success(dataFromServer);
}
});
};
})();
!!! Vous remarquerez lâutilisation de âmodelâ dans la chaĂźne JSON envoyĂ©e au serveur, comme le nom du paramĂštre des mĂ©thodes du contrĂŽleur java.
Ensuite, aller dans app/views/main.html
et inclure le nouveau fichier js Ă la suite des autres :
<script src="@{'/public/javascripts/backbone.sync.js'}" type="text/javascript" charset="${_response_encoding}"></sc
PrĂȘts pour un 2Ăšme essai ? âPlaying with BB Modelsâ
Rechargez tout dâabord la page de votre navigateur pour prendre les modifications en compte. Puis passez aux Ă©tapes suivantes ci-dessous :
save()
Dans la console du navigateur tapez les commandes suivantes :
b1 = new Bookmark({label:"K33g'sBlog",website:"www.k33g.org"});
b1.save();
Dans la console Play!>, on obtient :
postBookmark : {"id":null,"label":"K33g'sBlog","website":"www.k33g.org"}
Donc lorsque lâon sauvegarde un modĂšle BB câest une requĂȘte POST
qui est envoyée et la méthode postBookmark
qui est appelée.
Console du navigateur :
Au passage on peut voir dans la console que la méthode est de type create
Console du terminal (cÎté Play) :
save() again
Dans la console du navigateur tapez les commandes suivantes :
b1.set({id:1});
b1.save();
Dans la console Play!>, on obtient :
putBookmark : {"id":1,"label":"K33g'sBlog","website":"www.k33g.org"}
Donc lorsque lâon sauvegarde un modĂšle BB câest une requĂȘte PUT
qui est envoyée et la méthode putBookmark
qui est appelée.
On a affecté un id
au modĂšle, donc BB âestimeâ que le modĂšle existe, et donc que câest une mise Ă jour.
Console du navigateur :
Au passage on peut voir dans la console que la méthode est de type update
Console du terminal (cÎté Play) :
destroy()
Dans la console du navigateur tapez les commandes suivantes :
b1.destroy(); // b1.id = 1 sinon faire b1.set({id:1});
Dans la console Play!>, on obtient :
deleteBookmark : {"id":1,"label":"K33g'sBlog","website":"www.k33g.org"}
Donc lorsque lâon dĂ©truit un modĂšle BB câest une requĂȘte DELETE
qui est envoyée et la méthode deleteBookmark
qui est appelée.
fetch()
Dans la console du navigateur tapez les commandes suivantes :
b1.fetch(); // b1.id = 1 sinon faire b1.set({id:1});
Dans la console Play!>, on obtient :
getBookmark : {"id":1,"label":"K33g'sBlog","website":"www.k33g.org"}
Donc lorsque lâon utilise la mĂ©thode fetch() dâun modĂšle BB câest une requĂȘte GET
qui est envoyée et la méthode getBookmark
qui est appelée.
Bilan des courses :
Nous avons tout ce quâil faut cĂŽtĂ© Backbone pour passer les bonnes informations Ă Play!>. Nous passerons aux Backbone.Collection(s)
plus tard. Pour le moment nous allons coder le âpendantâ Java de notre modĂšle Backbone, afin de pouvoir effectuer des actions en base de donnĂ©es.
Créer un modÚle Bookmark.java
Allez dans app/models
et créez une classe Bookmark.java
:
package models;
import javax.persistence.Entity;
import play.data.validation.Required;
import play.db.jpa.Model;
@Entity
public class Bookmark extends Model {
@Required public String label;
@Required public String website;
public Bookmark(String label, String website) {
this.label = label;
this.website = website;
}
public Bookmark() {
}
@Override
public String toString() {
return label;
}
}
Puis allons modifier les méthodes du contrÎleur Application.java
:
package controllers;
import play.mvc.*;
import java.util.*;
import models.*;
import com.google.gson.Gson;
public class Application extends Controller {
public static void index() {
render();
}
/* GET */
public static void getBookmark(String model) {
System.out.println("getBookmark : "+model);
Gson gson = new Gson();
Bookmark bookmark = gson.fromJson(model,Bookmark.class);
Bookmark forFetchBookmark = Bookmark.findById(bookmark.id);
//tester if found ...
renderJSON(forFetchBookmark);
}
/* POST (CREATE) */
public static void postBookmark(String model) {
System.out.println("postBookmark : "+model);
Gson gson = new Gson();
Bookmark bookmark = gson.fromJson(model,Bookmark.class);
bookmark.save();
renderJSON(bookmark);
}
/* PUT (UPDATE) */
public static void putBookmark(String model) {
System.out.println("putBookmark : "+model);
Gson gson = new Gson();
Bookmark bookmark = gson.fromJson(model,Bookmark.class);
Bookmark updatedBookmark = Bookmark.findById(bookmark.id);
updatedBookmark.label = bookmark.label;
updatedBookmark.save();
renderJSON(updatedBookmark);
}
/* DELETE */
public static void deleteBookmark(String model) {
System.out.println("deleteBookmark : "+model);
Gson gson = new Gson();
Bookmark bookmark = gson.fromJson(model,Bookmark.class);
Bookmark bookmarkToBeDeleted = Bookmark.findById(bookmark.id);
//tester if found ...
bookmarkToBeDeleted.delete();
renderJSON(bookmarkToBeDeleted);
}
/* GET */
public static void allBookmarks() {
System.out.println("allBookmarks");
List<Bookmark> bookmarks = Bookmark.findAll();
renderJSON(new Gson().toJson(bookmarks));
}
}
Notez bien : les imports com.google.gson.*
qui nous permettent de âtraduireâ le JSON.
Ne pas oublier : allez dans le fichier conf/application.conf
et dans la rubrique Database configuration
ajouter la ligne db=fs
. (normal, on va utiliser la base de données)
ArrĂȘtez & relancez lâapplication (ça ne peut pas faire de mal).
Rechargez tout dâabord la page de votre navigateur pour remettre âĂ zĂ©roâ les variables/objets/modĂšles javascript (Backbone) et relancer la compilation des classes cĂŽtĂ© Play!>.
save()
Dans la console du navigateur tapez les commandes suivantes :
b1 = new Bookmark({label:"K33g'sBlog",website:"www.k33g.org"});
b1.save();
Attendez un petit peu (je nâai pas mis de callback pour attendre la rĂ©ponse du serveur). Vous voyerz une ligne Objet
dans la console, en fait câest la rĂ©ponse de Play!> qui a renvoyĂ© un objet de type JSON.
Si vous tapez la commande : b1.get("id")
vous obtenez 1
. Câest Play!> qui lors de la sauvegarde a affectĂ© un id automatiquement Ă lâobjet JSON renvoyĂ©, et Backbone qui a mappĂ© le rĂ©sultat sur son modĂšle b1.
On vérifie ?
save again()
Dans un 1er temps, on change une valeur dâune propriĂ©tĂ© de notre modĂšle et on sauve Ă nouveau :
b1.set({label:"Le blog de K33G"})
b1.save();
On voit bien que cette fois ci, câest un update, si vous surveillez votre terminal vous pouvez vĂ©rifier que câest bien la mĂ©thode putBookmark
qui a été appelée avec le changement de label
qui est pris en compte.
Oui mais est-ce que ça a bien enregistrĂ© mes donnĂ©es en base ? Allons vĂ©rifier âŠ
fetch()
Rechargez une nouvelle fois la page de votre navigateur pour remettre âĂ zĂ©roâ les variables/objets/modĂšles javascript (Backbone). Puis tapez les commandes suivantes :
b1 = new Bookmark({id:1})
b1.fetch()
Une fois que le serveur a répondu, vous pouvez vérifier que vous avez bien récupéré vos données :
b1.get("label")
Donc, nos données ont bien été enregistrées en base.
On ajoute quelques modĂšles avant de passer aux collections :
b2 = new Bookmark({label:"Coffee Bean",website:"http://coffeebean.loicdescotte.com/"});
b3 = new Bookmark({label:"blog.mklog",website:"http://blog.mklog.fr/"});
b4 = new Bookmark({label:"LyonJS",website:"http://lyonjs.org/"});
b2.save();
b3.save();
b4.save();
Passons donc aux collections
Rechargez une nouvelle fois la page de votre navigateur pour remettre âĂ zĂ©roâ les variables/objets/modĂšles javascript (Backbone). Puis tapez les commandes suivantes :
bookmarksCollection = new Bookmarks()
bookmarksCollection.fetch()
Une fois que le serveur a répondu :
bookmarksCollection.models
bookmarksCollection.models.forEach(function(model){ console.log(model.get("label")); })
On a bien retrouvĂ© nos donnĂ©es :) et finalement ce nâest pas si compliquĂ© que ça.
Derniers coups de tournevis pour la route
câest mieux dâutilise des callbacks lorsque lâon fait des appels aux serveurs (ben oui on bosse en mode asynchrone) :
Par exemple pour un save()
b = new Bookmark({label:"Google", website:"www.google.fr"})
b.save({},
{
success:function(data){ console.log("Gagné : ", data); },
error : function() { console.log("Oups! y'a un blem"); }
})
Ou pour un fetch()
bookmarksCollection.fetch({
success:function(data){
console.log("Gagné : ");
bookmarksCollection.models.forEach(function(model){ console.log(model.get("label")); })
},
error : function() { console.log("Oups! y'a un blem"); }
})
VoilĂ , câest fini pour aujourdâhui.
Bon je vous laisse dĂ©jĂ bricoler avec ça, et dans un prochain article, nous irons un peu plus loin : comment gĂšre-t-on les relations ? (par exemple, on associe un thĂšme ou une technologie Ă un bookmark). Et plus tard, je tenterais la mĂȘme chose avec Play!> version 2.
Tweet