====== Création de Modules Génériques "Jelix" (partie 2/2) ====== //(version de Jelix supportée 1.1.x)// Voici la seconde partie, de l'article [[fr:tutoriels:modules:generic1|Création de module génériques (1/2)]]. Le premier article détaillait le moyen d'ajouter facilement des Tags à ses discussions, lors de la création/modification d'une discussion. Ici, je dispose d'une page listant des discussions et j'ai envi que les visiteurs/membres du site puissent donner une appréciation (via une note) sur le contenu de ce qu'ils lisent. Ce article repose sur [[https://bitbucket.org/foxmask/havefnubb/src/tip/havefnubb/modules/hfnurates/|le code du module HfnuRates de l'application HaveFnuBB]] **Rappel** * j'appelle module "générique" le module offrant un service ; * j'appelle module "utilisateur" le module exploitant ledit service. **Aparté** Une fois un formulaire enregistré, l'utilisateur est redirigé sur la page présentant la discussion ajoutée. C'est classique ! Classique oui, mais cela est possible car tout est traité par le même module qui "sait" d'où vient l'utilisateur et où l'envoyer. **La difficulté qui se pose ici est** : je suis sur une page présentant la liste des discussions (d'un module forum), et à l'intérieure de celle-ci j'''utilise un autre module'' (HfnuRates) ''qui ne sait pas où renvoyer l'utilisateur'' une fois les données soumises. On utilisera donc une astuce pour y remédier. **Fin Aparté ** ===== SECOND VOLET : HfnuRates ===== ==== INGREDIENTS ==== - une zone - une table (et dao) - une classe métier - un contrôleur J'ouvre donc le template de ma page discussions et ajoute ce qui suit où bon me semble : {zone 'hfnurates~rates', array('id_source'=>$id_posts' 'source'=>'posts', 'return_url'=>'havefnubb~posts:list', 'return_url_param'=>array('id_posts'=>$id_posts)) } * Q1 : {zone ...} sert à quoi ? * R1 : la zone permet d'ajouter des portions de page à l'intérieure d'une autre. * Q2 : à quoi sert array() ? * R2 : l'array ici permet de fournir à la zone, des paramètres, qui sont dans notre présent cas : * @@A@'id_source'@@ = l'id de la table du module "utilisateur" * @@A@'source'@@ = une chaine permettant d'identifier la provenance des données * @@A@return_url@@ qui contient le chemin "jelix" du module "utilisateur" * @@A@return_url_param@@contient des params nécessaires pour retourner au module "utilisateur" * Q3 : Pourquoi tous ces paramètres ? * R3 : Comme évoqué en aparté, HfnuRates n'est pas en mesure de savoir où renvoyer l'utilisateur une fois les données transmises. Donc, dans le template du module "forum", on ajoutera les paramètres de "provenance" pour qu'ensuite le module HfnuRates puisse renvoyer l'utilisateur sur la page d'où il venait ! ==== LA ZONE ==== Dans la zone je récupère donc les paramètres passés, pour les assigner dans le template de la zone 'zone.rates'. Toujours dans la zone, j'en profite pour récupérer les "notes" pour cette discussion et calculer la moyenne et l'afficher dans la zone 'zone.rates' **zone ratesZone** class ratesZone extends jZone { protected $_tplname='zone.rates'; protected function _prepareTpl(){ //get the params $id_source = $this->intParam('id_source'); $source = $this->param('source'); $return_url = $this->param('return_url'); $return_url_params = $this->param('return_url_params'); // get the rates from the class $rates = jClasses::getService('hfnurates~rates'); $result = $rates->getTotalRatesBySource($id_source,$source); $resultText = jLocale::get('hfnurates~main.total.of.rates') . ':'.$result->total_rates . ' ' . jLocale::get('hfnurates~main.rate') .':'. $result->avg_level; //let's assign the var to the template $this->_tpl->assign('id_source',$id_source); $this->_tpl->assign('source',$source); $this->_tpl->assign('result',$resultText); $this->_tpl->assign('return_url',$return_url); $this->_tpl->assign('return_url_params',$return_url_params); } } ==== LE TEMPLATE zone.rates ==== le template de la zone ressemble à ceci :
{$result}
{foreach $return_url_params as $key => $value} {/foreach} [...ici le code HTML affichant le radiobutton "star1"... ]
on verra plus bas que la méthode rate_it du controleur default du module hfnurates exploitera les parms return_url* pour renvoyer l'utilisateur sur la bonne page. ==== LA TABLE ==== La table du module "générique", ici HfnuRates doit stocker les données le reliant au module "utilisateur", ici "forum" : CREATE TABLE `hf_rates` ( `id_user` INT NOT NULL , `id_source` INT NOT NULL , `source` VARCHAR(40) NOT NULL, `ip` VARCHAR(80) NOT NULL, level FLOAT NOT NULL , INDEX ( `id_user` ), INDEX ( `id_source` ), INDEX ( `source` ), PRIMARY KEY rates_id (id_user,id_source,source) ); la colonne "id_source" contiendra l'id de la discussion, et "source", la chaine "posts". Le reste de la table est spécifique au module HfnuRates et la clé primaire permet à un même utilisateur de mettre à jour sa note si bon lui semble. ==== LA CLASSE ==== class rates { // get the Rate of a given source and ID function getTotalRatesBySource($id_source, $source) { $cnx = jDb::getConnection(); $strQuery = 'SELECT COUNT(*) as total_rates, SUM(level) as total_level, AVG(level) as avg_level ' . ' FROM '.$cnx->prefixTable('rates'). " WHERE id_source = '".$id_source."' AND source='".addslashes($source). "' GROUP BY id_source"; $rs = $cnx->query($strQuery); $total = $rs->fetch(); return $total; } // save the Rate to a given source and ID function saveRatesBySource($id_source, $source, $rate) { [...] } } ==== LE CONTROLEUR ==== class defaultCtrl extends jController { function rate_it() { //info about the "source" from where the datas come from $id_source = $this->Intaram('id_source'); $source = (string) $this->param('source'); // the star $rate = $this->floatParam('star1'); $rates = jClasses::getService('hfnurates~rates'); $result = $rates->saveRatesBySource($id_source,$source,$rate); $rep = $this->getResponse('redirect'); $rep->action= (string) $this->param('return_url'); $rep->params= (array) $this->param('return_url_params'); return $rep; } function rate_ajax_it() { //info about the "source" from where the datas come from $id_source = $this->intParam('id_source'); $source = (string) $this->param('source'); //check if the cancel button was selected if ($id_source == 0 or $source == '') return; $rate = $this->floatParam('star1'); $rates = jClasses::getService('hfnurates~rates'); $rates->saveRatesBySource($id_source,$source,$rate); $result = $rates->getTotalRatesBySource($id_source,$source); // used for Ajax response $rep = $this->getResponse('htmlfragment'); $rep->addContent( jLocale::get('hfnurates~main.total.of.rates').':'.$result->total_rates . ' ' . jLocale::get('hfnurates~main.rate') .':'. $result->avg_level ); return $rep; } } * La première méthode traite la soumission des données quand le Javascript n'est pas activé * La seconde méthode traite la soumission des données quand le Javascript est pas activé et utilise Ajax ===== Conclusion ===== Pour obtenir un module, on ne peut plus générique, la zone est l'arme absolue puisqu'elle embarque toute la mécanique nécessaire aux échanges entre les modules concernés. Pour résumer ce qu'il faut pour qu'un module qui soit ré-exploitable à souhait : * une table avec 2 colonnes pour mémoriser la provenance des données du module "utilisateur" * une classe métier pour gérer ces données * une zone et son template. * et enfin placer {zone 'module~nomzone', array('id_source'=>$id,'source'=>'masource',...) } dans le template du module "utilisateur" Revenir sur [[fr:tutoriels:modules:generic1|Création de module génériques (1/2)]]