Raccourcis : Contenu - rubriques - sous rubriques
EN FR

Il est fort probable que vous ayez dans la plupart de vos actions, à initialiser la même feuille de style, les mêmes zones de menus, et autres traitements de personnalisation de la réponse. Plutôt que de répéter toutes ces opérations dans chaque contrôleur, vous allez créer un objet response qui fait le travail commun à toutes les actions.

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

Dans cette section, nous allons parler principalement de la création d'un objet réponse héritant d'un autre objet réponse "évolué" existant. Si vous voulez créer un objet réponse pour un nouveau type de format, voir le chapitre sur la génération d'un contenu dans un format spécifique.

Créer un objet réponse à partir d'une classe existante

Vos propres classes de réponses peuvent hériter de jResponseHtml par exemple (mais ça pourrait bien sûr être une autre classe jResponse* fournie par Jelix). D'ailleurs, par défaut, quand vous créez une application avec jelix-scripts, un tel objet est déjà créé, myHtmlResponse, qui hérite de jResponseHtml et est stocké dans le répertoire responses/ de l'application.

Dans cette classe, vous pouvez alors :

  • surcharger le constructeur pour réaliser des choses qui seront faites lorsque vous ferez le getResponse() dans votre contrôleur
  • surcharger la méthode doAfterActions(). 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 réponse. Voici par exemple votre objet responses/myHtmlResponse.class.php :


require_once (JELIX_LIB_CORE_PATH.'response/jResponseHtml.class.php');

class myHtmlResponse extends jResponseHtml {

   public $bodyTpl = 'myapp~main';

   protected function doAfterActions(){

   }
}

Votre page est en général découpée en zones :

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, matérialisés ici par des parties distinctes :

En particulier, la partie MAIN sera générée par les actions, en utilisant un template, une zone ou autre.

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_CORE_PATH.'response/jResponseHtml.class.php');

class myHtmlResponse extends jResponseHtml {

   public $bodyTpl = 'myapp~main';

   protected function doAfterActions(){
        // 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->body->assign('B','<h2>Hello !</h2>');

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

        // Dans cette action, pas de contenu pour C, 
        // donc on ne fait rien pour C

        // on s'occupe maintenant de la partie principale
        // qui a son propre template
        $tplMain = new jtpl();
        $tplMain->assign(...); 
        $rep->body->assign('MAIN', $tplMain->fetch('contenu_mon_action'));
        
        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'));
   }
}

Note : vous ne devez pas assigner des zones dans le constructeur de la réponse, surtout si la zone en question veut ajouter des feuilles de style ou faire d'autres modifications sur l'objet réponse. En effet, l'objet réponse n'est pas encore déclaré dans l'environnement jelix, et donc la zone ne pourra y accéder.

Déclaration de l'objet réponse

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


[responses]
html=myHtmlResponse

Jelix cherchera la classe indiquée dans le répertoire responses/ de l'application. Si cette classe se trouve dans le répertoire responses/ d'un module ("main" par exemple), il faut l'indiquer comme un sélecteur :


[responses]
html="main~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: jApp::config()->theme
  • les paramètres de la requête: jApp::coord()->request->getParam(..)

Ci-dessous un exemple :



   public function __construct() {
        parent::__construct();

        $theme = jApp::config()->urlengine['basePath'].'themes/'.jApp::config()->theme.'/' ;
        $this->addCSSLink($theme.'css/screen.css');
   }

   protected function doAfterActions(){

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

        $param = jApp::coord()->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
admin   = adminHtmlresponse

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


  $repHTML = $this->getResponse('html');
  // ou
  $repHTML2 = $this->getResponse('html2');
  // ou
  $repAdmin = $this->getResponse('admin');

Utiliser ponctuellement une réponse d'origine

Si dans une action, vous voulez absolument utiliser la classe d'origine fournie 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.