Présentation de l'exemple
Une aide de vue, ou ViewHelper, sert à factoriser des bouts de code pour nos views ou layouts.
L'appel à notre aide de vue se fera très simplement. Prenons par exemple le cas où on a besoin de déclarer des feuilles de style dont les noms sont contenus dans un tableau :
$base_path = $this->basePath(); echo $this->getHeadLinks($base_path, $favicon_file = null, $this->config['css']);
Dans cet exemple, on utilise deux aides de vue, basePath() qui est fournie dans le package Zendframework 2 et getHeadLinks() que je vais développer ci-dessous.
Pour mon aide de vue je passe trois paramètres :
- $base_path : la racine du service fournie par l'aide de vue de ZendFramework
- $favicon_file : le favicon à utiliser pour cette page
- $config['css'] : le tableau provenant du config/module.config.php
Dans config/module.config.php, je décris les feuilles de style à charger de la façon suivante :
return array( ... 'css' => array( 'css/style.css', 'css/nav.css', array( 'href' => 'css/ie7.css', 'media' => 'screen', 'conditionalStylesheet' => 'lt ie7', 'extras' => array('id' => 'dafap',) ), ), ...
cela devra donner dans le code de la page :
<!--[if lt ie7]> <link href="/css/ie7.css" media="screen" rel="stylesheet" type="text/css" id="dafap" /><![endif]--> <link href="/css/nav.css" media="screen" rel="stylesheet" type="text/css"> <link href="/css/style.css" media="screen" rel="stylesheet" type="text/css"> <link href="/img/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
Implémentation de notre aide de vue
Une aide de vue, ou ViewHelper, est une classe dérivée de Zend\View\Helper\AbstractHelper. Pour mon cas, je l'appelerai HeadLinks et elle sera placée dans le src du module, dossier View/Helper :
module └ MonModule └ src └ MonModule └ View └ Helper
Sa méthode _invoke() retournera le résultat en invoquant son nom déclaré dans module.php dans la méthode getViewHelperConfig().
public function getViewHelperConfig() { return array( 'invokables' => array( 'getHeadLinks' => __NAMESPACE__ .'\View\Helper\HeadLinks', ), ); }
Dans mon aide de vue, j'ai besoin d'utiliser l'aide de vue headLink de Zendframework. Or, je ne peux pas utiliser l'alias headLink qui n'est pas invokable. Je vais donc utiliser la classe directement.
namespace MonModule\View\Helper; use Zend\View\Helper\AbstractHelper; use Zend\View\Helper\HeadLink; class HeadLinks extends AbstractHelper { public function __invoke($base_path, $favicon_file = null, $cssFilesArray = array()) { $headLink = new HeadLink(); if (! is_null($favicon_file) && is_string($favicon_file)) { $headLink = $headLink(array( 'rel' => 'shortcut icon', 'type' => 'image/vnd.microsoft.icon', 'href' => $this->concatPath($base_path, $favicon_file) )); } else { $headLink = $headLink(); } foreach ($cssFilesArray as $css_file) { if (is_string($css_file)) { $headLink = $headLink->prependStylesheet($this->concatPath($base_path, $css_file)); } elseif (is_array($css_file)) { $href = $this->getParam('href', $css_file); $media = $this->getParam('media', $css_file); $conditionalStylesheet = $this->getParam('conditionalStylesheet', $css_file); $extras = $this->getParam('extras', $css_file); if (!is_null($href)) { $headLink = $headLink->prependStylesheet($this->concatPath($base_path, $href), $media, $conditionalStylesheet, $extras); } } else { throw new \Exception('Erreur de structure pour la définition des fichiers css.'); } } return $headLink; } private function getParam($nom, $tableau) { if (array_key_exists($nom, $tableau)) { return $tableau[$nom]; } else { return null; } } private function concatPath($base_path, $file = null) { if (! is_null($file)) { $file = '/' . ltrim($file, '/'); } $base_path = rtrim(str_replace('\\', '/', $base_path), '/'); return $base_path . $file; } }
Utilisation de mon aide de vue dans un layout
Pour utiliser mon aide de vue dans un layout, je dois disposer d'une variable $this->config qui contient notamment la clé 'css' donnant la structure à monter (en fait, je passe également dans ce tableau tous les éléments constitutifs du layout comme les composants du header, du footer, etc.).
Comment passer une variable à un layout ?
Première façon : depuis un contrôleur
Dans un contrôleur, on a accès au layout par la méthode layout(). On crée donc les variables directement :
$this->layout()->ma_variable = $valeur;
En particulier pour mon cas, je trouverai la valeur de ma variable de configuration de la façon suivante :
$sm = $this->getServiceLocator(); $config = $sm->get('config'); $this->layout()->config = $config['layout'];
Deuxième façon : depuis la classe Module
Etant donné que la configuration est disponible dans la classe Module, on peut créer la variable depuis la méthode onBootstrap() de cette classe :
public function onBootstrap(MvcEvent $e) { $eventManager = $e->getApplication()->getEventManager(); $config = $this->getApplication()->getServiceManager()->get('config'); $config_layout = $config['layout']; $eventManager->attach(MvcEvent::EVENT_RENDER, function($e) use ($config_layout) { $e->getViewModel()->setVariable('config', $config_layout); }); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); }
Troisième façon : en dérivant la classe Module de ZfcBase\Module\AbstractModule
On devra alors restructurer le fichier module.config.php de la façon suivante :
return array( 'MonModule' => array( 'layout' => array( 'css' => array( 'css/style.css', 'css/nav.css', array( 'href' => 'css/ie7.css', 'media' => 'screen', 'conditionalStylesheet' => 'lt ie7', 'extras' => array('id' => 'dafap',) ), ), ... ), ), ... );
Ainsi, on pourra utiliser dans le module la méthode getOptions() :
namespace MonModule; use ZfcBase\Module\AbstractModule; class Module extends AbstractModule { public function onBootstrap(MvcEvent $e) { $eventManager = $e->getApplication()->getEventManager(); $config_layout = $this->getOptions('layout'); $eventManager->attach(MvcEvent::EVENT_RENDER, function($e) use ($config_layout) { $e->getViewModel()->setVariable('config', $config_layout); }); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); } public function getDir() { return __DIR__; } public function getNamespace() { return __NAMESPACE__; } }
Cela va permettre d'utiliser une configuration particulière pour chaque module de l'application. Mais ça, ce sera l'objet d'un prochain article.
Voir aussi un article complet sur la création d'un ViewHelper dans ZF2.