ZF – À la conquête de Zend Framework ! – plugins de ressources (Layout, Dojo et Navigation)
Nous allons voir dans cet article les plugins de ressources.
Comme introduit précédemment dans l’article sur le bootstrapping, ces plugins vont nous permettre d’initialiser de manière plus structurée certaines ressources comme les vues ou le layout.
Dans notre exemple nous allons les utiliser pour mettre en place un layout complet comprenant les aides de vues, le DojoToolkit et la navigation du site.
Résumé des composants:
Pour commencer nous allons créer notre classe de ressource que nous nommerons Lib_Application_Resource_Layout, son chemin sera donc /library/Lib/Application/Resource/Layout.php.
Pour que cette ressource soit prise en compte dans l’application, il faut qu’elle soit déclarée dans notre fichier de config application.ini de la manière suivante:
… ;déclaration du chemin des plugins de ressource pluginpaths.Lib_Application_Resource = APPLICATION_PATH "/../library/Lib/Application/Resource" ;céclaration d'une classe à charger resources.layout = Lib_Application_Resource_Layout ...
classe de ressource
La classe doit étendre Zend_Application_Resource_ResourceAbstract ce qui nous donne la possibilité de définir la méthode init(), appelée automatiquement à la suite du constructeur.
class Lib_Application_Resource_Layout extends Zend_Application_Resource_ResourceAbstract {
/**
* @var Zend_View instance
*/
protected $_view;
public function init() {
//initialisation de Zend_layout
$options = array(
'layout' => 'default', //nom du fichier *.phtml
'layoutPath' => APPLICATION_PATH.'/layouts', //chemin du fichier *.phtml
'contentKey' => 'content' //mot clef utilisé dans le layout
);
$layout = Zend_Layout::startMvc($options);
//récupération de l'instance de Zend_View utilisée par le Layout
$this->_view = $layout->getView();
$this->_initHead();
}
}
Layout
Pour le moment nous initialisons juste un layout en MVC et nous rendons accessible la vue associée dans protected $_view.
Vous remarquerez l’appel à la méthode _initHead(), elle va initialiser les aides de vue de la balise <head>. Voyons à quoi elle ressemble.
Helpers
La variable protected $_view contient l’objet Zend_View utilisé par le layout pour le rendu, c’est donc cette vue qu’il nous faut configurer.
protected function _initHead() {
//doctype
$this->_view->doctype('XHTML1_STRICT');
$this->_view->headTitle("MonApplication");
//meta
$this->_view->headMeta()->appendName('keywords', 'test')
->appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8')// type de contenu et encodage
->appendHttpEquiv('Content-Language', 'fr-FR');
//css
$this->_view->headLink()->appendStylesheet('./public/css/layout.css');
}
Remarque:
Les view helpers utilisés ici sont toutes des dérivées de Zend_View_Helper_Placeholder, en français « emplacement réservé » qui permet une persistance des contenus entre les différentes vues utilisées dans l’application.
default.phtml
La base du layout et en place, voyons maintenant le fichier default.phtml
<?php echo $this->doctype();?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr" class="screen">
<head>
<?php
//meta
echo $this->headMeta();
//styles
echo $this->headLink();
//scripts
echo $this->headScript();
//title
echo $this->headTitle();
?>
</head>
<body >
<?php echo $this->layout()->content; ?><
</body>
</html>
Dans ce fichier nous rendons juste le contenu précédemment initialisé. Ici l’intérêt est assez minime mais dans une utilisation plus poussée ces aides de vues permettent par exemple la gestion complète du layout via un fichier xml, ce qui devient beaucoup plus intéressant (article à venir dans un futur plus ou moins proche !).
L’aide de vue $this->layout() nous donne accès au contenu rendu par nos controllers, ce qui correspond donc à la partie « dynamique » du layout.
Je n’ai volontairement mis aucune mise en page, car nous allons voir que dojo s’occupe de tout!
Dojo
L’intégration assez complète du framework Dojo dans ZF nous permet une initialisation complète directement dans notre classe de ressource via l’aide de vue dojo().
Nous ajouterons donc une autre méthode à notre classe qui sera appelée dans init() après _initHead().
protected function _initDojo() {
//activation des aides de vue pour dojo
Zend_Dojo::enableView($this->_view);
//ajout des styles dojo et le thème thundra
$this->_view->headLink()
->appendStylesheet('./public/js/Dojo/dojo/resources/dojo.css')
->appendStylesheet('./public/js/Dojo/dijit/themes/tundra/tundra.css');
//configuration
$this->_view->dojo()->enable()//activation du rendu
->setLocalPath('./public/js/Dojo/dojo/dojo.js')//chemin du fichier dojo.js
->addStyleSheetModule('dijit.themes.tundra')//thème utilisé
->setDjConfigOption('parseOnLoad', true)//parsage après chargement de la page
->requireModule('dijit.layout.LayoutContainer') //conteneur global
->requireModule('dijit.layout.ContentPane')//conteneur pour la mise en page
->requireModule('dijit.TitlePane'); //fenêtre avec barre de titre
}
Rien de très complexe et même plutôt intuitif. Dojo a un fonctionnement assez similaire à ZF, il fonctionne aussi avec des composants. Ils doivent impérativement être déclarés avec la méthode requireModule().
Maintenant nous allons finir notre fichier default.phtml, attention il va y avoir du changement !
<body class="screen tundra">
<!--CONTENEUR PRINCIPAL-->
<div dojoType="dijit.layout.LayoutContainer" class="screen">
<!--CONTENEUR TOP-->
<div dojoType="dijit.layout.ContentPane" layoutAlign="top" style="background:#ccc;">
</div>
<!--CONTENEUR LEFT-->
<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="background:#fff; width:250px;">
<!--CONTENEUR TITRE pour le menu-->
<div dojoType="dijit.TitlePane" title="Menu" toggleable=false>
<div id="nav"><?php echo $this->navigation()->menu(); ?></div>
</div>
</div>
<!--CONTENEUR RIGHT (client)-->
<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
<!--CONTENEUR TITRE pour le contenu-->
<div dojoType="dijit.TitlePane" title="<?php echo $this->navigation()->breadcrumbs(); ?>" toggleable=false>
<div id="page-contentPane"><?php echo $this->layout()->content; ?></div>
</div>
</div>
<!--CONTENEUR BOTTOM-->
<div dojoType="dijit.layout.ContentPane" layoutAlign="bottom" style="background:#ccc;"></div>
</div>
</body>
Ne vous inquiétez pas, tout va être expliqué.
Dojo peut être utilisé de manière déclarative, sous la forme de balises html avec un paramètre dojoType égale à la déclaration que l’on a faite avec requireModule(). Ainsi, quand le parseur dojo rentre en action, il transforme nos balises en « magnifiques » composants dojo!
La déclaration de la classe “tundra” dans la balise permet à Dojo de savoir quel thème est à utiliser dans la page, “screen” étant simplement notre classe css spécifiant les dimensions de notre application (obligatoire!).
Vous remarquerez aussi deux intrus, je nommerai navigation()->menu() et navigation()->breadcrumbs().
Leur nom est assez évocateur je pense. L’un va générer un menu, l’autre le fil d’Ariane, mais voyons tout ça en détail.
La navigation
ZF met à notre disposition un composant, Zend_Navigation, prenant en charge la navigation de votre application (un article plus approfondi y sera surement consacré d’ici peu). Pour déclarer un menu, plusieurs solutions sont possibles:
- sous forme d’array()
- format XML
- format INI (moins adapté à mon goût)
Deux types de page sont proposés:
Zend_Navigation_Page_Uri avec comme principaux paramètres le label et l’uri associée
Zend_Navigation_Page_Mvc où l’on déclare le couple controller/action associée.
Zend_Navigation_Page_Uri est pratique pour par exemple pointer vers des urls externes ce qui ne sera pas utile dans notre exemple. Nous utiliserons donc Zend_Navigation_Page_Mvc avec une déclaration XML. Voici le fichier navigation.xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<nav>
<accueil>
<label>Accueil</label>
<controller>index</controller>
<action>index</action>
<class>menu-item</class>
<resource>nav-public-home</resource>
</accueil>
<about>
<label>About Site</label>
<controller>index</controller>
<action>about</action>
<class>menu-item</class>
<resource>nav-public-about</resource>
</about>
<publication>
<label>Publication</label>
<controller>publication</controller>
<action>index</action>
<class>menu-item</class>
<resource>nav-private-publication</resource>
</publication>
</nav>
</root>
Nous déclarons trois rubriques, « Accueil », « About site » et « Publication » et le couple controller/action associé. La balise <class> déclare la classe CSS de nos rubriques pour la mise en page de notre menu.
Vous remarquerez que j’ai aussi ajouté une balise <resource>, elle nous servira dans la mise en place des ACL pour générer le menu associé aux droits utilisateur. Nous étudierons cela en détail dans le prochain article!
Bon… Nous avons notre menu, il ne reste plus qu’à demander poliment à ZF de l’utiliser!
Revenons donc à notre classe de ressource, nous allons lui ajouter une dernière méthode à appeler comme à chaque fois dans init():
protected function _initNavigation() {
//parsage du fichier xml en lui indiquant la section à utiliser, ici "nav"
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'nav');
//initialisation de Zend_Navigation
$navigation = new Zend_Navigation($config);
//initialisation de l'aide vue navigation()
$this->_view->navigation($navigation);
//initialisation du breadcrumbs
$this->_view->navigation()->breadcrumbs()
->setMinDepth(0)->setSeparator(' >> ');
}
Pas mal d’options sont disponibles pour configurer le menu et le fil d’arianne, je vous conseille donc de jeter un coup d’oeil à la doc sur les aides de navigation.
Conclusion
Voilà, nous avons construit un layout assez fonctionnel, configurable et surtout maintenable en séparant la couche ressource du bootstrap. Ceci est faisable pour toute ressource méritant une configuration personnalisée.
Nous verrons dans le prochain article la mise en place des contrôleurs et des vues (vide pour le moment) dans l’optique d’y restreindre les droits via Zend_Acl et Zend_Auth. Ceci nous amènera à utiliser les ressources déclarées dans notre fichier navigation.xml et ainsi générer le fameux menu personnalisé.

Merci beaucoup pour ce très bon tuto ! J’attends avec beaucoup d’impatience.
Les précédents été aussi très bien.
Bonne continuation !!
@Camille, merci pour ce retour positif, la suite ne devrait pas trop trop tarder ;-)
N’hésite pas à poser des questions si besoin!
@Glenn Merci pour tout ce travail. Certaines étapes obscure dans mon travail personnel s’éclaircisse enfin. A bientôt dans les autres tutos…..
Salut Glenn,
Connaitrais tu un bon tutoriel sur les Models (objet,table,mapper,service).
Ou serait-il possible d’avoir ton avis à ce sujet, comment procèdes tu? (je suis entrain de débuter avec ZendF. et cette partie reste assez flou)
Merci d’avance! –en espérant t’avoir donné des idées pour un futur tutoriel– ;)
Bonjour à toi Pierre!
Pour les modèles d’accès à la bdd, je me base sur Zend_Db_Table, son utilisation est assez simple mais limitée car pas de vrai full loading à l’image de Doctrine (sauf si tu l’implémente!).
Je te conseille vivement de potasser la doc, elle est assez complète à ce sujet bien que manquant un peu de clarté…
Zend_Db_Table
Tutos zend (je n’ai pas encore trouvé mieux:) ).
N’hésite pas à repasser par le blog d’ici peu, l’article sur l’accès aux données sera en 5ème position dans la suite “ZF – À la conquête de Zend Framework !”.
Bonne continuation!
Merci Glenn je vais attendre ton tutoriel, j’espère que celui ci sera un peu plus poussé que ce qu’on peut trouver sur le net.
(ex. lorsqu’un objet est composé d’élément provenant de plusieurs tables)
A bientôt!
Trés bons tutos. Merci.
J’apprécie surtout tes annotations sur la nouvelle version 1.10 de Zend car trop de Tutos sur le net sont obsolètes et on (je) ne comprends plus rien des fois .
Continue ;)
avez-vous un autre tutoriel plus détaillé sur le même sujet ?
Merci de m’envoyer si possible le lien
Cordialement,
Bonjour,
J’ai suivi avec bcp d’attention votre tutoriel…toutefois, je n’arrive pas à le reproduire chez moi.
Pourriez-vous svp y jeter un coup d’oeil.
J’ai posté un message sur ce forum mais je n’ai pas eu de retour et je n’arrive plus à avancer.
http://www.developpez.net/forums/d966549/php/outils/zend/zend-framework/autres-composants/file-dariane-zend_navigation/
Merci d’avance.
Bonne journée!
Cordialement Sheira
Sujet vraiment très intéressant, je suis novice et je me perd un peu dans ton tuto. Par exemple ton fichier xml navigation.xml se trouve dans l’arborescence de notre projet. A part le mettre dans le dossier view je ne vois pas trop ou l’on peut le mettre. Sinon comme d’hab tu démocratise bien le truc.
autant pour moi je suis trop con.
Hello,
je vois 2 choses qui pourraient être ajoutées dans ce tuto :
1) il me semble qu’il n’est pas précisé qu’il faille ajouter les initialisations suivantes :
$this->_initDojo();
$this->_initNavigation();
dans Layout.php (méthode init(), à la suite de $this->_initHead())
Conséquence : les styles et le menu xml ne sont pas chargés lorsque l’on arrive à la fin du tuto.
Remarque : c’est peut-être évident pour certains, mais autant le mettre si manquant.
2) L’emplacement des ressources dojo sur le web en terme de css et js pour limiter le temps de mise en place au sein de l’application et donc un aboutissement plus rapide et moins incertain.
J’ai récupéré tundra.css ici : http://o.aolcdn.com/dojo/1.2.0/dijit/themes/tundra/tundra.css
Voilà pour ma part, on est très proche de la perfection ;-)
C’est de la bombe bébé (Kool Shen).