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 :

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 ou PUT pour save()
  • DELETE pour destroy()
  • GET pour fetch()

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 :

Alt "bbplay001.png"

Console du terminal (cÎté Play) :

Alt "bbplay002.png"

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 :

Alt "bbplay003.png"

Au passage on peut voir dans la console que la méthode est de type create

Console du terminal (cÎté Play) :

Alt "bbplay004.png"

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 :

Alt "bbplay005.png"

Au passage on peut voir dans la console que la méthode est de type update

Console du terminal (cÎté Play) :

Alt "bbplay006.png"

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.

Alt "bbplay007.png"

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();

Alt "bbplay008.png"

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")

Alt "bbplay009.png"

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")); })

Alt "bbplay010.png"

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.

blog comments powered by Disqus

Related posts