jeudi 25 février 2010

Action AJAX avec Symfony et JQuery

Symfony et moi, c'est une réelle histoire d'amour technologique en ce moment.
Voici pourquoi... Tout est d'une simplicité enfantine et instinctive.
Ainsi pour faire quoi que ce soit, il y a toujours une solution évidente et facile.
Voici le tuto pour appeller une action Symfony en Ajax par JQuery.

Tout d'abord, créons un contexte.
1.L'utilisateur clique sur un bouton.
2.Cela déclenche un évenement JQuery et donc une fonction.
3.Cette fonction envoit des données telle adresse (reliée à une action)
4.L'action éffectue une tache quelconque comme un test de valeur et renvoit la réponse

1.L'utilisateur clique sur un bouton.

Voici un code HTML très simple pour simuler ceci.
<input id="mybutton" type="button" value="Valider">
 2.Cela déclenche un évenement JQuery et donc une fonction.
<input id="mybutton" type="button" onclick="myAjaxFunction()" value="Valider">
 #myJSFile.js

function myAjaxFunction(){}

3.Cette fonction envoit des données telle adresse (reliée à une action)
#myJSFile.js
        function myAjaxFunction(){
            var value = $("#myhiddenvalue").val();
            $.post("myModuleName/myAction",
            {myParam : value},
            function(data)
            {
                $("#mybutton").attr("value",data);
            });
        }
4.L'action éffectue une tache quelconque comme un test de valeur et renvoit la réponse

public function executeIndex(sfWebRequest $request)
 {
    if ($request->isXmlHttpRequest())
    {
        $myValue = $request->getParameter('myParam');
        if($myValue==1)
            $message = "super";
        else
            $message = "bof";
        return $this->renderText($message);
    }
}

Ainsi, le texte du bouton va changer grace à un appel AJAX.
Passez plus de paramètres, renvoyez au lieu d'un texte un fichier _myFileToDisplay.php (renderPartial au lieu de renderText)

exemple : 
return $this->renderPartial('myModuleNamle/myFileToDisplay', array('message' => $message,'hello' => "coucou"));

Pensez que lorsqu'on fait un renderPartial, le fichier doit commencer par underscore, soit ici _myFileToDisplay.php

Bonne chance

Un site grace au Framework Symfony très rapidement !

Symfony 1.4 + Doctrine

Symfony est un framework PHP très puissant. Selon le modèle MVC et intelligement pensé, il va devenir votre allié le plus puissant !

Symfony possède une communauté très développée et très active, ce qui permet de ne toujours trouver quelqu'un pour nous aider à faire ce qu'on veut.

Ce sujet va donc vous montrer comment créer un projet et les modules qui vont avec.

Je recommande l'utilisation de Netbeans 6.8 pour faire du Symfony. En effet, un clic droit sur votre projet vous permettra d'avoir accès à une interface reliée directement au framework ! Un gain de temps et une aide précieuse.

Tout d'abord, vous devez savoir ce que vous voulez faire comme site. En général, on commence par analyser sur une feuille de papier nos attentes et on en déduit notre schéma de données (si vous n'avez pas de schéma de données, je ne penses pas que symfony soit d'une grande aide pour vous...).
Ensuite, créez votre base de données dans phpmyadmin avec les tables qui conviennent.
Entrez quelques données de test puis retournez dans votre IDE (netbeans).
Faites donc un clic droit sur votre projet -> symfony et sélectionnez la tache :
- doctrine:build-schema
ce qui executera symfony doctrine:build-schema
cette commande, comme indiqué dans la fenêtre symfony de Netbeans va générer votre schéma à partir de votre base de données. Vous pouvez retrouver votre schéma dans le dossier /config/doctrine/schema.yml
Si vous voulez que vos tables (et donc vos modèles) soit "timestampable", c'est à dire qu'ils aient de base les champs "created_at" et "updated_at", il faut rajouter ceci à votre schema.yml :
# config/doctrine/schema.yml
myModeleName:
    actAs:
        Timestampable: ~
    columns:
        name:
            type: string(255)
            notnull:  true
Il est très important de respecter les tabulations (indentation) dans un fichier *.yml
Le fait d'ajouter à notre schema ces lignes va donc générer automatiquement les 2 champs "created_at" et "updated_at" :    
 actAs:
        Timestampable: ~
Maintenant, on va exporter les données de test de la base de données dans notre projet. Même processus que tout à l'heure, clique droit sur le projet -> symfony et on cherche désormais la tâche : doctrine:data-dump
Allez jeter un coup d'oeil dans /data/fixtures/data.yml
Vos données sont là, prêtes à être regénérées dans votre base de données dès que vous le voudrez. Lorsque l'on modifie le schéma de données, il faut évidement reconstruire la base de données.
Si on ajoute un champ myField à notre modèle myModeleName
myModeleName:
    actAs:
        Timestampable: ~
    columns:
        name:
            type: string(255)
            notnull:  true
       myField:
            type: int(4)
            notnull:false
 Ajouter ces 3 lignes à notre schéma va donc ajouter un champ.
Voyons si cela génère bien tout ce que l'on veut dans la base grâce à la tache
doctrine:build --all --and-load --no-confirmation
Cette tache va recréer la base de données (build) en se basant sur le schéma de données et va peupler votre base avec les enregistrements dans votre fichier data.yml (--and-load)
L'option --no-confirmation est juste pour ne pas nous demander confirmation lors de l'execution de la requete, on sait ce qu'on fait.

La base est propre et peuplée : OK
Mais cette tache ne s'est pas occupée seulement de cela. Elle a aussi généré les modèles pour chaque table avec les accesseurs getName(), getMyField() etc.
Vous pouvez voir ces fichiers dans /lib/model

Voilà qui est fait en ce qui concerne la partie modèle du concept modèle vue controleur.

Attaquons la partie CONTROLLEUR, les ACTIONS.

Vous l'avez compris, Symfony génère tout ! Il suffit de lui dire quoi faire.

Dans Symfony on distingue 3niveaux : le projet, les applications, les modules.
projet = site
applications = parties générales du site (client/admin)
modules = pages

Pour être vraiment compris, un exemple est mieux que tout :
- un site va en général avoir une application pour le client (frontend) et une application pour l'administration du site (backend). Frontend et backend est le jargon pour les applications. Si vous avez créé votre projet avec Netbeans 6.8 en choisissant l'option Symfony, vous avez déjà du créer l'application frontend.

Sinon, je ne penses pas vous étonner en vous disant qu'il faut aller dans la fenetre de symfony (clique droit sur le projet -> symfony).
Choisissez la tache doctrine:generate:app puis entrez le nom de l'application : frontend.

Voilà l'application crée, on monte d'un niveau et on génère le module.
Clique droit -> Symfony -> doctrine:generate-module
une commande aussi sèche n'a pas d'interet. Il faut lui donner le nom de l'application à laquelle le module va s'ajouter
on ajoute donc frontend puis le nom du module puis le nom du modele
ce qui donne doctrine:generate-module frontend myModuleName myModeleName
Je recommande d'ajouter à cette commande 2 options : --with-show et --non-verbose-templates
Ce qui donne :
doctrine:generate-module --with-show --non-verbose-templates frontend myModuleName myModeleName
Cela génère donc tout ce qu'il faut pour accéder à notre module.
Aussi accédez à votre application en tapant dans la barre d'adresse de votre navigateur http://localhost/myProjectName

 Vous verrez alors que Symfony a généré un CRUD (create, read, update, delete) pour votre module.

C'est plutot puissant mais ce n'est pas encore terrible. C'est moche et ca ne convient pour l'instant que peu.
Allons voir dans /app/frontend/modules/myModuleName
On peut voir deux dossiers : actions et templates
Ce qui se trouve dans le dossier templates seront le coté VUE de votre site alors que dans le dossier actions, ce sera pleinement le controlleur, les actions du site.
Pour l'instant de part et d'autre, nous avons les actions et template pour :
lister les objets (executeIndex et indexSuccess.php)
créer un objet(executeNew et newSuccess.php)
editer un objet (executeEdit et editSuccess.php)
et voir un objet (executeShow et showSuccess.php)

Il suffit de regarder dans le fichier actions.class.php  pour voir comment les actions fonctionnent. C'est très simple, en ce qui concerne l'appel on tape le nom du module/suivi du nom de l'action soit par exemple pour lister myModuleName/index














Le code dedans est typique à Doctrine et est très facile à prendre en main.
La variable $this est l'objet View. On lui affecte des variables comme ceci :
$this->myVar = "my content";
Pour l'utiliser dans la vue, il faut simplement taper $myVar : Rien de plus !

 Attaquons nous à la Vue maintenant !

 On a vu que c'est plutot moche de base. Pas de css, pas d'utilisation du layout.
Voici la procédure pour utiliser le layout : 

C'est le rôle de l'intégrateur, il s'agit de faire le css et de construire le corps des pages. Dans le dossier modules/templates, un fichier s'appelle layout.php. C'est celui-ci qu'il faut modifier et qui sera votre page maitre.

Dedans, vous allez devoir créer l'architecture et montrer ou doit se placer tel contenu relatif à chaque page.

Pour se faire, on utilise la header :


<?php include_slot("mySlotName", "<  my default content"); ?>
           
Ce sont des marqueurs : ici se placera tel élement.

Allons désormais dans la template indexSuccess.php et spécifions quel est tel ou tel contenu.

<php slot('content'); ?>
    mon vrai contenu
<php end_slot(); ?>
C'est ainsi que les master page fonctionne, très simple.

Donc faites votres CSS (exemple à la fin du sujet) et incluez le fichier en ajouter le nom du fichier dans le fichier view.yml de votre application ou de votre module.

Il n'existe pas par défaut dans le module mais si vous créez un dossier config dans votre module, avec un fichier view.yml, vous pouvez spécifier par exemple une feuille de style particulière pour votre module. Cette astuce est valable pour tout type de configuration.




CSS exemple : 

html{
    background: #F1F1F1;
    padding-top:30px;
}
body{
    width: 1024px;
    margin:0 auto;
    background: #89B1F9;
    border: 1px #808080 dashed;
    font-family: arial;
    font-size: 0.7em;
}


#header, #menu, #content, footer {
    text-align: center;
    height: 50px;
}

#header{
    padding: 0px;
    background: #89B1F9;
    height: 215px;
}

h1{
    border-bottom:1px solid #333333;
    color:#333333;
    display:block;
    font-family:Georgia,"Times New Roman",Times,serif;
    font-size:24px;
    font-weight:normal;
    line-height:32px;
    margin:0 0 21px;
    padding:0;
}

.clear{
    clear:both;
}

#content{
    background: #89B1F9;
    height: 100%;
    min-height: 275px;
}

img{
    border: 0px;
}

#footer{
    color: #FF9900;
    text-align: center;
    background: #89B1F9;
    height: 123px;
}

#footer a, #footer a:hover, #footer a:visited{
    padding: 0px 5px 0px 5px;
    color:#FF9900;
    font-weight: bold;
    text-decoration: none;
}

#footer #copyright{
    margin-top: 80px;
    font-size: 0.8em;
    color : #999999;
    text-transform: uppercase;
}

.even, .odd{
    cursor: pointer;
    background-color: #89BAF9;
    padding: 5px;
}

.odd{
    background-color: #BACDFA;
}