Scripts de contrôleur

Scripts de vue

Une fois que le contrôleur a assigné les variables et appelé render(), Zend_View inclue le script de vue requis et l'exécute "à l'intérieur" de la portée de l'instance Zend_View. Donc dans vos scripts de vue, les références à $this pointent en fait sur l'instance Zend_View elle-même.

Les variables assignées à la vue depuis le contrôleur lui sont référées comme des propriétés de l'instance. Par exemple, si le contrôleur a assigné une variable "quelquechose", vous vous référerez à cette variable par $this->quelquechose dans le script de vue. (Cela vous permet de garder une trace pour savoir quelles valeurs ont été assignées au script, et lesquelles sont internes au script lui même.)

Pour rappel, voici l'exemple de script issu de l'introduction de ce chapitre sur Zend_View.

  1. <?php if ($this->livres): ?>
  2.  
  3.     <!-- La table des livres -->
  4.     <table>
  5.         <tr>
  6.             <th>Auteur</th>
  7.             <th>Titre</th>
  8.         </tr>
  9.  
  10.         <?php foreach ($this->livres as $cle => $livre): ?>
  11.         <tr>
  12.             <td><?php echo $this->escape($livre['auteur']) ?></td>
  13.             <td><?php echo $this->escape($livre['titre']) ?></td>
  14.         </tr>
  15.         <?php endforeach; ?>
  16.  
  17.     </table>
  18.  
  19. <?php else: ?>
  20.  
  21.     <p>Aucun livre à afficher</p>
  22.  
  23. <?php endif; ?>

Échapper la sortie

Une des tâches les plus importantes à effectuer dans un script de vue est de s'assurer que la sortie est correctement échappée ; de plus ceci permet d'éviter les attaques de type cross-site scripting (XSS). A moins que vous n'utilisiez une fonction, une méthode, ou une aide qui gère l'échappement, vous devriez toujours échapper les variables lors de l'affichage.

Zend_View a une méthode appelée escape() qui se charge de l'échappement.

  1. // mauvaise pratique d'affichage
  2. echo $this->variable;
  3.  
  4. // bonne pratique d'affichage
  5. echo $this->escape($this->variable);

Par défaut, la méthode escape() utilise la fonction PHP htmlspecialchar() pour l'échappement. Cependant, en fonction de votre environnement, vous souhaitez peut-être un échappement différent. Utilisez la méthode setEscape() au niveau du contrôleur pour dire à Zend_View quelle méthode de rappel ("callback") elle doit utiliser.

  1. // crée une instance Zend_View
  2. $view = new Zend_View();
  3.  
  4. // spécifie qu'il faut utiliser htmlentities
  5. // comme rappel d'échappement
  6. $view->setEscape('htmlentities');
  7.  
  8. // ou spécifie qu'il faut utiliser une méthode statique
  9. // comme rappel d'échappement
  10. $view->setEscape(array('UneClasse', 'nomDeMethode'));
  11.  
  12. // ou alors une méthode d'instance
  13. $obj = new UneClasse();
  14. $view->setEscape(array($obj, 'nomDeMethode'));
  15.  
  16. // et ensuite effectue le rendu de la vue
  17. echo $view->render(...);

La fonction ou méthode de rappel doit prendre la valeur à échapper dans le premier paramètre, et tous les autres paramètres devraient être optionnels.

Utiliser des systèmes de gabarit (template) alternatifs

Bien que PHP lui-même un moteur de gabarit puissant, beaucoup de développeurs pensent que c'est beaucoup trop puissant ou complexe pour les graphistes/intégrateurs et veulent utiliser un moteur de template alternatif. Zend_View fournit deux mécanismes pour faire cela, le premier à travers les scripts de vues, le second en implémentant Zend_View_Interface.

Système de gabarit utilisant les scripts de vues

Un script de vue peut être utilisé pour instancier et manipuler un objet de gabarit séparé, comme un gabarit de type PHPLIB. Le script de vue pour ce type d'activité pourrait ressembler à ceci :

  1. include_once 'template.inc';
  2. $tpl = new Template();
  3.  
  4. if ($this->livres) {
  5.     $tpl->setFile(array(
  6.         "listelivre" => "listelivre.tpl",
  7.         "chaquelivre" => "chaquelivre.tpl",
  8.     ));
  9.  
  10.     foreach ($this->livres as $cle => $livre) {
  11.         $tpl->set_var('auteur', $this->escape($livre['auteur']);
  12.         $tpl->set_var('titre', $this->escape($livre['titre']);
  13.         $tpl->parse("livre", "chaquelivre", true);
  14.     }
  15.  
  16.     $tpl->pparse("output", "listelivre");
  17. } else {
  18.     $tpl->setFile("nobooks", "pasdelivres.tpl")
  19.     $tpl->pparse("output", "pasdelivres");
  20. }

Et ceci pourrait être les fichiers de gabarits correspondants :

  1. <!-- listelivre.tpl -->
  2. <table>
  3.     <tr>
  4.         <th>Auteur</th>
  5.         <th>Titre</th>
  6.     </tr>
  7.     {livres}
  8. </table>
  9.  
  10. <!-- chaquelivre.tpl -->
  11.     <tr>
  12.         <td>{auteur}</td>
  13.         <td>{title}</td>
  14.     </tr>
  15.  
  16. <!-- pasdelivres.tpl -->
  17. <p>Aucun livre à afficher</p>

Système de gabarit utilisant Zend_View_Interface

Certains peuvent trouver plus facile de simplement fournir un moteur de gabarit compatible avec Zend_View. Zend_View_Interface définit l'interface de compatibilité minimale nécessaire :

  1. /**
  2. * Retourne l'objet moteur de gabarit actuel
  3. */
  4. public function getEngine();
  5.  
  6. /**
  7. * Affecte le dossier des scripts de gabarits
  8. */
  9. public function setScriptPath($path);
  10.  
  11. /**
  12. * Règle un chemin de base pour toutes les ressources de vue
  13. */
  14. public function setBasePath($path, $prefix = 'Zend_View');
  15.  
  16. /**
  17. * Ajoute un chemin de base supplémentaire pour les ressources de vue
  18. */
  19. public function addBasePath($path, $prefix = 'Zend_View');
  20.  
  21. /**
  22. * Récupère les chemins actuels vers les ressources de vue
  23. */
  24. public function getScriptPaths();
  25.  
  26. /**
  27. * Méthode à surcharger pour affecter les variables des gabarits
  28. * en tant que propriétés de l'objet
  29. */
  30. public function __set($key, $value);
  31. public function __isset($key);
  32. public function __unset($key);
  33.  
  34. /**
  35. * Affectation manuelle de variable de gabarit, ou possibilité
  36. * d'affecter des variables en masse.
  37. */
  38. public function assign($spec, $value = null);
  39.  
  40. /**
  41. * Efface toutes les variables du gabarit déjà affectées
  42. */
  43. public function clearVars();
  44.  
  45. /**
  46. * Effectue le rendu du gabarit nommé $name
  47. */
  48. public function render($name);

En utilisant cette interface, il devient relativement facile d'encapsuler un moteur de gabarit tiers comme une classe compatible Zend_View. Comme par exemple, le code suivant est une encapsulation potentielle de Smarty :

  1. class Zend_View_Smarty implements Zend_View_Interface
  2. {
  3.     /**
  4.      * Objet Smarty
  5.      * @var Smarty
  6.      */
  7.     protected $_smarty;
  8.  
  9.     /**
  10.      * Constructeur
  11.      *
  12.      * @param string $tmplPath
  13.      * @param array $extraParams
  14.      * @return void
  15.      */
  16.     public function __construct($tmplPath = null,
  17.                                 $extraParams = array())
  18.     {
  19.         $this->_smarty = new Smarty;
  20.  
  21.         if (null !== $tmplPath) {
  22.             $this->setScriptPath($tmplPath);
  23.         }
  24.  
  25.         foreach ($extraParams as $key => $value) {
  26.             $this->_smarty->$key = $value;
  27.         }
  28.     }
  29.  
  30.     /**
  31.      * Retourne l'objet moteur de gabarit
  32.      *
  33.      * @return Smarty
  34.      */
  35.     public function getEngine()
  36.     {
  37.         return $this->_smarty;
  38.     }
  39.  
  40.     /**
  41.      * Affecte le dossier des scripts de gabarits
  42.      *
  43.      * @param string $path Le répertoire à affecter au path
  44.      * @return void
  45.      */
  46.     public function setScriptPath($path)
  47.     {
  48.         if (is_readable($path)) {
  49.             $this->_smarty->template_dir = $path;
  50.             return;
  51.         }
  52.  
  53.         throw new Exception('Répertoire fourni invalide');
  54.     }
  55.  
  56.     /**
  57.      * Récupère le dossier courant des gabarits
  58.      *
  59.      * @return string
  60.      */
  61.     public function getScriptPaths()
  62.     {
  63.         return array($this->_smarty->template_dir);
  64.     }
  65.  
  66.     /**
  67.      * Alias pour setScriptPath
  68.      *
  69.      * @param string $path
  70.      * @param string $prefix Unused
  71.      * @return void
  72.      */
  73.     public function setBasePath($path, $prefix = 'Zend_View')
  74.     {
  75.         return $this->setScriptPath($path);
  76.     }
  77.  
  78.     /**
  79.      * Alias pour setScriptPath
  80.      *
  81.      * @param string $path
  82.      * @param string $prefix Unused
  83.      * @return void
  84.      */
  85.     public function addBasePath($path, $prefix = 'Zend_View')
  86.     {
  87.         return $this->setScriptPath($path);
  88.     }
  89.  
  90.     /**
  91.      * Affectation une variable au gabarit
  92.      *
  93.      * @param string $key Le nom de la variable
  94.      * @param mixed $val La valeur de la variable
  95.      * @return void
  96.      */
  97.     public function __set($key, $val)
  98.     {
  99.         $this->_smarty->assign($key, $val);
  100.     }
  101.  
  102.     /**
  103.      * Autorise le fonctionnement du test avec empty() and isset()
  104.      *
  105.      * @param string $key
  106.      * @return boolean
  107.      */
  108.     public function __isset($key)
  109.     {
  110.         return (null !== $this->_smarty->get_template_vars($key));
  111.     }
  112.  
  113.     /**
  114.      * Autorise l'effacement de toutes les variables du gabarit
  115.      *
  116.      * @param string $key
  117.      * @return void
  118.      */
  119.     public function __unset($key)
  120.     {
  121.         $this->_smarty->clear_assign($key);
  122.     }
  123.  
  124.     /**
  125.      * Affectation de variables au gabarit
  126.      *
  127.      * Autorise une affectation simple (une clé => une valeur)
  128.      * OU
  129.      * le passage d'un tableau (paire de clé => valeur)
  130.      * à affecter en masse
  131.      *
  132.      * @see __set()
  133.      * @param string|array $spec Le type d'affectation à utiliser
  134.                                 (clé ou tableau de paires clé => valeur)
  135.      * @param mixed $value (Optionel) Si vous assignez une variable nommée,
  136.                                       utilisé ceci comme valeur
  137.      * @return void
  138.      */
  139.     public function assign($spec, $value = null)
  140.     {
  141.         if (is_array($spec)) {
  142.             $this->_smarty->assign($spec);
  143.             return;
  144.         }
  145.  
  146.         $this->_smarty->assign($spec, $value);
  147.     }
  148.  
  149.     /**
  150.      * Effacement de toutes les variables affectées
  151.      *
  152.      * Efface toutes les variables affectées à Zend_View
  153.      * via {@link assign()} ou surcharge de propriété
  154.      * ({@link __get()}/{@link __set()}).
  155.      *
  156.      * @return void
  157.      */
  158.     public function clearVars()
  159.     {
  160.         $this->_smarty->clear_all_assign();
  161.     }
  162.  
  163.     /**
  164.      * Exécute le gabarit et retourne l'affichage
  165.      *
  166.      * @param string $name Le gabarit à exécuter
  167.      * @return string L'affichage
  168.      */
  169.     public function render($name)
  170.     {
  171.         return $this->_smarty->fetch($name);
  172.     }
  173. }

Dans cet exemple, vous instanciez la classe Zend_View_Smarty au lieu de Zend_View, et vous l'utilisez de la même façon :

  1. //Exemple 1a. Dans l'initView() de l'initializer.
  2. $view = new Zend_View_Smarty('/chemin/vers/les/templates');
  3. $viewRenderer =
  4.     Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
  5. $viewRenderer->setView($view)
  6.              ->setViewBasePathSpec($view->_smarty->template_dir)
  7.              ->setViewScriptPathSpec(':controller/:action.:suffix')
  8.              ->setViewScriptPathNoControllerSpec(':action.:suffix')
  9.              ->setViewSuffix('tpl');
  10.  
  11. //Exemple 1b. L'utilisation dans le contrôleur d'action reste la même
  12. class FooController extends Zend_Controller_Action
  13. {
  14.     public function barAction()
  15.     {
  16.         $this->view->book   = 'Zend PHP 5 Certification Study Guide';
  17.         $this->view->author = 'Davey Shafik and Ben Ramsey'
  18.     }
  19. }
  20.  
  21. //Example 2. Initialisation de la vue dans le contrôleur d'action
  22. class FooController extends Zend_Controller_Action
  23. {
  24.     public function init()
  25.     {
  26.         $this->view   = new Zend_View_Smarty('/path/to/templates');
  27.         $viewRenderer = $this->_helper->getHelper('viewRenderer');
  28.         $viewRenderer->setView($this->view)
  29.                      ->setViewBasePathSpec($view->_smarty->template_dir)
  30.                      ->setViewScriptPathSpec(':controller/:action.:suffix')
  31.                      ->setViewScriptPathNoControllerSpec(':action.:suffix')
  32.                      ->setViewSuffix('tpl');
  33.     }
  34. }

Scripts de contrôleur