Raccourcis : Contenu - rubriques - sous rubriques
EN FR
La page correspondant à la dernière version stable est consultable dans le Manuel Jelix 1.5

Il y a plusieurs types de traitements : les traitements métiers, et ceux dédiés à la génération de la page web. Pour les traitements métiers, vous utiliserez des classes métiers, des classes services, des daos. Celles-ci pouvant être utilisable par tous les modules, c'est un premier moyen de réaliser des traitements métiers qui puissent être réutilisables. Voir /classes-metiers.

Pour ce qui concerne la génération d'une page, c'est un peu plus complexe que ça car il y a plusieurs façons de faire. Nous sommes donc devant le cas suivant : nous avons plusieurs pages qui ont des parties communes. Cela peut être par exemple un bandeau, un pied de page, un menu sur le coté etc.. Il peut y avoir aussi quelques pages qui ont un peu plus que ça en commun. Voici diverses solutions selon le contexte.

  • Utilisation de méthodes privées de contrôleurs
  • Héritage de contrôleurs
  • Utilisation d'une réponse commune
  • Utilisation de zones

Méthodes privées de contrôleurs

Si la similitude des pages se résume à quelques actions qui sont dans un même contrôleur, alors vous pouvez utiliser une méthode privée/protégée, qui va faire le travail commun à toutes ces actions.



class defaultCtrl extends jController {

   protected function common(){
      $rep = $this->getResponse('html');
      $rep->title = 'Même titre pour tout le monde';
      $rep->body->assign('menu', '<ul><li>item 1</li><li>item 2</li></ul>');
      return $rep;   
   }


   function index(){
      $rep = $this->common();
      $rep->body->assign('MAIN','<p>Bienvenue sur cette application de test</p>');
      return $rep;
   }

   function liste(){
      $rep = $this->common();
      $rep->body->assign('MAIN','<ul><li>une</li><li>liste</li></ul>');
      return $rep;
   }


}

Dans cette exemple, les deux actions index et liste font appel à une méthode commune qui va réaliser le travail commun.

Héritage de contrôleurs

Si plusieurs actions de plusieurs contrôleurs ont des traitements en commun, alors vous pouvez utiliser le mécanisme d'héritage objet. C'est à dire réaliser un contrôleur de base, qui ne sera pas utilisé directement, mais dont hériteront les contrôleurs concernés.

Voici un exemple de contrôleur de base, dans le fichier controllers/myBaseController.php :


class myBaseController extends jController {

   protected function common(){
      $rep = $this->getResponse('html');
      $rep->title = 'Même titre pour tout le monde';
      $rep->body->assign('menu', '<ul><li>item 1</li><li>item 2</li></ul>');
      return $rep;   
   }

}

Et dans vos contrôleurs :


global $gJCoord;
include $gJCoord->getModulePath('monModule').'controllers/myBaseController.php';

class defaultCtrl extends myBaseController {
   
   function index(){
      $rep = $this->common();
      $rep->body->assign('MAIN','<p>Bienvenue sur cette application de test</p>');
      return $rep;
   }

   function liste(){
      $rep = $this->common();
      $rep->body->assign('MAIN','<ul><li>une</li><li>liste</li></ul>');
      return $rep;
   }


}

Notez l'include et le extends myBaseController;

Bien sûr, le contrôleur de base peut contenir des propriétés, d'autres méthodes, voir même des méthodes d'actions. C'est à dire que vous pouvez ainsi avoir plusieurs contrôleurs qui possèdent au final des actions communes (qui peuvent elle-même tenir compte de propriétés ou d'autres méthodes pour gérer des différences).

Vous pouvez faire par exemple un contrôleur de base, qui définit une série d'actions : liste, creation, modification, suppression. Ces actions se basant sur des propriétés pour savoir les daos et les templates à utiliser. Ainsi, il est aisé de réaliser plusieurs contrôleurs, héritant de ce contrôleur de base, et n'ayant plus qu'à indiquer dans des propriétés les daos et les templates. De quoi ainsi se faire une administration basique assez rapidement.

Personnalisation de réponse commune

Les deux solutions précédentes sont intéressantes pour des cas peu courants, ou du moins, pas généraux à l'application. Si vous avez des choses en commun pour la majorité des actions, il est préférable de faire autrement : surcharger un objet réponse.

Vous créerez cet objet response de façon à ce que ce soit lui qui fasse le travail commun à toutes les actions. Imaginons par exemple que toutes les pages HTML de votre site ait le même menu dynamique, la même feuille de style etc.. Vous créerez donc une classe response comme il est indiqué dans générer un contenu personnalisé, et qui effectuera ce travail.

Si vous voulez réaliser des modules réutilisables, cette façon de faire est d'autant plus intéressante puisqu'alors tout ce qui ne concerne pas le module est réalisé à l'extérieur de ce module. Il est donc plus indépendant de l'application, contrairement au cas où il gère lui même dans ses actions les parties communes des pages du site (bandeau etc...).

Vos propres classes de réponses peuvent hériter de jResponseHtml par exemple. Dans cette classe, vous pouvez alors :

  • surcharger le constructeur pour réaliser des choses qui seront fait lorsque vous ferez le getResponse dans votre contrôleur
  • surcharger la méthode _commonProcess. Notez que cette méthode n'existe que pour jResponseHtml. Elle sera appelée aprés votre action, et juste avant l'affichage définitif.

Voyons plus précisément comment ça se gère globalement. Vous avez donc vos pages HTML, qui contiennent la partie <head> et la partie <body> :

Vous aurez un template principal qui s'occupe de générer l'ensemble du contenu de <body>, et ce template va être déclaré au niveau de votre propre objet response. Voici par exemple votre objet responses/myHtmlResponse.class.php :


require_once (JELIX_LIB_RESPONSE_PATH.'jResponseHtml.class.php');

class myHtmlResponse extends jResponseHtml {

   public $bodyTpl = 'myapp~main';

   protected function _commonProcess(){

   }
}

Votre page est en général découpé en zone :

Ainsi le template pourrait ressembler à ceci


<div id="header"> ...    {$date} </div>
<div id="sidebar-left"> {$A}  {$B}  {$C} </div>
<div id="sidebar-right"> {$D} </div>

<div id="main-content"> {$MAIN} </div>

<div id="footer"> ...</div>

Ces zones A, B, C, D et MAIN peuvent être générées par des sous-templates ou des objets jZone, materialisés ici par des parties distinctes :

En particulier, la partie MAIN sera générée par un template que les actions fourniront.

Ainsi l'objet réponse pourra s'occuper par exemple de la partie A (si celle-ci est commune à toutes les pages), et les autres zones seront remplies à loisir par les actions. Dans l'objet réponse on aura donc :


require_once (JELIX_LIB_RESPONSE_PATH.'jResponseHtml.class.php');

class myHtmlResponse extends jResponseHtml {

   public $bodyTpl = 'myapp~main';

   protected function _commonProcess(){
        // toutes les pages auront une zone de login affichée
        $this->body->assignZone("A", "auth~login");

        // et au cas où rien n'est défini pour B,C,D et MAIN, on met du contenu
        // par défaut
        $this->body->assignIfNone('B','');
        $this->body->assignIfNone('C','');
        $this->body->assignIfNone('D','');
        $this->body->assignIfNone('MAIN','<p>No content</p>');

        // on indique les autres variables 
        $this->body->assign('date', date('Y-m-d'));
   }
}

Dans les actions (contrôleurs), on fera donc des choses comme :


    function mon_action() {
        $rep = $this->getResponse('html');
        // on indique du contenu pour B
        $rep->assign('B','<h2>Hello !</h2>');

        // on indique du contenu pour D
        $rep->assignZone('D', 'ma_sidebar');

        // Pas de contenu pour C, donc on ne fait rien pour C

        // on s'occupe maintenant de la partie principal
        // qui a son propre template
        $tplMain = new jtpl();
        $tplMain->assign(...); 
        $rep->assign('MAIN', $tplMain->fetch('monmodule~montpl'));
        
        return $rep;
    }

Bien sûr, la réponse peut définir aussi autre chose que le template : feuille de styles et cie. Ce qui évite de le faire dans les actions. Exemple, en surchargeant le constructeur :


class myHtmlResponse extends jResponseHtml {

   public $bodyTpl = 'myapp~main';

   // traitement executé AVANT les actions
   public function __construct() {
        parent::__construct();
        $this->addCSSLink('design/screen.css');
   }

   // traitement executé APRES les actions
   protected function doAfterActions(){

        $this->title .= ($this->title !=''?' - ':'').' My App';

        // toutes les pages auront une zone de login affichée
        $this->body->assignZone("A", "auth~login");

        // et au cas où rien n'est défini pour B,C,D et MAIN, on met du contenu
        // par défaut
        $this->body->assignIfNone('B','');
        $this->body->assignIfNone('C','');
        $this->body->assignIfNone('D','');
        $this->body->assignIfNone('MAIN','<p>No content</p>');

        // on indique les autres variables 
        $this->body->assign('date', date('Y-m-d'));
   }
}

Déclaration de l'objet response

Cet objet response est déclaré comme ceci dans la configuration :


[responses]
html=myHtmlResponse

Toutes les actions qui feront alors appel à la réponse "html", fourniront un objet myHtmlResponse, et donc une page avec un formulaire de login généré par la zone 'auth~login', un contenu par défaut pour les variables de templates MAIN, A, B etc (si elles n'ont pas été définies par l'action).

Astuces utiles

Lorsque vous définissez une réponse personnalisée, il peut être utile de récupérer certaines valeurs de votre application, comme

  • le theme: $GLOBALS['gJConfig']->theme
  • les paramètres de la requête: $GLOBALS['gJCoord']->request->getParam(..)

Ci-dessous un exemple



   public function __construct() {
        parent::__construct();
        $theme = $GLOBALS['gJConfig']->urlengine['basePath'].'themes/'.$GLOBALS['gJConfig']->theme.'/' ;
        $this->addCSSLink($theme.'css/screen.css');
   }

   protected function _commonProcess(){

        $this->title .= ($this->title !=''?' - ':'').' My App';

        $param = $GLOBALS['gJCoord']->request->getParam('paramSommaire')

        // toutes les pages auront une zone de login affichée
        $this->body->assignZone("A", "auth~login", array( 'paramSommaire' => $param ) );

        // et au cas où rien n'est défini pour B,C,D et MAIN, on met du contenu
        // par défaut
        $this->body->assignIfNone('B','');
        $this->body->assignIfNone('C','');
        $this->body->assignIfNone('D','');
        $this->body->assignIfNone('MAIN','<p>No content</p>');

        // on indique les autres variables 
        $this->body->assign('date', date('Y-m-d'));
   }

Définir plusieurs réponses

Notez que vous pouvez définir plusieurs réponses html, dans le cas où votre site comporte plusieurs pages type. Par exemple :


[responses]
html=myHtmlResponse
html2=myOtherHtmlResponse
adm=adminHtmlresponse

Il suffira alors dans les actions d'indiquer le bon code pour indiquer le type de réponse :


  $rep = $this->getResponse('html');
  // ou
  $rep = $this->getResponse('html2');
  // ou
  $rep = $this->getResponse('adm');

Utiliser ponctuellement une réponse d'origine

Si dans une action, vous voulez absolument utiliser la classe d'origine fourni par Jelix, et non celle qui redéfinit un type de réponse, vous pouvez alors l'indiquer en indiquant true en deuxième paramètre de getResponse :


 $rep = $this->getResponse('html', true);

$rep contiendra un objet de type jResponseHtml, et non myHtmlResponse.

Utilisation de zones

Il se peut qu'un ensemble de page possède une ou plusieurs zones identiques, sans que cela soit général à tout le site. Vous pouvez alors créer des zones.