Vous êtes sur la page 1sur 70

Prsentation du Zend Framework - Premiers pas

par Julien Pauli (Tutoriels, confrences PHP) (Blog)


Date de publication : 03/04/2007 Dernire mise jour : 04/11/2010

Depuis Mars 2006 est apparu le Framework maison de chez Zend, pour PHP5. Pour rappel, Zend est une socit qui commercialise tout un tas d'outils pour les entreprises, autour de PHP. Zend Framework est un d'entre eux si ce n'est qu'il n'est pas commercialis : distribu sous "New BSD Licence", il est gratuit, libre, conu par une grande communaut de dveloppeurs interesss dont je fais parti, pilot par Zend, et il propose gnration de documents PDF, connecteurs vers de multiples services webs, connecteurs vers des bases de donnes diverses et support de MVC... On peut utiliser le Framework en tant que cadre de developpement directif, ou l'utiliser dans le cadre d'un simple support bibliothquaire, la manire de PEAR. Le projet Zend Framework est en perpetuel dveloppement, et certains composants sont dvelopps par les entreprises intrsses : les Webservices Gdata sont dvelopps par Google eux-mmes, mais dans le respect de la licence du projet. Zend Framework reprend en tout point le concept de PHP lui-mme : libre, ouvert, simple, efficace et puissant : un vrai rgal.

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

I - Prsentation............................................................................................................................................................ 3 I-A - Prambule...................................................................................................................................................... 3 I-B - Introduction.....................................................................................................................................................4 I-C - Pr-requis.......................................................................................................................................................4 I-D - Le coeur du Framework................................................................................................................................ 5 I-E - Les conventions de nommage - Vocabulaire................................................................................................ 5 II - #Zend_Loader........................................................................................................................................................ 7 III - #Zend_Debug #Zend_Version............................................................................................................................ 10 IV - #Zend_Registry...................................................................................................................................................11 V - #Zend_Config.......................................................................................................................................................13 VI - Zend_Cache........................................................................................................................................................16 VII - #Zend_Validate.................................................................................................................................................. 19 VIII - #Zend_Filter...................................................................................................................................................... 23 VIII-A - Zend_Filter............................................................................................................................................... 23 VIII-B - Zend_Filter_Input..................................................................................................................................... 23 IX - #Zend_Db........................................................................................................................................................... 28 IX-A - Introduction................................................................................................................................................ 28 IX-B - Requtes simples...................................................................................................................................... 30 IX-C - Rcupration de rsultats......................................................................................................................... 31 IX-D - Insert, Update et Delete............................................................................................................................ 34 IX-E - Transactions...............................................................................................................................................35 IX-F - Slections...................................................................................................................................................36 IX-G - Passerelle vers les tables......................................................................................................................... 38 IX-G-1 - Gnralites........................................................................................................................................38 IX-G-2 - L'exemple.......................................................................................................................................... 38 IX-G-3 - Dfinition des passerelles.................................................................................................................39 IX-G-4 - Les rsultats (Row)...........................................................................................................................42 IX-G-5 - Les jeux de rsultats (Rowset).........................................................................................................43 IX-G-6 - Gestion des dpendances................................................................................................................44 IX-H - Rappels......................................................................................................................................................45 X - #Zend_Log........................................................................................................................................................... 46 XI - #Zend_View........................................................................................................................................................ 49 XI-A - Principe...................................................................................................................................................... 49 XI-B - Helpers (aides au rendu)...........................................................................................................................50 XII - Zend_Layout...................................................................................................................................................... 53 XII-A - Principe..................................................................................................................................................... 53 XII-B - Exemples.................................................................................................................................................. 54 XIII - Zend_Form........................................................................................................................................................55 XIII-A - Manipuler des lments de formulaire.................................................................................................... 56 XIII-B - Ajouter des validateurs et valider le formulaire....................................................................................... 58 XIII-C - Dcorateurs : grer le rendu HTML........................................................................................................ 61 XIII-D - Autres fonctionnalits.............................................................................................................................. 64 XIII-E - Etendre Zend_Form.................................................................................................................................64 XIV - Zend_Application.............................................................................................................................................. 65 XIV-A - Configurer ses objets (ressources)......................................................................................................... 66 XIV-B - Utiliser les plugins pour configurer ses objets (ressources)................................................................... 68 XV - Conclusions....................................................................................................................................................... 70

-2Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

I - Prsentation I-A - Prambule


Le Zend Framework (ZF) fait beaucoup de bruit sur la toile du dveloppement PHP. Il sait se classer dans la vague des Framework "reconnus" sous PHP. Google le prsente d'ailleurs parmi ses outils pour developpeurs. J'ai dcid de vous y faire goter du bout des lvres ;-). Ce Framework a bien grandi. En l'espace d'un an, il a chang de licence pour s'ouvrir au dveloppement communautaire, et il accuse dj une quarantaine de composants oprationnels. Il est vrai qu' ses dbuts, dbut 2006 (le projet date d'Octobre 2005), tout tait diffrent. Beaucoup de refactorisation et de correction de bugs ont t faits. Une si belle progression n'aurait pu tre possible sans un modle de dveloppement communautaire, mais bien architectur. Tout le monde peut reporter un bug sur le tracker, proposer ses ides, faire partager ses expriences, tout ceci orchestr par l'quipe de gestion du projet de Zend. Personnellement, j'ai bien aim mes dbuts sous ZF, c'est en dcouvrant peu peu sa structure et son articulation que j'ai dcid de contribuer un peu, tout d'abord via ce tutoriel de prsentation. Mon blog regorge d'informations diverses concernant ZF, et j'cris aussi d'autres articles ou ateliers techniques. ZendFramework reprsente aussi une partie de mon travail titre professionnel, en effet je suis formateur sur ce Framework et j'aide son dploiement ou son utilisation dans le milieu professionnel en consulting architectural. Je bosse sous ce Framework depuis environ Octobre 2006 (version 0.2), et je suis de prs tout ce qui le touche, notamment son dveloppement actuel qui tend se rapprocher d'un style Ruby On Rails, de par certaines caractristiques. Nul doute que les programmeurs habitus du "full object", ne seront pas dpayss (les adeptes de Java par exemple). Je suis contributeur, je participe donc au dveloppement de certains composants ainsi qu' la correction de bugs et l'amlioration de certaines fonctions. A la tte du Zend Framework, on trouve Andi Gutmans, qui n'est autre qu'un des 2 architectes responsables du Zend Engine, le moteur de PHP ayant succd au projet initialement conu par Rasmus Lerdof. Le but de Zend est simple : faire de ZF un framework calqu sur PHP : aussi simple, intuitif, et puissant, que le langage PHP lui-mme, et je dois dire que pour le moment, c'est nettement le cas ! Certes il existe des tonnes de frameworks dans l'univers de PHP, et des bons en plus, mais on peut dire du Zend Framework qu'il est amen devenir la brique que tout dveloppeur PHP sera mme de savoir utiliser, surtout dans un environnement professionnel. Car c'est bien l que Zend intervient : l'entreprise vend du support et des services autour de produits, eux, libres : PHP d'abord, et aujourd'hui : ZendFramework. Une entreprise est bien plus rassure lorsqu'un support professionnel est prsent derrire un produit, fortiori libre. Passer le framework sous une licence "ouverte" est donc bienvenu de la part de Zend. ZF n'est pas ferm et peut se relier d'autres frameworks; de mme , il y a 2 moyens d'utiliser ZF : en "glue" : vous utilisez uniquement les composants dont vous avez besoin, ponctuellement, la manire de PEAR. Autre mthode : "full-stack" : vous dcidez ds le dpart de btir votre architecture entire sur ZF. Cette permabilit de Zend Framework en fait sa force ultime : vous pouvez doucement apprendre le maitriser, avant de totalement l'utiliser, ne plus pouvoir vous en passer; car ZF a bel et bien pour objectif de rpondre aux besoins les plus redondants du dveloppement de sites Internet en PHP ZF est la surcouche fonctionnelle de PHP5, test, scuris, dvelopp et pens par des ingnieurs, architectes et dveloppeurs d'importance, le tout dans un esprit collaboratif, libre et open source. Si vous tes intresss pour approfondir le vaste sujet que reprsente le ZendFramework, j'ai co-crit un ouvrage son sujet, vous en apprendrez plus sur sa page ddie.

-3Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

I-B - Introduction
Un Framework apporte un cadre standard pour le dveloppement d'applications interface web. Il agrge diffrentes classes, ce qui augmente la couverture fonctionnelle d'un langage tout en en simplifiant sa manipulation. Il permet plusieurs personnes (notamment en Entreprise) de s'organiser autour d'un projet, quelle que soit sa taille. Il introduit des rgles de codage et d'architecture qui sont l pour faire en sorte que toutes les personnes relatives au projet parlent la mme langue. Tous les dveloppeurs vont ainsi crire du code partir du mme cadre de travail, et l'change des donnes entre eux est trs facilit. Les architectes et les chefs de projet techniques s'y retrouvent aussi, car la puissance de la programmation oriente objet leur permet d'utiliser des mthodes connues et ayant fait leurs preuves, comme la modlisation UML, le design logiciel ou les design patterns. La conception objet permet aussi un fort dcouplage applicatif, la rutilisabilit maximale du code et favorise grandement les tapes de test et de gestion de la qualit d'un produit. Avec ce jour une grosse cinquantaine de packages fonctionnels; le Zend Framework propose "une collection modulaire de classes PHP 5 qui simplifient les tches courantes du dveloppeur". Il s'agit pour l'essentiel de fonctionnalits trs utilises comme une couche d'abstraction de bases de donnes (fonde principalement sur PDO), le support de MVC, la gnration de documents PDF, l'envoi d'e-mails, la gestion de flux de syndication Atom et RSS, la gestion de l'internationalisation... Le Zend Framework intgre aussi des "connecteurs" pour les services en ligne de Yahoo!, Google, Amazon, Flickr, Twitter, FaceBook... On peut noter aussi une classe de gestion des dates, un package complet pour l'indexation de contenu bas sur le clbre moteur Lucne de l'Apache Group, tout un tas d'outils facilitant l'internationalisation, les sessions, etc. Pour s'assurer du succs de son Framework, Zend s'est appuy sur un modle participatif et communautaire impliquant plus de 180 participants au nombre desquels figurent de grands acteurs comme Yahoo!, Google, IBM et General Electric. La concision du code qu'apporte un Framework de haut niveau, plus fonctionnel que technique, augmente la productivit des dveloppeurs. Par exemple, il faut environ 15 lignes de code PHP pour afficher un flux RSS, tandis que 5 suffisent avec le Zend Framework.

I-C - Pr-requis
Ce tutoriel suppose que vous ayez de solides connaissances du travail sous PHP dans sa version 5.3 et notamment du modle objet de celui-ci, ainsi que de la SPL (Standard Php Library), qui fournit un ensemble de classes interne PHP. Dans le cadre de la comprhension de cet article, il est conseill de possder de bonnes comptences en programmation oriente objet (POO), de bonnes notions de conception UML et des Design Patterns, ainsi que quelques connaissances du langage SQL; tant donn que nous ne ferons pas que "survoler" certaines de ses fonctionnalits Vous retrouverez les diagrammes de classe des principaux packages tudis en annexe. L'environnement de travail tudi dans cet article est PHP 5.3.x. Zend Framework requiert PHP 5.2.4 minimum pour fonctionner. Sans nul doute, votre point de repre reste l'API en ligne, le mcanicien ne bossant pas sans sa caisse outils... Histoire de ne pas se perdre dans les mthodes et les objets, on garde un oeil sur le manuel. Attention tout de mme, la version originale du manuel est la version anglaise. Les autres versions sont des traductions, effectues par des groupes de traduction de l'quipe de dveloppement, et peuvent donc tre dsynchronises, le temps de la traduction. Vrifiez donc les statuts des traductions, ou prfrez la doc originale, en anglais. Commenons par tlcharger la dernire version stable de ZF. ce jour, ce tutoriel est crit avec ZF 1.11

-4Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Il est important de vrifier la version du framework utilise. Celui-ci assure une compatibilit ascendante, quelques cassures sont noter, documentez vous: Les ChangeLog peuvent vous aider.

I-D - Le coeur du Framework


Je vous renvoie au sommaire afin de prendre connaissance des quelques composants que nous allons tudier dans cet article. Rien qu'avec ces quelques composants, nous serons dj en mesure de faire une petite appli web sympathique, vous remarquerez que je n'utiliserai pas ici #Zend_Controller, donc pas de MVC dans cet article. Cependant, notre section Zend Framework devrait satisfaire vos autres curiosits. Il n'est pas obligatoire de raliser un projet 100% sous ZF. Ainsi, mme sans MVC, ZF va tout de mme nous simplifier la vie. Cet article n'a pas pour vocation d'tre exhaustif, certaines mthodes ne seront pas prsentes, elles sont cependant bien prsentes dans l'API. Le coeur du Framework est reprsent par le dossier library de l'archive tlcharge. La structure interne de ZF est rgie par des conventions de nommage, que voici :

I-E - Les conventions de nommage - Vocabulaire


#Zend_Db reprsente un composant que l'on peut aussi appeler package (en rfrence Java), il est matrialis par le script /ZF-path/Zend/Db.php, la classe reprsente tant Zend_Db. Cette convention de nommage sera utilise pour charger des classes plus tard. Elle est identique certains projets, tels que PEAR. Remplacez les underscores ( _ ) dans le nom de la classe par des slashs ( / ), pour voir apparatre l'arborescence du fichier. Si votre application respecte la mme norme, alors vous verrez que le dveloppement devient encore plus souple. Comme pour PEAR, chaque underscore ( _ ) dans le nom de la classe reprsente donc une descente dans l'arborescence, et un lien de dpendance fonctionnelle. Chaque composant donne naissance une classe, portant le mme nom, et chaque composant est une entit du Framework, qui peut contenir d'autres classes qui l'enrichissent et qui dpendent d'elle. Ainsi, Zend_Db_Adapter_Abstract est une classe dont le fichier est /ZF-path/Zend/Db/Adapter/Abstract.php, contenu dans le package #Zend_Db On peut donc dire que tout ce qui descend, dpend. Une dpendance est un lien UML soit direct : hritage, soit indirect : utilisation, implmentation, etc. Mais un des avantages de ZF est son couplage relativement faible. Tous les packages ne dpendant pas les uns des autres, seules quelques liaisons internes sont effectues, lorsque c'est ncessaire. Ainsi, vous pouvez sans problme utiliser #Zend_Db, par exemple, sans avoir dpendre d'un autre package. Seules quelques dpendances entre packages sont noter (elles sont mme de temps en temps facultatives) o c'est rellement ncessaire : #Zend_Mail va utiliser #Zend_Mime (a se comprend), #Zend_Http_Client va utiliser #Zend_Uri. Mais ce n'est pas le gros foutoir, dans lequel l'inclusion du moindre composant, entrane une inclusion de dizaines d'autres (et donc un temps de traitement revu la hausse). Il est conseill de placer le rpertoire du Framework en dehors de la racine web, sinon, d'interdire son accs, par exemple avec un fichier .htaccess. Comme pour tout Framework, dans un souci de pratique, il faut d'abord ajouter son rpertoire l'include path de PHP. Ceci se fait soit par l'intermdiaire du fichier php.ini, soit via la fonction set_include_path(). Nous utiliserons en dveloppement une gestion d'erreur large (E_ALL | E_STRICT). L'utilisation d'un framework apporte une baisse notable des performances d'une application, ceci est d l'inclusion de dizaines de fichiers par requte HTTP.
-5Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Lors de l'utilisation de MVC notamment, il n'est pas rare qu'une simple petite requte HTTP provoque l'ouverture de dizaines de fichiers PHP sur le serveur, pour la traiter. Pour absorber et faire disparaitre cet inconvnient de taille, un cache d'opcodes (type APC) second par un cache applicatif (type Zend_Cache) sont des solutions tout fait reconnues et utilises. N'oubliez pas aussi de toujours tourner sur une version de PHP jour. PHP 5.3 apporte des amliorations importantes en terme de performances par rapport la version 5.2

-6Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

II - #Zend_Loader
La classe Zend_Loader comporte dj toute une srie d'outils trs pratiques. Ce ne sont que des mthodes statiques, sans dpendances externes (Elles ne necessitent pas d'autres composants, cependant d'autres composants ont besoin d'elle). Le composant inclure est #Zend_Loader, il est donc reprsent par le fichier /Zend/Loader.php. Quasiment tous les composants du Framework dpendent de #Zend_Loader. configuration pour utilisation de ZF
<?php // ZFHome est le chemin o le dossier 'library' est plac. error_reporting(E_ALL | E_STRICT); set_include_path('path/to/ZFHome' . PATH_SEPARATOR . get_include_path());

ZF utilise sa propre gestion d'exceptions qui n'est autre qu'un alias de la classe Exception native de PHP. class Zend_Exception extends Exception{} Toute exception qui sera leve dans vos applications enverra, au plus bas, une Zend_Exception. Notez que Zend_Exception n'tant pas dclare en 'final', il est possible de l'tendre, ce qu'il est hautement conseill de faire. Je ne vais pas faire un tutoriel sur les Exceptions, mais juste rappeler que chaque package, ou chaque entit lmentaire, doit renvoyer sa propre exception, nomme. Cela facilite grandement le dbogage, notamment dans le cadre de projets travaills en quipe. Si tout le monde envoie des 'Exception', toutes simples, on ne peut absolument pas savoir d'o viennent les erreurs, de mme lors des processus de tests, tout se complique. Remarquez qu'il faut que Zend Framework soit dans l'include_path de PHP. Il est conseill d'effectuer cette modification dans PHP.ini directement. Nous supposerons cel par la suite. Nous allons poursuivre avec les mthodes 'helpers' du composant #Zend_Loader. Utiliser des helpers, alors que PHP seul peut reprsenter les mmes fonctions, est utile si vous chargez des fichiers dont le nom ou le chemin d'accs sont variables (des vrifications sont faites sur le nom). Sinon, un require() fait l'affaire. loadFile() charge un fichier PHP. utilisation de Zend_Loader supposant ZF prsent dans l'include_path
<?php // manire classique require('example1.php');

// manire ZF require('Zend/Loader.php'); try { Zend_Loader::loadFile('example2.php'); } catch (Zend_Exception $e) { echo $e->getMessage(); } <?php // manire classique avec once require_once('example1.php'); // manire ZF avec once require('Zend/Loader.php'); try { Zend_Loader::loadFile('example2.php', null, true); } catch (Zend_Exception $e) { echo $e->getMessage(); }

La grande diffrence avec PHP, comme pour tous les outils du Framework Zend, est qu'ils s'appuient sur une gestion d'Exception interne, que vous pouvez contrler comme vous le souhaitez. Si un fichier comporte des caractres interdits, une Zend_Exception sera leve.
-7Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Plus rpandu dj, loadClass() charge une classe en utilisant loadFile(). Cette mthode s'utilise surtout avec les mcanismes d'autoload. Configuration de ZF avec autoload

<?php require('Zend/Loader/Autoloader.php'); Zend_Loader_Autoloader::getInstance();

spl_autoload_register() est utilis en interne par cette mthode, et enregistre la fonction d'autoload de Zend Framework sur la pile des autoloaders. Avec l'autoload, ds que PHP rencontre une classe qu'il ne connait pas (c'est dire dont le fichier la dfinissant n'a pas encore t inclu), il va utiliser la fonction d'autoload pour chercher le fichier correspondant cette classe. La fonction d'autoload de ZF lui fait utiliser loadClass() Aprs que le fichier ait t trouv, loadClass() s'assure que la classe a t charge suivant les conventions de nommage. loadClass() effectue donc 2 actions : charge le fichier de la classe, et vrifie le nom de la classe dans ce fichier. Pour de plus amples informations sur l'autoload, Framework parcourez cet atelier Zend

Une fois l'autoload activ grce l'instruction Zend_Loader_Autoloader::getInstance(), nous pouvons charger toute classe Zend_ sans avoir l'inclure avant. Pour charger des autres classes, il faut utiliser un espace de nommage, c'est dire un prfixe de classe (Comme Zend_ pour le Zend Framework). Il faut ensuite ajouter le dossier contenant ce dossier espace de noms dans l'include path de PHP, et dclarer l'espace de nom l'autoloader. Ca parait compliqu ? Regardez comme c'est simple : Utiliser l'autoload pour charger ses classes

<?php define ('APP_PATH', __DIR__); set_include_path(get_include_path() . PATH_SEPARATOR . APP_PATH . '/mesclasses' . PATH_SEPARATOR); require('Zend/Loader/Autoloader.php'); $loader = Zend_Loader_Autoloader::getInstance(); $loader->registerNamespace(array('Dvp_', 'JP_')); // Dvp_Class est dfinie dans APP_PATH/mesclasses/Dvp/Class.php $class = new Dvp_Class; // JP_Exemple est dfinie dans APP_PATH/mesclasses/JP/Exemple.php $class2 = new JP_Exemple; ?>

L'utilisation de l'autoload est aujourd'hui trs largement rpandue et recommande dans les projets webs. Sinon, loadClass() et loadFile() acceptent un second paramtre $dirs, chane ou tableau reprsentant un (des) dossier(s) dans lequel (lesquels) rechercher le fichier. isReadable() est une copie de son homologue PHP, la seule diffrence qu'isReadable() parcourt l'include path. Pour grer correctement l'extensibilit de ses applications, la classe Zend_Loader_PluginLoader vous propose de charger manuellement une classe en prcisant uniquement son suffixe. Cela permet notamment de charger un ensemble de prfixes que la classe essayera en ordre LIFO : Utilisation de PluginLoader

<?php require 'Zend/Loader/PluginLoader.php'; $loader = new Zend_Loader_PluginLoader(); $loader->addPrefixPath('Dvp', 'chemin/developpez');

-8Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Utilisation de PluginLoader

$loader->addPrefixPath('Other', 'autrechemin/ailleurs'); $obj = $loader->load('Utils'); /* $obj est instance de la classe Other_Utils si autrechemin/ailleurs/Utils.php existe et possde la classe, sinon il s'agira d'un objet Dvp_Utils se trouvant dans chemin/libs/Developpez/ Utils.php si ce fichier existe, dans le dernier cas : une exception sera leve */

Se servir de ce composant manuellement est plutt rare, en revanche le ZendFramework l'utilise lui en interne trs souvent. Ds lors qu'on vous demandera de prciser le nom d'une classe par une chaine reprsentant son prfixe, alors Zend_Loader_PluginLoader est utilis en interne. C'est notamment le cas pour les formulaires, les vues, etc...

-9Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

III - #Zend_Debug #Zend_Version


#Zend_Debug ne contient actuellement qu'une mthode (utile) statique de dbbuguage. dump(): est une amlioration trs apprcie de var_dump() qui rajoute des <pre> de formatage pour un confort de lisibilit amlior. C'est le remplaant des echo() et autres print_r() var_dump(), extrmement pratiques en dbuguage. setSapi():, permet de spcifier manuellement le SAPI sur lequel PHP tourne, le formatage de la sortie ne sera plus encadr de <pre> mais de PHP_EOL (End Of Line, dpendant de l'OS sous lequel PHP tourne). En thorie vous n'aurez pas besoin d'utiliser cette mthode sauf cas trs spcifiques. #Zend_Version ne contient qu'une seule mthode statique de comparaison de version. compare(): compare la version passe en paramtre, avec la version actuelle de Zend_Framework. Elle utilise version_compare() de PHP, elle renvoie cependant uniquement un String. Intressant noter, la constante Zend_Version::VERSION contient la version actuelle du Zend Framework (par exemple "1.8.3"). Ceci pourra tre utilis pour de la detction d'environnement par exemple.

- 10 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

IV - #Zend_Registry
Ce composant est issu du design pattern Registre. Le Registre est un pattern qui fournit un mcanisme de stockage de donnes, destin favoriser le mlange global des objets dans une application. C'est une alternative l'utilisation de variables globales. Le registre de ZF s'utilise de manire statique ou dynamique, nous utiliserons plutt les mthodes statiques. Le Framework l'utilise lui-mme en interne pour son mlange de donnes. set() et get() en sont les mthodes principales : Enregistrement d'un objet dans le registre
<?php $config = new Zend_Config_Ini('./ config.ini', 'database'); // $config reprsente un objet de configuration Zend_Registry::set('conf', $config);

Dans cet exemple, un objet de configuration (que nous verrons juste aprs) est cre et enregistr dans le registre sous le nom de 'conf', qui va nous servir rcuprer l'instance : Voiture.php

<?php class Voiture { public $marque; public $couleur; public function __construct() { $conf = Zend_Registry::get('conf'); $this->marque = $conf->voiture->marque; $this->couleur = $conf->voiture->couleur; } }

Dans cette classe, nous extrayons l'objet config du registre pour dfinir la couleur et la marque des voitures instances de Voiture. Ceci est trs avantageux, et nous permet d'crire un code portable, crit une fois, stock dans le registre, et utilis partout o il le faut. L'avantage par rapport une variable globale est qu'on n'est pas dpendant du nom d'une variable prcisment. Dans l'exemple ci-dessus, je peux tout moment changer le nom de la variable $config, la classe Voiture utilise le registre et non le nom de la variable directement, dclare ailleurs. Prcisons nouveau : le registre de ZF renvoie toujours la mme instance d'un objet (mais pas d'un tableau mme si ce cas d'utilisation est plus que rare). Ainsi, n'importe o dans un script : Rcupration d'un objet depuis le registre
<?php $conf = Zend_Registry::get('conf'); $conf->voiture->marque = 'une marque'

Ceci applique la modification sur $conf, l'unique instance dans le registre, et modifie donc l'objet partag 'conf'. Souvenez-vous, le registre est l dans le seul but de partager une info unique, entre tous les scripts. Il faudra veiller toutefois ne pas tout stocker dans le registre. En gnie logiciel, il faut garder absolument sous contrle la notion de dpendance (ou aussi de couplage) : le registre mlange tout, il faut l'utiliser bon escient et aussi rarement que possible. Prfrez toujours l'injection de dpendances : un programme se reposant trop sur un registre est intestable et inmaintenable. isRegistered() : Afin d'viter l'crasement accidentel d'objets, vous pouvez tester l'appartenance d'un objet au registre via cette mthode en lui passant directement l'objet en paramtre ; elle retourne TRUE s'il, FALSE sinon.

- 11 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

setInstance() est une mthode qui permet carrment d'implmenter son propre pattern Registre tendant Zend_Registry. Si votre application doit se brancher sur une structure comportant dj un registre, cette mthode permettra de l'utiliser. Zend_Registry est un composite : il auto gre sa(ses) propre(s) instance(s). Zend_Registry tend ArrayObject, de la SPL.

- 12 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

V - #Zend_Config
Tout le monde a un jour crit quelque chose comme cela : Exemple de configuration classique d'un site en PHP
<?php $db_host $db_name $db_user $db_pass ?> = = = = 'localhost'; 'name_of_database'; 'myname'; 'secret';

Sur de gros projets, cela ne tient plus la route et il devient difficile d'accder aux variables de configuration. Autre exemple de configuration classique d'un site en PHP
<?php $GLOBALS['config']['db_name'] = 'localhost'; ?>

Pourquoi pas. Mais dans un souci de portabilit, et afin de pouvoir tablir plusieurs configs pour plusieurs utilisateurs, par exemple, pourquoi ne pas extraire tout simplement la config dans un fichier de config part : config.ini ou config.xml ? Nul besoin alors d'crire du code pour parser ces fichiers, voyons le cas ini : Zend_Config_Ini permet de charger un fichier de configuration ini en utilisant la fonction PHP parse_ini_file(). Reportez-vous ce manuel pour crire vos fichiers ini, il existe quelques petites subtilits. Config.ini :
[database] username = foo password = bar hostname = localhost [voiture] marque = ma-marque-de-voiture couleur = vert

Avec ce fichier de configuration, le script suivant va encapsuler nos donnes dans un objet et nous les montrer : Utilisation de Zend_Config avec un fichier .ini

<?php $config = new Zend_Config_Ini('./config.ini'); echo $config->database->username . '-' . $config->database->password . '-' . $config->database>hostname; ?>

Le fichier de config ini est donc transform en class->proprits et, mieux encore, le parseur gre aussi l'hritage. Par exemple, un fichier de config unique, mais dont les paramtres sont crass, avec une gestion d'utilisateurs : Config.ini :
[database] name = database hostname = localhost [developers : database] name = dev-database username = developers password = dev-password [teamleaders : database] - 13 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Config.ini :

username = team-leaders password = tl-password

Chargement de sections diffrentes partir d'un fichier ini

<?php $config = new Zend_Config_Ini('./config.ini', 'developers'); echo $config->username . '-' . $config->name ; // developers - dev-database ?> <?php $config = new Zend_Config_Ini('./config.ini', 'teamleaders'); echo $config->username . '-' . $config->name ; // team-leaders - database ?>

me Ici, nous passons au constructeur le nom de la section charger comme 2 paramtre. "Developers : database" signifie que developers hrite des proprits de database. Il peut en redfinir d'autres ou craser les proprits parentes (hritage OO avec visibilit protected). Notez que le fait de charger une section fait entrer notre objet dedans. Nous pointons donc $config->leparamtre directement, et non plus $config->lasection->leparamtre. En revanche, l'objet $config reste en lecture seule, toute tentative d'affectation renvoie une Zend_Config_Exception. Il n'est donc pas possible de modifier un paramtre ini, depuis le framework par dfaut. Ce comportement peut tre me chang via une 3 option constructeur : Autoriser les modifications sur l'objet Zend_Config

<?php $config = new Zend_Config_Ini('./config.ini', null, true); $config->database->username = 'myUserName'; // autoris ?>

Notez qu'il n'est toutefois pas possible de sauvegarder l'objet vers le fichier Ini. Le fichier Ini est en lecture seule force, lui. De plus, getSectionName() retourne la section qui a t prcdemment charge, et areAllSectionsLoaded() retourne true si vous n'avez pas choisi de section dans votre constructeur (en passant null le paramtre de section). Zend_Config est un design pattern composite. Chaque section reprsente une instance de l'objet Zend_Config niche dans son pre. Les interfaces Countable et Iterator, de la SPL, sont utilises. Il s'agit de la reprsentation des donnes sous forme d'un arbre, chaque noeud est une branche l'extrmit de laquelle se trouve une feuille : la donne. Nous pouvons en plus des sections, crer un hritage avec le point '.'. Ce sparateur est modifiable. Config.ini :
[site] debug = 1 db.hostname = localhost log.writter = database [dev : site] [prod : site] debug = 0 db.hostname = mydbprod

Chargement de la section 'dev'


$config = new Zend_Config_Ini('./config.ini', 'dev'); - 14 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Chargement de la section 'dev'


echo $config->debug // 1 echo $config->db->hostname // localhost

Chargement de toutes les sections


$config = new Zend_Config_Ini('./config.ini'); echo $config->site->debug // 1 echo $config->prod->debug // 0 echo $config->site->db->hostname // localhost

Chargement de la section 'prod'


$config = new Zend_Config_Ini('./config.ini', 'prod'); echo $config->debug // 0

Zend_Config_Yaml et Zend_Config_Json sont aussi disponibles et lisent chacune respectivement des donnes au formats Yaml et Json.

- 15 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

VI - Zend_Cache
#Zend_Cache est un composant fort sympathique pour mettre tout un tas de donnes diverses et varies dans un cache. Il convient ds lors de dfinir un peu de vocabulaire. Une faade de cache, aussi appele en anglais (et dans la doc officielle) "frontend", reprsente le type de donnes que l'on veut pouvoir mettre en cache. Un support de cache, en anglais "backend", reprsente l'endroit dans lequel les donnes vont tre stockes. Le composant #Zend_Cache permet donc de lier une faade un support, et c'est ce couple l qui sera utilis. Concernant les faades, il est possible de mettre en cache :

- 16 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Diffrentes faades Zend_Cache


1 2 3 4 5 6

Zend_Cache_Frontend_Output : sortie standard Zend_Cache_Frontend_Function : rsultat de l'appel d'une fonction Zend_Cache_Frontend_Class : rsultat de l'appel des mthodes statiques d'une classe Zend_Cache_Frontend_File : fichier Zend_Cache_Frontend_Page : page HTTP complte Zend_Cache_Frontend_Capture : page HTTP complte avec intgration au modle MVC de ZendFramework

Toutes ces faades spcialises hritent d'une faade hautement gnrique : Zend_Cache_Core. Celle-ci fournit des mthodes bas niveau de gestion du cache, comme save(), load(), clean(), remove() ... Les supports eux, sont aussi nombreux :

- 17 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Diffrents supports Zend_Cache


1 2 3 4 5 6 7 8 9 10 11

Zend_Cache_Backend_File : stocke les donnes de cache dans un fichier Zend_Cache_Backend_Sqlite : stocke les donnes de cache dans SQLite Zend_Cache_Backend_Memcached : stocke les donnes de cache dans un serveur ou une ferme Memcache en utilisant l'extension ext/memcache Zend_Cache_Backend_LibMemcached : stocke les donnes de cache dans un serveur ou une ferme Memcache en utilisant l'extension ext/memcached Zend_Cache_Backend_Apc : stocke les donnes de cache dans le cache OPCode APC Zend_Cache_Backend_Xcache : stocke les donnes de cache dans le cache OPCode Xcache Zend_Cache_Backend_ZendServer : stocke les donnes de cache dans la distribution PHP intgre ZendServer Zend_Cache_Backend_ZendPlatform : stocke les donnes de cache dans le serveur d'application ZendPlatform Zend_Cache_Backend_TwoLevels : stocke les donnes de cache dans deux supports diffrents, en permettant la gestion de la bascule de l'un l'autre Zend_Cache_Backend_BlackHole : stocke les donnes de cache dans rien du tout : simulacre servant pour les tests Zend_Cache_Backend_Static : stocke les donnes de cache provenant de Capture dans des fichiers

Ce qu'il faut savoir, c'est que les supports bass sur les fichiers sont lents, mais par contre ils permettent souvent de stocker des quantits de donnes normes. A l'inverse, un support bas sur la mmoire vive (Memcached, APC, XCache, Sqlite dans certains cas) sont extrmement rapides, mais en gnral limits en capacit. L'utilisation de #Zend_Cache est donc plutt simple : Zend_Cache possde une mthode factory() qui va crer un cache, c'est dire une association entre une faade et un support. Il convient de les paramtrer, et la doc officielle dtaille trs bien tout cela.
<?php $bO = array(); $fO = array('lifetime' => 60, 'automatic_serialization' => true); $cache = Zend_Cache::factory('Core', 'APC', $fO, $bO);

Ce code cre un cache gnrique (qui va servir tout faire : Zend_Cache_Core), avec comme support de stockage : APC. APC ne ncessite aucune donne de configuration, nous passons un tableau vide en quatrime paramtre. Core ne ncessite aucune option, mais les paramtres par dfaut ne vont pas nous arranger. Nous passons donc 2 options : lifetime est trs importante : il s'agit de la dure de vie des infos dans le cache (en secondes). automatic_serialization indique Zend_Cache_Core de srialiser la donne de manire automatique si celle-ci le ncessite : par exemple un tableau ou un objet. Utilisation du cache

<?php // ... if (($donnees = $cache->load('mesdonnes')) === false) { $donnees = $db->findBigData(); $cache->save($donnees, 'mesdonnes'); }

Simplicit extrme : load() demande de charger des donnes stockes l'index "mesdonnes". Si cette mthode retourne false, alors c'est que les donnes n'taient pas prsentes dans le cache. Nous les rcuprons donc depuis un objet factice $db, puis nous n'oublions pas de les stocker dans les cache au bon index. Il existe des options de nettoyage et de taguage du cache qui sont trs pratiques et font de #Zend_Cache une solution souple et efficace dans son domaine. Enfin si vous devez grer plusieurs objets de cache (ce qui est souvent le cas), Zend_Cache_Manager saura alors mmoriser leurs informations respectives et vous fournir une passerelle simple vers les objets de cache stocks.

- 18 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

VII - #Zend_Validate
La scurit est un point que tout bon dveloppeur doit avoir en permanence l'esprit. Je ne vais pas faire un cours de scurit ici, mais juste vous parler des composants #Zend_Validate et #Zend_Filter qui agissent selon le mme modle, ils seront traits ensemble car possdent beaucoup de ressemblances. Zend_Validate est un conteneur de validateurs qui va permettre de crer des chanes de validateurs sur mesure, qui vont nous simplifier la vie face des situations courantes en dveloppement web. Un validateur est une fonction qui vrifie si une donne respecte un schma. Un filtre au contraire, modifie la donne selon un schma semblable. Je ne vais montrer que quelques exemples, mais l'API en ligne regorge d'autres mthodes sympathiques. On notera Zend_Validate_* { Alnum, Alpha, Between, Hostname, Int, Ip, Regex (...) } Nous pouvons crer des instances de chacun de ces validateurs et les utiliser individuellement, mais nous pouvons aussi les chaner dans Zend_Validate : On aura bien compris qu'un validateur va servir valider les donnes reues par l'utilisateur, c'est un composant de la catgorie scurit des applications web, dont on va pouvoir user et abuser, sa mthode principale est isValid(). Un validateur commence par retourner true, puis teste la valeur soumise travers sa classe et ses conditions, ds que l'une d'elle n'est pas remplie, son retour vaut false. Plutt que d'instancier un validateur chaque fois, et de lui soumettre isValid(), la mthode statique raccourcie is() peut s'avrer pratique pour un validateur prcis : Exemple d'utilisation basique de Zend_Validate
<?php $float = new Zend_Validate_Float(); $float->isValid(25.3); // true

//quivalent : Zend_Validate::is(25.3,'float'); //true

En premier paramtre, passez votre valeur, en deuxime paramtre, un string reprsentant le validateur (qui doit tre atteignable et lisible), le troisime paramtre sert pour les options du validateur. Lorsqu'un validateur retourne false : la donne n'est donc pas valide, des mthodes permettent de savoir pourquoi. getMessages() renvoie les messages d'avertissement que le validateur retourne, destins etre affichs. getErrors() lui, va renvoyer des codes d'erreurs, qui sont prsents sous forme de constantes dans la classe du validateur, ceux-ci ne sont pas destins tre affichs, mais permettre un traitement adquat de l'erreur, voyons ca : Exemple d'utilisation plus avance de Zend_Validate
<?php $validator = new Zend_Validate_Between(2,8); $value = 25;

if ($validator->isValid($value)) { echo "tout est bon"; } else { foreach ($validator->getMessages() as $message) { echo "$message\n"; } } // ce code affiche '25' is not between '2' and '8', inclusively

Nous demandons ici de valider la donne : la valeur doit tre comprise entre 2 et 8. Nous lui fournissons '25' et nous affichons les messages d'chec du validateur. Tous les validateurs ont des messages par dfaut, qui sont personnalisables par setMessages(). Etant donn qu'un validateur peut gnrer plusieurs messages, getMessages() retourne un tableau, qu'il faut donc passer via un foreach, par exemple.

- 19 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Changement des messages d'erreur dans Zend_Validate

<?php $validator = new Zend_Validate_Between(2,8); $validator>setMessages(array(Zend_Validate_Between::NOT_BETWEEN => "Attention '%value%' n'est pas compris inclusivement entr $value = 25; if ($validator->isValid($value)) { echo "tout est bon"; } else { foreach ($validator->getMessages() as $message) { echo "$message\n"; } } // ce code affiche Attention '25' n'est pas compris inclusivement entre '2' et '8'

Pour illustrer l'utilit de getErrors(), voici un petit exemple. Rappelons que getErrors() est similaire getMessages(), mais va servir effectuer un traitement spcial sur une condition d'chec du validateur en s'appuyant sur des constantes de classe. Par exemple, le validateur Digit vrifie que la chaine passe de contient bien que des chiffres, mais vrifie aussi si celle-ci n'est pas vide. Nous pouvons effectuer un traitement spcial dans ce cas : Exemple d'utilisation avance Zend_Validate
<?php $validator = new Zend_Validate_Digits(); $value = '';

if ($validator->isValid($value)) { echo "tout va bien"; } else { if ( in_array(Zend_Validate_Digits::STRING_EMPTY, $validator->getErrors()) ) { // traitement pour le cas o la chaine est vide

} else { // la chaine n'est pas vide, mais provoque un chec de validation : il ne s'agit donc pas que de chiffr foreach ($validator->getMessages() as $message) { echo "$message\n"; } }

Utilisons le principe de chanage des validateurs maintenant : nous avons toute une srie de validateurs individuels disposition, que nous ajouterons un validateur personnalis grce addValidator(). Lors de l'appel isValid(), tous les validateurs vont passer en revue la donne passe en paramtre, puis chacun crira dans un journal si oui ou non, son test est pass. On pourra rcuprer le journal aprs via getMessages(), pour affichage, ou getErrors() pour un traitement. Cration d'une chaine de validateurs

<?php $chaine = new Zend_Validate(); $chaine->addValidator(new Zend_Validate_Int()) ->addValidator(new Zend_Validate_GreaterThan(8)); if ($chain->isValid($data)) { // la donne est valide } else { // itration sur les messages d'erreur foreach ($chaine->getMessages() as $message) { echo "$message\n"; } } ?>

Dans notre exemple ci dessus, nous crons un validateur compos d'une chaine de validateurs individuels associs, qui vrifie si $data est un entier - suprieur 8.

- 20 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Dans le cas o notre donne n'est pas un entier, le validateur va tout de mme continuer sa chaine, et passer dans GreaterThan. Les validateurs sont utiliss dans leur ordre d'ajout la chaine de validation et getMessages() va alors retourner tous les messages d'echec : ceux de Int, et ceux de GreaterThan. Il est possible de lui spcifier de s'arrter de valider, ds qu'un des validateurs de la chaine choue, ceci grce un deuxime paramtre pour addValidator() : Cration d'une chaine de validateurs avec arrt en cas d'erreur sur un validateur
<?php $chaine = new Zend_Validate(); $chaine->addValidator(new Zend_Validate_Int(), true) // true en second paramtre ->addValidator(new Zend_Validate_GreaterThan(8)); if ($chain->isValid($data)) { // la donne est valide } else { // itration sur les messages d'erreur foreach ($chaine->getMessages() as $message) { echo "$message\n"; } } ?>

Dans l'exemple si dessus, nous avons mis true le deuxime paramtre pour addValidator() concernant le validateur Int. Ainsi, si notre donne ($data) n'est pas un entier, la chaine va crire le message d'echec de Int dans sont journal, puis va stopper, sans passer par GreaterThan, et les autres validateurs, si on en avait chain plus. Il est de mme possible d'crire ses propres validateurs, en implmentant Zend_Validate_Interface, et en rdfinissant les mthodes isValid(), getMessages() et getErrors(), par exemple nous souhaitons un mot de passe de 8 caractres minimum, avec au moins une lettre majuscule, une minuscule, et un chiffre : Cration d'un validateur personnalis

<?php class MyValid_PasswordStrength extends Zend_Validate_Abstract { const LENGTH = 'length'; const UPPER = 'upper'; const LOWER = 'lower'; const DIGIT = 'digit'; protected $_messageTemplates = self::LENGTH => "'%value%' self::UPPER => "'%value%' self::LOWER => "'%value%' self::DIGIT => "'%value%' ); public function isValid($value) { $this->_setValue($value); $isValid = true; if (strlen($value) < 8) { $this->_error(self::LENGTH); $isValid = false; } if (!preg_match('/[A-Z]/', $value)) { $this->_error(self::UPPER); $isValid = false; } if (!preg_match('/[a-z]/', $value)) { $this->_error(self::LOWER); $isValid = false; } if (!preg_match('/\d/', $value)) { array( doit avoir une longueur d'au moins 8 caractres", doit contenir au moins une lettre majuscule", doit contenir au moins une lettre minuscule", doit contenir au moins un chiffre"

- 21 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Cration d'un validateur personnalis


} }

$this->_error(self::DIGIT); $isValid = false;

return $isValid;

Nous allons tout de mme dire un petit mot du gros validateur que reprsente Zend_Validate_EmailAddress Zend_Validate_EmailAddress utilise Zend_Validate_Hostname pour au final permettre de vrifier si l'adresse email est bien forme et si la partie pseudonyme respecte la RFC2822. Concernant la partie domaine, il est vrifi si elle respecte la syntaxe d'un nom DNS du type nomdhote.org. Il est possible de rgler le filtre pour prendre en compte les adresses IP (et donc vrifier leur syntaxe), ou alors les noms de domaines locaux. Une fonction pour vrifier si le domaine accepte les Emails est prvue. Elle vrifie dans l'enregistrement du DNS la prsence d'un champ MX signifiant que le domaine est apte recevoir des emails.

- 22 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

VIII - #Zend_Filter
#Zend_Filter va se dcomposer en 2 grands paragraphes

VIII-A - Zend_Filter
#Zend_Filter est en tout point semblable #Zend_Validate l'exception qu'un filtre va transformer la donne selon son modle, et non pas juste vrifier qu'elle respecte ce modle. Zend_Filter est un conteneur de filtres qui va permettre de crer des chanes de filtres sur mesure. Nous pouvons crer des instances de chacun de ces filtres et les utiliser individuellement, mais nous pouvons aussi les chaner dans Zend_Filter : Utilisations banales de Zend_Filter

<?php $alpha = new Zend_Filter_Alpha(); echo $alpha->filter('Foo45Bar'); // 'FooBar' $balise = '<h1>balise</h1>'; $pasDeTag = new Zend_Filter_noTags(); echo $pasDeTag->filter($balise); // 'balise'

Chainage de filtres

<?php $chaine = new Zend_Filter(); $chaine->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_noTags()); $message = $chaine->filter($_POST['message']);

En plus des filtres dj incorpors dans le Framework, vous pouvez crire vos propres filtres en implmentant l'interface Zend_Filter_Interface. La seule mthode dfinir est filter() Si vous n'avez pas envie de charger une instance de la classe de votre filtre, et d'appliquer la mthode filter, vous pouvez passer par la mthode raccourcie get() de Zend_Filter, qui fonctionne sur le mme principe que is(), de Zend_Validate.

VIII-B - Zend_Filter_Input
Zend_Filter_Input en revanche, se voit reserv un paragraphe complet. Il mle #Zend_Validate et #Zend_Filter, qui sont trs semblables en fonctionnement, afin de fournir un moyen de valider/filtrer les donnes d'entre d'un script, typiquement on pensera $_GET et $_POST. On cre une instance d'Input, une 'boite' ou 'box', compose la fois de validateurs, et de filtres, puis nous passons nos variables d'entre l'interieur, pour rcuprer des variables saines en sortie. Le plan est donc : Dclarer des rgles de validation et de filtrage - Crer une instance Zend_Filter_Input avec les rgles prcdemment dfinies - Passer les donnes dans cette moulinette - Rcuprer les donnes saines, et ventuellement les messages d'erreur. chainage de filtres ET de validateurs sur un tableau d'entres
<?php $filters = array( 'nom' => 'StringTrim' );

$validators = array( 'nom' => 'Alpha', 'annee' => array( 'Int', array('Between', 1900, 2000) ) );

- 23 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

chainage de filtres ET de validateurs sur un tableau d'entres

$box = new Zend_Filter_Input($filters,$validators); $box->setData($_GET); // filtrage et validation de toute l'entre GET if ($box->isValid()){ echo "tout est OK"; }else{ Zend_Debug::dump($box->getInvalid()); } ?>

setData() s'applique sur sur notre "boite", instance de Zend_Filter_Input, et lui spcifie quelle est la donne d'entre analyser. Notez bien que chaque rgle crite dans les validateurs et les filtres, est un tableau dont la cl doit reprsenter le nom de la variable analyser, la valeur reprsente une chaine pelant le nom du validateur/filtre appliquer, on peut aussi fournir une instance personnalise. Nous aurions pu utiliser la syntaxe quivalente $box = new Zend_Filter_Input($filters,$validators,$_GET); aussi getInvalid() retourne les problmes rencontrs par le validateur. Les filtres eux ne rencontrent pas de problme, ils appliquent leur(s) filtre(s), btement, aux variables. http://monserveur/monscript.php?nom=john&annee=1998
Tout est OK

http://monserveur/monscript.php?nom=j1o2h3n&annee=2008
array(2) { ["nom"] => array(1) { [0] => string(46) "'j1o2h3n' has not only alphabetic characters" } ["annee"] => array(1) { [0] => string(52) "'2008' is not between '1900' and '2000', inclusively" } }

Notez que les filtres sont d'abord appliqus sur les valeurs, puis les validateurs passent derrire. Il n'est donc pas necessaire, et dconseill, d'appliquer le filtre Zend_Filter_HtmlEntities sur les entres, car celui-ci pourrait fausser le jugement des validateurs qui passent aprs Le filtre Zend_Filter_HtmlEntities est de toute faon appliqu en fin de traitement automatiquement, la rcupration des valeurs se fait par un accesseur, sinon par getUnescaped(). http://monserveur/monscript.php?nom=j%9Ej%9E
<?php $filters = array( 'nom' => 'StringTrim' ); $validators = array( 'nom' => 'NotEmpty', ); $box = new Zend_Filter_Input($filters,$validators); $box->setData($_GET); echo $box->nom // j&eacute;j&eacute; echo $box->getEscaped('nom') // idem echo $box->getUnescaped('nom') // jj ?>

Ici j'ai spcifi que je veux juste que ma variable 'nom', contenu dans mon tableau $_GET, soit non vide. Je lui passe volontairement des caractres spciaux, comme '' (%9E), qui seront convertis automatiquement par Zend_Filter_Input, aprs y avoir fait pass les filtres d'abord, et les validateurs ensuite. On comprend ainsi que si

- 24 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

j'avais voulu passer du Zend_Filter_HtmlEntities en filtre, mon validateur passant aprs les filtres aurait pu tre troubl dans son jugement, qu'il aurait port sur une variable dja modifie. Vous pouvez changer le filtre d'echappement si celui-ci (htmlentities) ne vous convient pas, ce qui sera cependant rarement le cas. Procdez avec setDefaultEscapeFilter() : Modification du filtre final d'chappement
<?php $filters = array( 'nom' => 'StringTrim' ); $validators = array( 'nom' => 'NotEmpty', ); $box = new Zend_Filter_Input($filters,$validators); $box->setData($_GET); $box->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); ?>

Dernier rappel : Zend Framework echappe automatiquement (par dfaut avec Zend_Filter_HtmlEntities) les donnes, une fois celles-ci d'abord filtres, puis valides. Ce n'est pas termin, car d'autres options toutes aussi agrables, viennent complter la classe Zend_Filter_Input. Par exemple la clause spciale note *, qui permet d'appliquer un filtre toutes les valeurs contenues dans une entre (typiquement, nous traitons $_GET ici): Toutes les variables passeront par le filtre StringTrim
<?php $filters = array( '*' => 'StringTrim' );

En plus de getInvalid(), qui nous renvoie un tableau avec pour cl la variable qui a caus un echec d'un des validateurs, et pour valeur, le message de cet echec, nous avons d'autres mthodes : getUnknown() nous renvoie les champs qui sont prsents dans la requte, mais qui n'ont pas t prvus dans une des rgles. Logiquement donc : des champs injects : Traitement des champs superflus ou additonnels
<?php $filters = array( 'adresse' => 'StringToLower' ); $validators = array( 'adresse' => 'NotEmpty', ); $box = new Zend_Filter_Input($filters,$validators); $box->setData($_GET); echo $box->adresse; if ($box->hasUnknown()){ Zend_Debug::Dump($box->getUnknown()); } ?>

Si j'interroge ce script via http://monserveur/cescript.php?adresse=Abc&uneinjection=injection , alors j'obtiens cette sortie : http://monserveur/cescript.php?adresse=Abc&uneinjection=injection


<?php abc // ok, mon filtre StringToLower a t appliqu

- 25 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

http://monserveur/cescript.php?adresse=Abc&uneinjection=injection
array(1) { ["uneinjection"] => string(9) "injection" }

hasUnknown() renvoie true si un champ a t inject, et getUnknown() renvoie un tableau contenant les variables injectes dans le script (par $_GET ici) De la mme manire hasMissing() et getMissing() existent aussi, pour spcifier cette fois le contraire : si des champs on t prvus dans les rgles, mais n'apparaissent pas dans la variable d'entre filtre. Cependant, par dfaut, Zend Framework ne les traite que si on le lui spcifie, via une constante de classe, et la valeur 'required' : Traitement des champs requis, mais absents dans le tableau d'entre
<?php $filters = array( 'adresse' => 'StringToLower' );

$validators = array( 'adresse' => array('NotEmpty', Zend_Filter_Input::PRESENCE => 'required' ) ); $options = array(Zend_Filter_Input::MISSING_MESSAGE=>'Le champ %field% est requis par la rgle %rule %, mais n\'est pas fournit'); $box = new Zend_Filter_Input($filters,$validators,$_GET,$options); if ($box->hasMissing()){ Zend_Debug::Dump($box->getMissing()); } ?>

Intrrog sans fournir de paramtre 'adresse', ce script va nous renvoyer :


array(1) { ["adresse"] => array(1) { [0] => string(71) "Le champ adresse est requis par la rgle adresse, mais n'est pas fournit" } }

Nous avons utilis une variable $options pour passer un message d'erreur que notre classe Zend_Filter_Input devra nous retourner, comme dja vu. Notez que ce paramtre est le 4me paramtre de l'instanciation de la classe, le 3me reprsentant les donnes passer dans la boite. Attention, ceci est utilis pour la mtacommande 'required', si vous voulez personnaliser chaque message d'erreur de chaque validateur, procdez comme suit : La mtacommande 'messages', permet de personnaliser les messages d'erreurs, elle se fournit via un tableau index dont la cl reprsente le numro du validateur, relativement sa position d'insertion : Utilisation de la mtacommande 'messages'
<?php $filters = array( 'adresse' => 'StringToLower' );

$validators = array( 'adresse' => array('NotEmpty', new Zend_Validate_StringLength(10), 'messages' => array(0=>'Le champ adresse est vide', // validateur d'index 0 : NotEmpty

- 26 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Utilisation de la mtacommande 'messages'


1=>'Le champ adresse doit faire 10 caractres' // validateur d'index 1 : StringLength ) ) ); $box = new Zend_Filter_Input($filters,$validators,$_GET); ?>

D'autres mtacommandes sont encore disponibles. Mme si cette classe semble un peu complexe (nombreux tableaux imbriqus), elle suit videmment une logique qu'il suffit de capter (un peu d'entrainement et c'est bon), et elle s'avre non pas pratique, mais indispensable.

- 27 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

IX - #Zend_Db IX-A - Introduction


Ce composant est bien entendu d'une importance extrme. Il rgit toute la couche d'abstraction aux bases de donnes. C'est la partie du tutoriel la plus longue car elle dtaille, dans un cas prcis mais quelque peu commun (MySQL, via PDO), les diffrents cheminements des objets dans la jungle que reprsente #Zend_Db. Ce composant traite en effet plusieurs classes et plusieurs manires d'aborder la base de donnes. Il y a les couches d'accs, les aides aux requtes, les conteneurs de rsultats (Rows), les jeux de rsultats (Rowsets) pour le TDG ( Table Data Gateway) et la gestion des relations entre les tables.

Il est donc possible d'excuter des requtes simples, manuelles, de bien des faons diffrentes, ou alors de traiter des requtes prpares, des transactions ; si bien qu'on a tendance tre un peu perdu au dbut et que des coups d'oeil frquents l'API s'imposent. Je vais donc m'efforcer de dtailler le coeur du composant, le parcours des classes et les mthodes rsultantes sur les objets instancis. #Zend_Db est compos d'un Adaptateur qui permet de se connecter un type de base. Il est possible de passer par PDO, ou non. Je conseille, lorsque c'est possible (PDO est activ dans les dernires distrib de PHP, mais les drivers ne sont pas forcment prsents ou activs sur les serveurs) d'utiliser PDO, car il s'agit de l'interface de branchement de PHP (Php Data Object), et l'extension PDO demeure trs puissante pour piloter un SGBD. Seuls MySQLi, Oracle et DB2 sont disponibles hors PDO pour Zend_Framework, mais il existe des bibliothques (non officielles) pour d'autres SGBD. De notre cot, nous parlerons de MySQL via PDO, vous devez donc possder l'extension PDO active sur votre serveur, mais c'est la configuration courante de PHP depuis PHP5.1. Vous devez aussi possder le driver PDO de votre SGBD, je vous renvoie la doc sur PDO pour plus d'info : certains drivers sont disponibles dans les binaires PHP depuis PHP 5.1, d'autres sont tlchargeables sur PECL. Nous ne traiterons donc ici que de MySQL sous PDO ; de ce fait, il faudra activer le driver PDO_MYSQL dans php.ini si vous tes sous Windows. Sous Linux, il faudra prendre soin de compiler PHP avec PDO et le driver Mysql. Il est conseill aussi ceux qui ne sont pas l'aise avec PDO, de s'y mettre :-) Un petit tour sur la doc officielle, par exemple... Chaque SGBD possde sa propre couche d'abstraction, mais la manipulation de #Zend_Db est quasiment la mme, quelque soit le SGBD utilis. Le systme complexe de #Zend_Db est bas sur de multiples hritages de mthodes. Ainsi, lorsqu'on veut se connecter via un driver, cela cre un objet qui hrite de mthodes gnrales, puis les mthodes propres au driver sont rajoutes ou bien redfinissent les mthodes gnrales. Il en rsulte donc tout un arsenal de mthodes disponibles. Tous les rsultats (Statements) sont grs par Zend_Db_Statement, les rsultats PDO le sont par Zend_Db_Statement_PDO, l encore, via la POO, tout est redfini, factoris et hrit. Les Exceptions envoyes sont des instances de Zend_Db_Adapter_Exception Notez qu'un profiler, Zend_Db_Profiler, est aussi de la partie et permet de faire du profiling sur sa base. Le profiling est l'action d'couter l'tat de sa base lors de requtes et notamment de dterminer le temps d'excution de chaque requte, le nombre de requtes effectues, et ainsi d'optimiser au mieux l'interfaage de votre application avec votre base de donnes, de manire faire en sorte que celle-ci ne devienne pas un goulot d'tranglement pour votre application. Nous ne dtaillerons pas le profiling dans ce tutoriel. Les adaptateurs qui composent #Zend_DB utilisent le profiler Zend_Db_Profiler en interne. Celui-ci n'est pas activ par dfaut car il consomme un peu de ressources pour ses calculs. L'activer est trs simple. Un autre objet Zend_Db_Profiler_Firebug existe aussi : il envoie ses rsultats dans FireBug.

#Zend_Db est le composant principal, il est compos de :


Zend_Db Zend_Db_Adapter (Zend_Db_Profiler) non trait

- 28 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Zend_Db_Select Zend_Db_Expr (Zend_Db_Statement) peu utilis de manire directe Zend_Db_Table(_Abstract) Zend_Db_Table_Row(_Abstract) Zend_Db_Table_Rowset(_Abstract) Zend_Db_Table_Select

Zend_Db ne comporte qu'une mthode : une fabrique d'objets de connexion Factory(). Le design Pattern AbstractFactory est utilis, il est trs classique et trs simple. Utilisation de la fabrique de Zend_Db pour crer un adaptateur
<?php $params = array ('host' => '127.0.0.1', 'username' => 'developper', 'password' => 'mypassword', 'dbname' => 'myapp'); $db = Zend_Db::factory('PDO_MYSQL', $params); ?>

$db est donc votre objet de plus bas niveau d'interfaage avec votre base. Vous verrez par la suite que nous n'utiliserons quasiment plus que des objets de plus haut niveau, mais il faut aborder les tapes dans l'ordre ;-) Utilisation de la fabrique de Zend_Db conjointement avec un objet Zend_Config
<?php $config = new Zend_Config_Ini('config.ini'); $db = Zend_Db::factory($config->database);

config.ini
[app] database.adapter database.params.host database.params.username database.params.password database.params.dbname = = = = = pdo_mysql 127.0.0.1 developper mypassword myapp

Voyez comme Zend_Db joue avec Zend_Config. Trs souvent dans ZendFramework, un objet Zend_Config pourra tre pass un autre objet. $db est donc un objet qui, au passage, s'est vu dot des mthodes de Zend_Db_Adapter_Abstract, puis Zend_Db_Adapter_Pdo_Abstract, pour finir en une instance de la classe Zend_Db_Adapter_Pdo_Mysql. Voyez comme l'architecture interne de ZF a t dveloppe de manire souple et adaptable : nous passons sous 3 couches pour obtenir un objet connexion de bas niveau. Il faut dire qu'il existe un tas de SGBD diffrents, et ceux-ci ont la fcheuse tendance diffrer quelque peu au niveau des mthodes des drivers. ZF fait donc son boulot comme il faut : le dveloppeur n'a que faire de ce qu'il se passe dessous. Attention toutefois, lors de la cration de l'objet $db, la fabrique ne teste pas si la connexion a russi. La connexion ne s'effectue que lors de l'appel d'une requte, ce qui peut tre gnant. En gnral, on aime bien lorsqu'on cre une connexion, la tester. Et ne pas attendre de balancer une requte pour s'apercevoir que la base n'est pas disponible, que l'on n'a mal orthographi ses identifiants, que l'on n'a pas les bons droits... Autant tout de suite le savoir. Nous avons pour cela sous la main une mthode hrite de Zend_Db_Adapter_Abstract, getConnection(). Elle effectue une connexion, puis retourne l'identifiant de connexion PDO (dont nous n'avons pas besoin en ralit) Rappel de scurit : il faut stocker ses identifiants d'accs aux bases de donnes dans des fichiers HORS de la racine web. Essai explicite de la connection
<?php // $params = array(...);

- 29 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Essai explicite de la connection

try { $db = Zend_Db::factory('PDO_MYSQL', $params); $db->getConnection(); } catch (Zend_Db_Adapter_Exception $e){ echo $e->getMessage(); }

Ici, nous capturons et affichons une ventuelle Exception provenant de l'adaptateur gnrique. Nous pourrions par exemple voir : SQLSTATE[28000] [1045] Access denied for user 'developer'@'localhost' (using password: YES) ou tout autre message nous signalant un problme (driver PDO introuvable, extension PDO non compile, etc.) Je ne dtaille pas le schma de la base de donnes, ca sera fait plus tard. Les requtes sont lmentaires, et ne concernent ici qu'une seule table. Ce qu'il faut noter, ce sont les mthodes utilises, et la prsentation des rsultats. Notre connecteur tant configur, excutons une requte simple :

IX-B - Requtes simples


query() prpare une requte et l'excute pour retourner un rsultat issu de Zend_Db_Statement, dans notre cas c'est un Zend_Db_Statement_PDO : Utilisation de la mthode query() pour requter un SGBD
<?php // ... configuration de $db comme vu avant ... $result = $db->query('SELECT num, nom FROM membres');

$result est un objet de la classe Zend_Db_Statement_PDO. Si vous utilisiez PDO auparavant, vous ne serez pas dboussol ; si ce n'est pas le cas, je vous conseille quand mme un petit tour sur le manuel PHP, rubrique PDO. Ceci au regard de la suite de ce tutoriel, concernant notamment les diffrents 'fetch_modes' (modes de captures de rsultat) qu'offre PDO. Dans le cadre de l'utilisation de ZF, il n'est en thorie pas ncessaire de toucher aux fetch_modes de PDO, car c'est ZF qui va s'en charger quand ca sera ncessaire. Vous pouvez toutefois spcifier un mode de capture via la mthode setFetchMode() sur l'objet $db. Les modes PDO suivants sont accepts : PDO::FETCH_{LAZY - ASSOC - NAMED - BOTH - NUM - OBJ}, le reste ne l'est pas : ceci est un choix de l'quipe de dveloppement car le Framework risque de ne pas tre compatible avec. Leur utilisation lvera donc systmatiquement une exception, il est conseill de ne pas se soucier du tout des fetch_mode bas niveau de PDO, et d'utiliser plutt les mthodes de capture que Zend Framework propose : c'est lui qui va piloter PDO pour vous, si vous utilisez un cas trs particulier, vous pouvez toujours redfinir des mthodes et crer votre propre interfaage avec le SGBD. Nous pouvons appliquer la mthode fetchAll() sur le rsultat : Utilisation de mthodes de Zend_Db_Statement
<?php $rows = $result->fetchAll(); ?> $rows est de la forme : array(2) { [0] => array(2) { ["num"] => string(1) ["nom"] => string(3) } [1] => array(2) { ["num"] => string(1) ["nom"] => string(3) } }

"1" "Foo" "2" "Bar"

- 30 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

A peu prs toutes les mthodes de la classe PDOStatement sont applicables sur les rsultats, fetchObject(), fetch(), fetchColumn()... Ce genre de requte tant rare, voyons une requte avec un WHERE, chapp comme il se doit :
<?php $name = "foo's name"; // notez la simple quote $sql = $db->quoteInto('SELECT * FROM members WHERE name = ?', $name); //$sql est la requte chappe, c'est un string, on peut l'echo $result = $db->query($sql); $data = $result->fetchAll();

La mthode quoteInto() s'applique sur l'objet de bas niveau $db et retourne la requte (non le rsultat) en chappant les caractres avec la mthode propre au SGBD utilis, nul besoin de s'en soucier. $sql = "SELECT * FROM members WHERE name = 'foo\'s name'"; Pour echapper un simple terme, utilisez quote():
<?php $name = $db->quote("l'echappement"); // l\'echappement

quoteIdentifier() va servir echapper un nom de colonne, ou de table, ayant une valeur ambigue pour le SGBD, comme "order", ou "select" quoteColumnAs() fait la mme chose, mais en spcifiant un alias SQL :
<?php $order = $db->quoteIdentifiers("order"); // `order` $column = $db->quoteColumnAs("order", "o"); // `order` AS `o`

Voyez la backquote ajoute. C'est le caractre d'chappement spcial de Mysql pour sa syntaxe. Pour obtenir sa valeur, getQuoteIdentifierSymbol() est l. Il est de mme possible, et c'est plus courant, d'envoyer une requte directement via query(), en envoyant plusieurs paramtres :
<?php $name = "foo's name"; $result = $db>query('SELECT * FROM membres WHERE nom = :nom AND country = :pays', array('nom'=>'Julien', 'pays'=>'France')); $data = $result->fetchAll(); ?>

Les donnes sont automatiquement chappes ici. query() prpare la requte puis l'excute pour retourner un jeu de rsultats. Dans le cas o l'on souhaite conserver sa requte et profiter pleinement du mcanisme des requtes prpares, il est possible de prparer ses requtes manuellement avec prepare() et ses amies, adeptes de PDO ou de mysqli, c'est le mme mcanisme : Ici la requte est prpare, mais utilise tout de suite, ceci est donc exactement quivalent query(), qui prpare ses requtes avant des les envoyer :
<?php $sql = $db->prepare('SELECT * FROM membres WHERE nom = :name'); $sql->bindValue('name', 'Estelle'); $sql->execute(); $result = $sql->fetchAll();

IX-C - Rcupration de rsultats


Bon, ceci est un peu long, c'est dcompos en 2/3 tapes : on prpare optionnellement la requte, on l'excute et on capture le jeu de rsultats sur lequel nous appliquons une mthode de rcupration (fetch***).

- 31 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Il est possible de relier les 4 tapes en 1 seule, et ce via 6 mthodes qui vont toutes prparer, chapper les paramtres, excuter la requte et rcuprer le jeu de rsultats. La seule diffrence entre elles est la manire de rcuprer ce jeu de rsultats. Elles excutent directement une requte et retournent un jeu de rsultats format de manire concrte. Selon la situation, on choisira une mthode plutt que l'autre et elles sont toutes adaptes des situations courantes du dveloppement web. Ces mthodes s'utilisent donc directement avec l'objet $db. Imaginons une table qui n'aurait que 2 enregistrements. Il est important ici de noter la forme du rsultat, le nombre de dimensions des tableaux de retour, les cls et les valeurs : fetchAll() renvoie tous les rsultats sous forme d'un tableau 2 dimensions :
<?php $result = $db>fetchAll('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France'); ?> // $result contient : array(2) { [0] => array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo" } [1] => array(2) { ["id"] => string(1) "2" ["name"] => string(3) "Bar" } }

fetchRow() renvoie le premier rsultat trouv sous forme d'un tableau 1 dimension :
<?php $result = $db>fetchRow('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France'); ?> array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo" }

Notez qu'on ne peut plus accder aux rsultats suivants aprs, utilisez cette mthode lorsque vous savez pertinament qu'un seul rsultat vous sera retourn (recherche par cl primaire). fetchOne() renvoie la valeur du premier rsultat trouv :
<?php $result = $db>fetchOne('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France'); ?> string(1) : 1

1 est le numro id du premier membre dont le pays est 'France'. Il est donc inutile de slectionner plusieurs champs avec fetchOne(), seul le premier champ du premier rsultat est retourn, il en rsulterait un gaspillage de ressources. fetchCol() renvoie tous les rsultats sous forme de tableau 1 dimension ne comportant que les valeurs de la premire colonne :
<?php $result = $db>fetchCol('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France'); ?> array(2) { - 32 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog) [0] => string(1) "1" [1] => string(1) "2"

"1" et "2" sont les id des membres dont le pays est 'France'. Ici aussi, inutile de vouloir slectionner plusieurs colonnes, seule la premire est renvoye. fetchAssoc() renvoie tous les rsultats sous forme d'un tableau 2 dimensions dont la cl de dimension 1 est le rsultat du premier champ :
<?php $result = $db>fetchAssoc('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France')); ?> // $result contient : array(2) { [1] => array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo" } [2] => array(2) { ["id"] => string(1) "3" ["name"] => string(3) "Bar" } }

Presque identique fetchAll(), fetchAssoc() cre un tableau associatif. Changeons un peu la requte :
<?php $result = $db>fetchAssoc('SELECT name, id, country FROM membres WHERE country = :country', array('country'=>'France'); ?> // $result contient : array(2) { ["Foo"] => array(3) { ["name"] => string(3) "Foo" ["id"] => string(1) "1" ["country"] => string(6) "france" } ["Bar"] => array(3) { ["name"] => string(3) "Bar" ["id"] => string(1) "2" ["country"] => string(6) "france" } }

Enfin, fetchPairs() renvoie tous les rsultats sous forme d'un tableau 1 dimension dont la cl est la donne de la premire colonne et la valeur est la donne de la 2me colonne :
<?php $result = $db>fetchPairs('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France'); ?> // $result contient : array(2) { [1] => string(3) "Foo" [2] => string(3) "Bar" }

Il est inutile de vouloir slectionner plus de 2 colonnes. La premire colonne donnant la cl du tableau dans le rsultat, il faut que ca soit une cl primaire de table, sinon le tableau va tre cras par les donnes suivantes satisfaisant la requte :
<?php

- 33 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog) $result = $db>fetchPairs('SELECT country, name FROM membres WHERE country = :country', array('country'=>'France'); ?> // $result contient : array(2) { ["France"] => string(3) "Bar" // crasement du rsultat pour name='Foo' }

Ces 6 mthodes s'adaptent donc des situations du web et vous permettent de choisir la manire dont le rsultat doit vous tre prsent. Si aucun rsultat ne correspond la requte, le retour est une identit FALSE, c'est--dire qu'en castant le retour en bool, on obtient FALSE. Ainsi, si une chane doit tre retourne, le boolen FALSE est renvoy sa place, mais si un tableau multidimensionnel doit tre retourn, un tableau vide une dimension est retourn (ce qui est quivalent en identit FALSE). Mmorisez bien : Ces 6 mthodes executent ET rcuprent le rsultat (chacune sa manire), en une seule opration. Si vous voulez dcomposer, pour pouvoir "fetcher" vous mme, dans un while, par exemple, utilisez alors la syntaxe vue plus haut, base de query().

IX-D - Insert, Update et Delete


Nous allons dsormais tenter l'insertion, la mise jour ou l'effacement de donnes. Nous allons commencer crire de moins en moins de syntaxe SQL et, pour rester clair, les noms des variables sont explicites. De cette manire, je n'cris pas la requte SQL relle mais elle va se deviner trs facilement, mme si elle peut paraitre idiote dans sa smantique SQL, c'est pour le principe : insert() insre des donnes dans une table, elle prend 2 paramtres : insertion de donnes
<?php $rows = array ( 'name' => 'David', 'country' => 'England', ); $table = 'membres'; $affectedRows = $db->insert($table, $rows); $idInsere = $db->lastInsertId(); ?>

Les donnes sont chappes automatiquement. La valeur de retour est le nombre de lignes affectes. De mme, lastInsertId() retourne le numro identifiant de la dernire insertion, si celle-ci est une colonne auto incrmente, comme c'est le cas trs souvent des cl primaires, souvent aussi nommes "id". update() met jour des donnes dans une table, elle prend 3 paramtres : Mise jour de donnes
<?php $set = array ( 'country' => 'france', ); $table = 'membres'; $where[] = 'name = David'; $where[] = 'country = England'; $affectedRows = $db->update($table, $set, $where); ?>

- 34 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Les donnes du SET sont chappes automatiquement, mais c'est vous d'chapper le WHERE si c'est ncessaire. La valeur de retour est le nombre de lignes affectes. la clause WHERE est mise dans un tableau, si il y a plusieurs arguments comme c'est le cas ici, un AND est automatiquement effectu. Enfin, delete() supprime des enregistrements dans une table, elle prend 2 paramtres : Suppression de donnes
<?php $table = 'membres'; $where = $db->quoteInto('name = ?', 'Foo'); $deletedRows = $db->delete($table, $where); ?>

Vous devez chapper le WHERE si ncessaire. La valeur de retour est le nombre de lignes affectes (supprimes ici). N'oubliez pas la clause WHERE, sinon toutes les donnes seront supprimes ;-) Ca reste du SQL n'est-ce pas. describetable() effectue une syntaxe SQL similaire et retourne un tableau. listTables() retourne un tableau avec la liste des tables. Autres fonctionnalits
<?php $db->describeTable('test'); /* array(2) { ["id"] => array(14) { ["SCHEMA_NAME"] => NULL ["TABLE_NAME"] => string(4) "test" ["COLUMN_NAME"] => string(2) "id" ["COLUMN_POSITION"] => int(1) ["DATA_TYPE"] => string(9) "mediumint" ["DEFAULT"] => NULL ["NULLABLE"] => bool(false) ["LENGTH"] => NULL ["SCALE"] => NULL ["PRECISION"] => NULL ["UNSIGNED"] => NULL ["PRIMARY"] => bool(true) ["PRIMARY_POSITION"] => int(1) ["IDENTITY"] => bool(true) } ... ... */ $db->listTables(); /* array(5) { [0] => string(8) "messages" [1] => string(7) "membres" [2] => string(4) "test" [3] => string(5) "test2" } */?>

IX-E - Transactions
Un petit mot sur la gestion des transactions, tout de mme. Ici on est en surcouche de PDO, donc toutes ses caractristiques s'y appliquent. Les transactions existent quel que soit le SGBD pilot, car mme s'il ne les supporte pas, lui, ou le moteur de stockage de la table intrroge; PDO les mulera. C'est une des caractristiques sympathiques de PDO. D'origine, le mode 'autocommit' est activ dans l'adaptateur, qui transmet donc cet tat PDO ; cela signifie que toute requte envoye au SGBD est systmatiquement valide. Bien entendu, pour utiliser les transactions, votre SGBD et votre moteur de stockage doivent pouvoir les grer. C'est le cas d'INNODB pour MySQL mais pas de MyISAM.
- 35 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Si vous utilisez MyIsam, tout se passera comme si les transactions n'existaient pas, mais pas de message d'erreur : PDO mule les mthodes relatives aux transactions, il les fait exister mais elles ne peuvent fonctionner que si cot SGBD, tout est OK beginTransaction() Dsactive l'autocommit et dmarre une transaction commit() Valide la transaction courante et ractive l'autocommit rollback() Annule la transaction courante et ractive l'autocommit Trs simple, un exemple : Exemple d'utilisation des transactions
<?php $rows = array ( 'name' => 'John', 'country' => 'USA', );

$table = 'membres'; $db->beginTransaction(); try { $db->insert($table, $rows); $db->commit(); }catch(Zend_DB_Adapter_Exception $e) { $db->rollback(); echo $e->getMessage(); } ?>

Notez que les noms des 3 mthodes proposes par Zend Framework concernant les transactions sont les mmes que celles proposes par PDO dans PHP.

IX-F - Slections
Et maintenant, nous allons voir grce Zend_Db_Select comment effectuer des requtes complexes (jointures, prdicats, etc.) sans crire la moindre syntaxe SQL. Cependant, la rigueur reste de mise. Zend_Db_Select va permettre d'crire la syntaxe d'une requte SQL, manire objets, en s'affranchissant du SGBD utilis en dessous : l'adapter va convertir la syntaxe objet en une syntaxe comprhensible pour le SGBD (car je rappelle que tous les SGBD ne respectent pas forcment la norme SQL, et une syntaxe SQL [manuelle] peut donner lieu a des erreurs sur un SGBD, mais pas sur un autre). En plus d'apporter cet avantage, lorsqu'il s'agit d'crire des requtes la vole, vous allez voir que c'est bien plus simple de manipuler un objet, avec toutes ses mthodes pratiques. En effet, Zend_Db_Select est dite interface 'fluent' : chaque mthode exprime de par son orthographe, ce qu'elle fait. Et chaque mthode retourne $this, donc on peut flcher et chainer les mthodes les unes la suite des autres. Essayons un "SELECT id, name FROM membres WHERE country = 'usa' ORDER BY name ASC LIMIT 2" (syntaxe SQL pour MySQL - notre cas donc -). select() permet d'crire une requte de slection complte, en utilisant un pourcentage infirme de langage SQL. Elle permet aussi l'chappement automatique des caractres, elle gre tous les SGBD que gre l'Adapter, elle va traduire notre requte faon objet en requte SQL compatible avec le SGBD interrog via l'Adapter. Exemple de requtage de manire objet avec Zend_Db_Select

<?php $select = $db->select(); // rcupration de notre objet de Zend_Db_Select // quivalent $select = new Zend_Db_Select($db); $select->from('membres',array('id','name')); $select->where('country = ?','usa'); $select->order('name ASC'); $select->limit(2); $result = $db->fetchAll($select); ?>

- 36 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Bien entendu, les jointures sont possibles. En voici un exemple trs simple (2 tables) : Zend_Db_Select : jointures

<?php $select = $db->select(); $select->from('messages','message_txt') ->join('membres','membres.id=messages.membreid','name') ->where('messages.id = :idmess'); $result = $db->fetchAll($select, array('idmess'=>2) ); ?>

"SELECT message_txt, name FROM messages JOIN membres ON membres.id=messages.membreid WHERE messages.id = '2'" C'est la traduction MySQL. C'est tout simple, j'ai chang aussi la manire d'interroger la base avec un binding, comme nous l'avons vu aupravant (le ':idmess'). C'est le cas le plus pratique, car il permet de passer la valeur lors de l'excution de la requte et non dans son corps. On peut effectuer tout type de jointure, joinLeft(), joinRight(), joinFull(), joinCross(), joinNatural(). Les jointures par dfaut rcuprent *, mais on peut bien entendu les monter comme on le souhaite, de manire trs propre. La doc officielle vous y aidera. Les valeurs externes passes dans un select() sont toutes chappes automatiquement, pour viter l'chappement automatique, la classe Zend_Db_Expr permet de former une variable de clause non echappe. Pour effectuer un SELECT FOR UPDATE (spcifique Mysql), la mthode forUpdate() est l. La mthode select() cre un objet Zend_Db_Select qui retourne lui-mme, chaque modification, ce qui nous permet d'enchaner les actions par de multiples -> se succdant. Zend_Db_Select possde de mme une mthode magique __toString(), qui permet d'afficher la requte textuelle traduite par l'Adapter, par un simple <?php echo $select;?>. Utilisez-la pour bien voir comment la requte a t traduite (tout est chapp, les colonnes sont traduites par 'table.colonne'...). Vous pouvez aussi demander visualiser un lment prcis de la requte. getPart() retourne une partie prcise de la requte, demande via une constante de classe.
<?php $select = $db->select(); $select->from('messages') ->order('id'); $orderClause = $select->getPart(Zend_Db_Select::ORDER); // 'id' ?>

reset() efface une partie prcise de la requte, demande via une constante de classe, exactement comme la syntaxe de getPart() Un petit mot sur limitPage() : permet d'effectuer une pagination, avec slection automatique de la tranche de rsultat :
<?php $select = $db->select(); $select->from('membres', '*'); $select->order('id DESC'); $select->limitPage(3, 10); $result = $db->fetchCol($select); ?>

J'ai utilis fetchCol() pour vous rappeler que vous pouvez utiliser n'importe quelle mthode de retour de rsultat dj vu. Ici, limitPage() demande sur la liste de tous les membres, organise par id inverse, de slectionner pile la bonne partie pour afficher la page 3, en ayant chaque contenant 10 rsultats. Zend_Db_Select possde encore having(), group(), distinct(), forUpdate()...

- 37 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

IX-G - Passerelle vers les tables IX-G-1 - Gnralites


Pour terminer, nous allons passer la gestion de la passerelle vers les tables dont l'utilisation se rapproche de celle de RubyOnRails ou de CakePHP. L'accs aux donnes et aux tables est une partie trs importante dans la modlisation d'applications n-tiers. Dans Zend Framework, une couche d'accs aux tables et aux enregistrements de celles-ci est prvue par dfaut, mais toutes les classes mres sont abstraites. On pourra donc personnaliser entirement les processus d'accs, si celui par dfaut de ZF ne nous convient pas. L'accs aux tables et leurs enregistrement dans ZendFramework est matrialis par Zend_Db_Table / Zend_Db_Table_Row / Zend_Db_Table_Rowset, ils hritent de Zend_Db_Table_Abstract / Zend_Db_Table_Row_Abstract / Zend_Db_Table_Rowset_Abstract. Zend_Db_Table est la classe qui permet de faire correspondre une table ou vue du SGBD, une classe : elle implmente le design pattern Table Data Gateway, elle effectue les requtes personnalises : elle reprsente une table de la base de donnes (il y aura donc [au moins] autant de classes que de tables mapper). Ce schma est modifiable. Toute table doit obligatoirement possder une cl primaire sur au moins une colonne de table, Zend Framework ne sait pas traiter les tables qui n'ont pas de cl primaire lorsque vous utilisez la passerelle Zend_Db_Table. En gnral, une table d'entits comporte une cl primaire, sur une colonne (il est de coutume de l'appeler 'id') qui est auto incrmente. En revanche, les tables d'association peuvent avoir une cl primaire sur une colonne, ou sur plusieurs, selon la cardinalit. Un membre ne peut emprunter un mme livre qu'une seule fois : dans la table emprunts, la cl primaire sera compose de la cl primaire de la table membres et de la primaire cl de la table livres. On s'assure ainsi qu'on ne peut enregistrer 2 fois le mme membre, empruntant un mme livre. Mais s'il existe plusieurs exemplaires de ce livre, alors on aura une cl primaire dans la table emprunts unique, en plus des 2 cls trangres membres et livres. Un membre pourra donc emprunter plusieurs fois le mme (exemplaire) du livre, chaque emprunt tant distingu par une cl unique sur une colonne. Il s'agit des concepts connus de OneToMany (1 plusieurs) - OneToOne (un vers un seul) - et ManyToMany (plusieurs plusieurs). Zend_Db_Table reprsente une table (ou une vue) du SGBD, elle sert des objets Zend_Db_Table_Row. Ce sont les rsultats mapps (proprits = colonne de table). On les appellera les rsultats. Ils implmentent le design pattern Row Data Gateway Zend_Db_Table_Rowset est un conteneur de rsultats pourvu d'un itrateur, on appellera cela un jeu de rsultats. C'est un design pattern connu aussi : le dataset. Un rsultat ne comporte pas d'accesseurs : on modifie une proprit directement par affectation. Par contre des mthodes existent pour rcuprer des rfrences de tables, lorsque les tables sont lies entre elles par une intgrit rfrentielle (cls trangres). La couche d'accs aux donnes agit donc en mode LazyLoading, elle ne charge pas automatiquement les collections dpendantes, nous allons voir a : Voici l'exemple utilis ici, il est trs simple,

IX-G-2 - L'exemple
CREATE TABLE `livres` ( `isbn` varchar(14) NOT NULL, `titre` varchar(70) NOT NULL, `auteur` varchar(70) NOT NULL, PRIMARY KEY (`isbn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `livres` VALUES ('978-2212116762', 'Best Practices PHP5', 'Guillaume Ponon'); INSERT INTO `livres` VALUES ('978-2212120042', 'PHP5 Avanc', 'Cyril Pierre De Geyer'); INSERT INTO `livres` VALUES ('978-2841773381', 'Pratique de MySQL et PHP (Broch) ', 'Philippe Rigaux'); - 38 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

CREATE TABLE `membres` ( `num` smallint(5) NOT NULL auto_increment, `nom` varchar(50) NOT NULL, `date_naissance` date NOT NULL, PRIMARY KEY (`num`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; INSERT INTO `membres` VALUES (1, 'julien', '1982-11-01'); INSERT INTO `membres` VALUES (2, 'Benoit', '1984-02-08'); INSERT INTO `membres` VALUES (3, 'Estelle', '1977-08-07');

CREATE TABLE `emprunts` ( `membre` smallint(5) NOT NULL, `livre` varchar(14) NOT NULL, `date` date NOT NULL, PRIMARY KEY (`livre`,`membre`), KEY `membre` (`membre`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; INSERT INTO `emprunts` VALUES (1, '978-2212116762', '2007-03-24'); INSERT INTO `emprunts` VALUES (2, '978-2212116762', '2007-03-08'); INSERT INTO `emprunts` VALUES (3, '978-2841773381', '2007-04-02'); ALTER TABLE `emprunts` ADD CONSTRAINT `emprunts_ibfk_1` FOREIGN KEY (`membre`) REFERENCES `membres` (`num`) ON DELETE CASCADE ON UPDATE CASCADE, ADD CONSTRAINT `emprunts_ibfk_2` FOREIGN KEY (`livre`) REFERENCES `livres` (`isbn`) ON DELETE CASCADE ON UPDATE CASCADE;

Un exemple simple, comme celui dcrit juste avant. Membres - Livres - Emprunts. Emprunts possde une cl primaire sur 2 colonnes, un livre peut tre emprunt plusieurs fois (il a des exemplaires), mais un mme membre ne peut pas possder plusieurs exemplaires d'un mme livre). La table emprunts rpond donc la question "qui a emprunt quoi, et quand ?" Voici les fichiers de passerelle des tables Membres et Livres, ils tendent Zend_Db_Table_Abstract. Si nous avions voulu retoucher le mcanisme interne de la passerelle, nous aurions tendu Zend_Db_Table, dans laquelle nous aurions modifi la logique (ce qui est trs pratique pour personnaliser totalement sa couche d'accs aux donnes). On placera les fichiers des passerelles (qui comportent donc des classes), qui ne sont autre que notre logique mtier, dans un rpertoire /modele qui se trouvera hors racine web, car il n'a pas besoin de s'y trouver. On rajoutera simplement son chemin dans l'include_path, au dbut des scripts (en attendant un systme automatis, prvu; vous pouvez toujours crer le votre). Comme je vous l'ai dit, je fonctionne dans cet article avec l'autoload activ, pour conomiser des lignes. Toutes les classes sont supposes incluses et disponibles.

IX-G-3 - Dfinition des passerelles


modele/Membres.php
<?php class Membres extends Zend_Db_Table_Abstract { protected $_name = 'Membres'; protected $_primary = 'num'; { public function findByNom($nom) $where = $this->getAdapter()->quoteInto('nom = ?',(string)$nom); return $this->fetchRow($where);

- 39 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

modele/Membres.php
} }

modele/Livres.php

<?php class Livres extends Zend_Db_Table_Abstract { protected $_name = 'Livres'; protected $_primary = 'isbn'; }

La variable $_name reprsente le nom de la table SQL, et la variable $_primary reprsente la cl primaire (c'est un array si la cl est multi-colonnes). Ici, je les ai prciss, mais le mcanisme de Zend Framework permet de s'en affranchir. Si on ne spcifie pas la cl primaire, ZF va utiliser DESCRIBE TABLE pour se la chercher lui-mme. Si le nom de la table n'est pas prcis, alors le nom de la classe sera utilis (Cette information est mise en cache pour soulager le SGBD). Je conseille, ne serait-ce que pour y voir plus clair, de toujours spcifier la config de sa table dans la dfinition de sa classe, de plus, on peut vouloir nommer sa classe, et donc son fichier de classe, diffrement du nom de sa table ;-). $_sequence est un boolen true par dfaut dans l'abstraction. Il signifie que nos cls primaires sont en autoincrmentation, on ne le spcifie donc pas.Il peut contenir aussi un string pour agir sur les squences, une notion d'unicit de cl qu'utilise PostgreSQL ou encore DB2 Le systme de passerelle vers les tables de Zend Framework ne fonctionne qu'avec des tables ayant une cl primaire(ou une squence) modele/Emprunts.php

<?php class Emprunts extends Zend_Db_Table_Abstract { protected $_name = 'emprunts'; protected $_primary = array('membre', 'livre'); protected $_referenceMap = array( 'emprunteur' => array( // le rle UML de Membres vers Emprunts 'columns' => 'membre',// la colonne de emprunts est membre 'refTableClass' => 'Membres', // la classe des membres est 'Membres' 'refColumns' => 'num' // la cl primaire de membres est num (clause facultative) ), 'locations' => array( 'columns' => 'livre', 'refTableClass' => 'Livres', 'refColumns' => 'isbn' //facultatif, il s'agit de la PK par dfaut ));

$_referenceMap sert lier les tables. Le principe est simple : toute table recevant une cl trangre, doit remplir cet attribut de classe pour prciser quelles tables, et quelles cls sont lies avec elle. La cl primaire d'emprunts est sur 2 colonnes. C'est spcifi par un array. La definition des rfrences est trs importante et indique la logique de notre base de donnes au Framework. Pour les emprunts, dans la table emprunts, un membre est un emprunteur. C'est en fait le rle UML qui relie les 2 classes dans un Diagrammes de Classes de Conception. On fait rfrence la classe Membres, et la colonne est num. Il est possible qu'il y ait plusieurs colonnes (mme si c'est rare). Lorsqu'on a plusieurs rles, par exemple un membre me est l'emprunteur d'un livre mais il pourrait aussi tre son auteur. On aurait alors une 2 cl de membres dans emprunts, et on aurait par exemple matrialis le rle par "Auteur" ; en plus du rle "emprunteur". Il y a autant de rles UML que de dpendances entre les tables. Si la cl de rfrence est une cl sur plusieurs colonnes, on les spcifiera dans un array(), dans le mme ordre qu'elles ont t dfinies dans la classe parent. Si on ne spcifie pas la cl de la table parente (refColumns), alors la cl primaire dclare est prise par dfaut.

- 40 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Je vous conseille quand mme de spcifier la refColumns, je sais que les programmeurs sont paresseux (Lazy), mais rien qu'en lisant la dfinition des rfrences, on a tout de suite le schma de la base et des classes en visuel. C'est trs agrable lorsqu'on reprend 1 an aprs le projet (mme si on a comment son code). En plus de ceci, les classes passerelles des tables ont ncessairement besoin de notre adaptateur, rappelez vous notre objet $db qui sert manipuler la base au plus bas niveau. Forcment, les classes passerelles en ont besoin, et plutt que de le passer en paramtre aux objets chaque fois, vu que nous n'utilisons qu'une seule base et une seule connexion, nous allons dire tout le systme de passerelle que l'adaptateur par dfaut est $db. Dans le script principal, juste aprs avoir cre notre objet $db, nous le dclarons en tant qu'adaptateur par dfaut aux passerelles : Dclaration de l'adaptateur par dfaut aux passerelles

<?php // $params = ... try { $db = Zend_Db::factory('PDO_MYSQL', $params); $db->getConnection(); Zend_Db_Table::setDefaultAdapter($db); } catch (Zend_Db_Adapter_Exception $e){ echo $e->getMessage(); }

Zend_Db_Table::setDefaultAdapter($db); ca parle bien. Dans le cas de plusieurs bases, il faut trimbaler les 2 objets de connexion, mais des mthodes simplifient la tche, ou alors redfinissez une classe, tout reste possible. findByNom() est une mthode que j'ai crite moi-mme, elle va permettre de chercher des membres par leur nom. Regardez comment elle est crite. On rcupre l'adaptateur, car c'est lui qui possde la mthode d'chappement quoteInto(). On chappe le paramtre, cast au pralable en string, et on envoie ca fetchRow(). L'chappement des paramtres n'est pas automatique, nous devons donc utiliser les mthodes quote(), quoteInto() ou quoteIdentifier(), de l'adaptateur. Nous les avons dj vues. Dans les classes mtier, on dfinira donc toute la logique mtier d'accs aux donnes (findByNom(), mais aussi des mthodes du style findLivreLePlusRecent(), ou encore findPaniersVides()...), et c'est le contrleur qui accdera cette logique, dans un modle MVC. Outre les mthodes mtier que nous pouvons crire, il y en a dj pas mal qui sont implmentes dans ZF. Ainsi, sur des instances des classes Membres, Livres ou Emprunts : find() recherche des enregistrements par cl primaire. Vous rcuprez un jeu de rsultats (Rowset) contenant les enregistrements correspondants. Si on passe find() un tableau, alors on cherche plusieurs enregistrements : Recherche par cl primaire
<?php // ... Dfinition de l'adaptateur et des classes passerelles ... $membre = new Membres(); $membresTrouves = $membre->find(array(1,2)); ?>

createRow() retourne un rsultat vide, prt etre rempli ou utilis. fetchAll() excute une requte personnalise, retournant un jeu de rsultats (on choisira la mthode fetchAll() lorsqu'on sait que notre requte est susceptible de retourner plusieurs rsultats). fetchRow() excute une requete personnalise, retournant un rsultat (on choisira la mthode fetchRow() lorsqu'on sait que notre requte ne retourne qu'un seul rsultat ; s'il y en a plusieurs, elle ne retournera alors que le premier d'entre eux, attention). getAdapter() retourne l'objet bas niveau de connexion attribu la table. info() retourne toute la configuration du mapping de la table, sur un array (cl primaire, colonnes, types de colonnes, tables dpendantes...) getDependantTables() nous rappelle les tables dpendantes de l'objet, que nous avons configures au pralable, il s'agit d'un tableau PHP.

- 41 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

insert() et update, sont identiques celles dj vues mais mappes sur la table en cours (on ne spcifie pas le nom de la table, juste les paires colonne->valeur). select(), gnre un objet Zend_Db_Table_Select, comparable Zend_Db_Select (dja vu plus haut), mais verrouill sur la table dont il est issu. Les mthodes fetchAll() et fetchRow() acceptent en paramtre un objet Zend_Db_Table_Select, tout comme le font les mthodes de l'adaptateur. Cet objet sert diriger la requte, qui par dfaut est de type "select *".

IX-G-4 - Les rsultats (Row)


Nous venons de dcrire les schmas de passerelle de nos tables ainsi que la plupart des mthodes applicables sur les classes de dfinition tendant Zend_Db_Table_Abstract. Lorsque nous cherchons un rsultat (fetch***), selon la mthode utilise, nous nous retrouverons avec soit une instance de Zend_Db_Table_Row (un rsultat unique), soit une instance de Zend_Db_Table_Rowset (un jeu de rsultats uniques Zend_Db_Table_Row). (Ces 2 conteneurs de donnes spciaux sont redfinissables de manire trs simple, si le coeur vous en dit.) Pour l'exemple, createRow() nous retourne un unique rsultat, ce qui est logique ; en revanche, find() peut trouver plusieurs rsultats. La mthode find() retourne donc un jeu de rsultats, fetchAll() retourne un jeu, tandis que fetchRow() retourne un rsultat. C'est trs important car selon le type d'objet retourn, nous ne pourrons utiliser les mmes mthodes dessus. Si on nous retourne un jeu de rsultat, on ne pourra pas appliquer les mthodes d'un rsultat dessus. Faites y attention, cela a tendance embrouiller au dbut. Mme si la logique est tout fait de mise, il faut la comprendre, lorsqu'on y est pas habitu. Rcupration, modification et sauvegarde d'un enregistrement de la table membres
<?php // ... $tableMembre = new Membres(); $julien = $tableMembre->findByNom('julien'); $julien->date_naissance = '1982-12-08'; $julien->save(); ?>

Sur un rsultat, toutes les colonnes SQL sont mappes en tant que proprits de l'objet. Attention, en utilisant PDO, le paramtre PDO::CASE_NATURAL lui est pass par Zend Framework. Cela signifie que les changes entre le SGBD et l'OS se font en casse naturelle. Ainsi sous Windows, et concernant MySQL (je n'ai pas d'infos pour d'autres SGBDs) la casse n'est pas existante, et une colonne appel 'MACOLONNE', pourra tre appele via 'macolonne', mais pas sous Linux, qui respecte la casse. Il est conseill de toujours appeler ses noms de tables/colonnes, en minuscules, pour viter les ennuis de plateforme. Dans tous les cas, ZF utilise lui-mme en interne la casse naturelle, il est possible de changer le mode, les mthodes sont l, mais a va troubler ZF, de manire gnrale, il vaut mieux laisser ZF grer les paramtres PDO pour nous. Nous n'utilisons pas PDO nous programmeurs mais bel et bien le Framework qui, lui, utilise PDO comme il le souhaite (dans nos exemples, bass sur PDO) Regardez, $julien->date_naissance signifie que j'accde la colonne date_naissance du membre julien. Etant donn qu'il n'y a pas d'accesseur (get(), set()), je la modifie directement et je sauvegarde le tout en base via la mthode save(). Ainsi, sur un rsultat, je peux aussi utiliser : save() sauvegarde le rsultat en base. Notez que si celui ci n'existe pas (issu d'un createRow(), par exemple) alors une requte SQL "insert" sera utilise, sinon "update" sera utilis. delete() efface (dans la base bien sr) le rsultat. toArray() est trs pratique et transforme le rsultat en un tableau du type 'nom_de_la_colonne' => 'valeurcorrespondante'. setFromArray() est du mme style, elle attribue des valeurs notre objet suivant un tableau pass en paramtre du type 'nom_de_la_colonne' => 'valeur-correspondante'. Ceci est trs utilis lors de rcupration de formulaires, pour remplir rapidement un rsultat et le sauvegarder. D'autres mthodes find* existent, dcrites plus bas dans la section gestion des relations.

- 42 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

IX-G-5 - Les jeux de rsultats (Rowset)


Certaines mthodes, donc, renvoient un jeu de rsultats. Un jeu de rsultats (Zend_Db_Table_Rowset) est un simple conteneur de rsultats implmentant les interfaces SeekableIterator et Countable de la SPL. J'aurai aim seekable aussi, mais ca n'est pas le cas. Bref il s'agit d'un conteneur de rsultats, itrable via un foreach et comportant toutes les mthodes hrites de la SPL (current(), count(), next()). Un genre de ResultSet, pour les habitus de Java ;-)
<?php // ... $tableLivres = new Livres(); $deuxLivres = $tableLivres->find(array('978-2212116762','978-2841773381')); foreach ($deuxLivres AS $ceLivre){ echo $ceLivre->titre.'<br />'; } ?>

Ici je rcupre les 2 livres par leur cl primaires (Isbn), et j'affiche leur titre. Si je ne veux qu'un enregistrement, je procde comme suit :
<?php // ... $tableLivres = new Livres(); $leLivre = $tableLivres->find('978-2212116762')->current(); $leLivre->titre = 'Best Practices PHP 5'; $leLivre->save(); ?>

Je suis oblig de spcifier que je veux dans le jeu de rsultats le premier (et unique) rsultat, en l'atteignant par current(). Les autres mthodes d'accs proviennent de la SPL et d'Iterator. En implmentant aussi Countable, j'ai accs une mthode count() pour compter le nombre de rsultats retourns (attention, mon code n'a ici aucun sens smantique, selectionner tous les rsultats pour les compter est une aberration pure cot SGBD, un simple count(*) tant suffisant) :
<?php // ... $tableLivres = new Livres(); $lesLivres = $tableLivres->fetchAll(); echo 'il y a actuellement '. $lesLivres->count() .' livres dans ma base de donnes'; ?>

Une mthode toArray(), comparable celle d'un rsultat, est disponible sur un jeu de rsultats. Elle renvoie un tableau multidimensionnel de rsultats :
<?php // ... $tableLivres = new Livres(); $tabLesLivres = $tableLivres->fetchAll()->toArray(); /* $tabLesLivres contient : array(3) { [0] => array(3) { ["isbn"] => string(14) "978-2212116762" ["titre"] => string(20) "Best Practices PHP 5" ["auteur"] => string(16) "Guillaume Ponon" } [1] => array(3) { ["isbn"] => string(14) "978-2212120042" ["titre"] => string(11) "PHP5 Avanc" ["auteur"] => string(21) "Cyril Pierre De Geyer" } [2] => array(3) { ["isbn"] => string(14) "978-2841773381" ["titre"] => string(34) "Pratique de MySQL et PHP (Broch) "

- 43 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog) ["auteur"] => string(15) "Philippe Rigaux"

} */ ?>

IX-G-6 - Gestion des dpendances


Nous allons nous pencher sur la gestion des dpendances sous ZF. Si les termes 'Lazy mode', et 'full mode' vous disent quelque chose, sachez que ZF est lazy. Lors de la rcupration d'un enregistrement, il est possible de faire rfrence ses parents ou ses enfants. Ce n'est que lors de l'appel de la rfrence que le rsultat est charg. Si par exemple je rcupre un membre, je peux facilement afficher les titres des livres qu'il emprunte. Ou encore, si j'ai un enregistrement reprsentant un 'emprunt', je peux retrouver, grce des mthodes spciales, le membre y faisant rfrence ou bien le livre. Zend Framework tire toute sa puissance de PHP5 et, grce aux mthodes magiques __get(), __set() et surtout __call(), il va intercepter les appels de mthodes pour nous, de manire trs intuitive. Je vais vous donner un exemple. Avant toute chose, sachez que ces mthodes ne s'appliquent que sur un rsultat. On ne peut pas les appliquer sur des instances de jeu de rsultats, ce qui est logique. Je rcupre un membre, et je veux lister tous les livres qu'il a emprunt :
<?php // ... $tblMembres = new Membres(); $monMembre = $tblMembres->find(1)->current(); $sesLivres = $monMembre->findLivresViaEmprunts(); foreach ($sesLivres AS $unDeSesLivres) { echo $unDeSesLivres->titre.'<br />'; }

J'instancie ma table membres. Je rcupre le membre n=1, n'oubliez pas que le retour de find() est systmatiquement un jeu de rsultats (Rowset), je dois donc passer par current() (mthode de Zend_Db_Table_Rowset_Abstract) pour rcuprer mon rsultat. Sur un rsultat, je peux trouver ses dpendances par rle. En effet, Zend_Db_Table_Row est dot d'une mthode magique, qui va intercepter les appels du style find<tableClass>Via<IntersectionTableClass>(). $monMembre->findLivresViaEmprunts() retourne donc un jeu de rsultats reprsentant tous les livres - emprunts par monMembre. Le foreach est un itrateur, n'oubliez pas $sesLivres est un jeu de rsultats : en itrant dessus, on rcupre des rsultats reprsentatifs de livres. Sur ces rsultats, nous avons accs aux proprits de l'objet, ici c'est titre qui nous intresse. find<tableClass>Via<IntersectionTableClass>() rcupre un jeu de rsultats dans un schma cardinalits de type 'plusieurs plusieurs'. C'est un raccourci de commodit de la mthode findManyToManyRowset('tableClass','tableClass', 'role'). Pensez bien cardinalits dans un modle conceptuel. Un membre peut emprunter zro ou plusieurs livres. Un livre peut tre emprunt par zro ou plusieurs membres (on a dit qu'on raisonnait de cette manire, par 'exemplaires'). C'est une association plusieurs vers plusieurs, qui se traduit par une table de liaison, 'emprunts'. Si maintenant j'ai un livre, et que je veux lister toutes les dates auxquelles il a t emprunt, je procde comme suit :
<?php // ... $tblLivres = new Livres(); $monLivre = $tblLivres->find('978-2841773381')->current(); $sesEmprunts = $monLivre->findEmprunts(); foreach ($sesEmprunts AS $unDeSesEmprunts) { echo $unDeSesEmprunts->date.'<br />'; }

find<tableClass>() rcupre un jeu de rsultats d'une table dpendante, dans un schma '1 plusieurs'. C'est un raccourci de commodit de la mthode findDependentRowset('tableClass','role'). 1 livre peut avoir plusieurs rfrences dans la table emprunts, nous rcuprons donc un jeu de rsultats sur lequel nous itrons.

- 44 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Agissons enfin dans le dernier sens : nous avons un rsultat de type emprunts, et nous voulons connatre le nom du membre qui il appartient :
<?php // ... $tblEmprunts = new Emprunts(); $monEmprunt = $tblEmprunts->find('2','978-2841773381')->current(); echo $monEmprunt->findParentMembres()->nom.'<br />';

findParent<tableClass>() rcupre un jeu de rsultats d'une table parente. C'est un raccourci de commodit de la mthode findParentRow('tableClass','role'). De type '1 1' (1 emprunt donn ne fait rfrence qu' un membre), nous rcuprons un unique rsultat, sur un Row donc. Je n'ai pas parl des rles mais il est possible d'y faire rfrence. Si par exemple un membre emprunte un livre mais peut aussi tre son auteur, alors lister les livres crits par un membre se fera de la manire $leMembre>findLivresViaEmpruntsByAuteur(). Tout est automatique, Zend Framework se charge pour nous de faire les jointures ncessaires. Je n'ai pas non plus test les rsultats de mes requtes : un find(), peut par exemple ne retourner aucun rsultat, vous de le grer. Idem pour l'effet de cascade des SGBDs. ZF inclue un systme de cascade, qui permet d'agir la manire d'un SGBD, en actionnant en cascade les rsultats (DELETE ou UPDATE) : je n'en parle pas ici, car la gestion de l'intgrit de la base doit tre laisse la charge du SGBDR et non de l'application qui tourne dessus. Le staff de ZF nous le prcise clairement : se reposer sur la gestion de l'intgrit rfrentielle via ZF n'est pas recommand et peut mener des comportements hasardeux. Mes tables sont au format Innodb, un format de table grant les relations et l'intgrit, je ne m'occupe en rien de cela dans mon code applicatif. Abuser des mthodes de rcupration des dpendances va gnrer une charge insoutenable pour le SGBD. Ces mthodes sont l, mais en pratique on les utilise trs trs peu. Utiliser une mthode de rcupration de dpendance dans une boucle foreach, par exemple, amne une dgradation certaine des performances de l'application. Crez vous mme vos jointures, limitez les champs retourns (*, ne sert que trs trs rarement), et si possibles, utilisez des vues et des procdures stockes. N'agissez pas l'aveugle en vous reposant sur le framework, ayez toujours en tte les requtes envoyes votre SGBD. ZF ne fait que proposer une interface avec les SGBDs, vous de l'utiliser de manire correcte, rflchie et sense. Les 3 mthodes de rcupration des dpendances que nous vennons de voir, prennent optionnellement en paramtre un objet Zend_Db_Table_Select, trs pratique pour limiter les colonnes des rsultats, et ne pas choisir '*', comme c'est le cas par dfaut.

IX-H - Rappels
#Zend_Db et tous ses amis n'est pas une solution ORM. Un ORM est un systme qui masque totalement les donnes manipules dans l'application, du support qui va servir les faire persister (une base de donnes trs souvent). Le systme Zend_Db_Table_* peut tre utilis comme couche basse dans un ORM, mais une fois de plus : a n'est pas un ORM : voyez Doctrine pour cela.

- 45 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

X - #Zend_Log
Ce composant plutt petit est trs facile d'utilisation. Il va servir journaliser des vnements divers : une exception leve, la base de donnes qui ne rpond plus, une tentative d'intrusion... Plutt que d'crire la main le code, #Zend_Log est relativement complet. Sa classe, Zend_Log va utiliser des Zend_Log_Writer_*** afin de dfinir le(s) support(s) qui va contenir les logs. On a le choix entre un flux (fichier, sortie standard...) ou une table de base de donnes. Pour les tests, on a un objet dguis (Mock), ou un NULL, qui va neutraliser la journalisation. Enfin, les messages loggus pourront tre mis en forme, via des Zend_Log_Formatter_**, et mme filtrs. Utilisation basique de Zend_Log

<?php $log = new Zend_Log(); $fileWriter = new Zend_Log_Writer_Stream('my/file.log'); $log->addWriter($fileWriter); $log->info('Message d\'information'); $log->alert('Oula, gros problme'); ?>

Sur le journaliseur, j'ai 7 mthodes disposition, qui vont dpendre du degr de gravit de l'erreur survenue. Ces 8 degrs sont compatibles RFC-3164 et viennent du protocole BSD syslog, compatibles PEAR log. EMERG 0 : Urgence : le systme est inutilisable 1 : Alerte: une mesure corrective doit tre prise immdiatement 2 : Critique : tats critiques 3 : Erreur: tats d'erreur 4 : Avertissement: tats d'avertissement 5 : Notice: normal mais tat significatif 6 : Information: messages d'informations 7 : Debug: messages de dboguages

ALERT CRIT ERR WARN NOTICE INFO DEBUG

Issu de la doc officielle. Ainsi si j'applique une mthode err() mon objet de log, je journalise une erreur de niveau 3. Mais qu'est ce qui est enregistr, rellement ? Et bien il s'agit de 4 infos, timestamp - message - priority priorityName. Pour rajouter un paramtre prendre en compte lors d'un vnement de journalisation, indiquez-le par setEventItem() Modification du format d'enregistrement dans le journal
$log = new Zend_Log(); $fileWriter = new Zend_Log_Writer_Stream('my/file.log'); $log->addWriter($fileWriter); $log->setEventItem('Memory used', memory_get_usage()); $log->debug('Juste pour dconner');

Et voil, mon journal retiendra en plus la mmoire utilise par PHP cet instant-l : chaque fois que je journaliserai un vnement. Ici, ils sont retenus dans un fichier. Pour les enregistrer en base de donnes, et bien j'instancie un nouveau support, je peux en utiliser autant que je veux, j'crirai donc mon log plusieurs endroits diffrents, mais avec toujours une seule mthode : Enregistrement du journal plusieurs endroits

<?php $log = new Zend_Log(); $fileWriter = new Zend_Log_Writer_Stream('my/file.log'); // $db est une instance Zend_Db_Adapter_Abstract

- 46 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Enregistrement du journal plusieurs endroits

$dbWriter = new Zend_Log_Writer_Db($db, 'logTable', array('date_col'=>'timestamp', 'message_col'=>'message')); $log->addWriter($fileWriter); $log->addWriter($dbWriter); $log->notice('This is a notice');

Ici, mon vnement de type 'notice' va tre enregistr dans le fichier ET dans la base de donnes. J'ai pris soin de lui fournir une instance de Zend_Db_Adapter (voir chapitre sur #Zend_Db). Je lui ai dit aussi que je veux utiliser la table nomme 'logTable', et que sur cette table, chaque vnement du journal, la colonne 'date_col' enregistre le paramtre 'timestamp' du journal, et 'message_col', enregistre le paramtre 'message'. Facile quand mme... Si un jour j'ai envie de dbogguer et de dsactiver mon journal, alors je le fais l'endroit o je l'ai configur (et non chaque endroit ou je journalise... vla la galre!), et je lui passe un support spcial de leurre, en dsactivant les autres rels, videmment. Il s'agit du Zend_Log_Writer_Null, je peux mme chainer en faisant un $log = new Zend_Log(new Zend_Log_Writer_Null()). Pour leurrer le journal, entendez par l pouvoir l'utiliser dans l'application, le support Mock peut nous aider : Ecrire le journal dans un tableau PHP

<?php $log = new Zend_Log(); $mock = new Zend_Log_Writer_Mock(); $log->addWriter($mock); $log->debug('Un petit message comme ca'); Zend_Debug::Dump($mock); /* affiche : object(Zend_Log_Writer_Mock)#2 (4) { ["events"] => array(1) { [0] => array(4) { ["timestamp"] => string(25) "2007-09-04T22:57:16+02:00" ["message"] => string(21) "Message d'information" ["priority"] => int(6) ["priorityName"] => string(4) "INFO" } } ["shutdown"] => bool(false) ["_filters:protected"] => array(0) { } ["_formatter:protected"] => NULL } */ ?>

Notre support de stockage 'Mock' contient une proprit publique qui contient un tableau o sont stocks les vnements du journal, on y accde donc par $mock->events[**]['message'], par exemple. Je vais vite fait parler des formateurs, qui servent formater les vnements du journal. Par exemple pour le sortir en XML, on fait comme a : Journalisation au format XML

<?php $log = new Zend_Log(); $writer = new Zend_Log_Writer_Stream('php://output'); $formateur = new Zend_Log_Formatter_Xml(); $log->setFormatter($formateur); $log->addWriter($writer); $log->debug('Un petit message comme ca');

- 47 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Journalisation au format XML


/* affiche <logEntry> <timestamp>2007-09-04T23:04:39+01:00</timestamp> <message>Un petit message comme ca</message> <priority>7</priority> <priorityName>DEBUG</priorityName> </logEntry> */ ?>

Si vous avez besoin de plusieurs objets de log, chacun configur avec ses supports (Writers) et ses ventuels filtres/ formateurs, vous pourrez alors utiliser la mthode Zend_Log::factory(), elle permet de dcrire des objets log avec une seule mthode prenant en paramtre un tableau, ou encore un objet de type Zend_Config #Zend_Log comporte donc tout ce dont on a besoin. Comme d'habitude avec Zend Framework, des interfaces et classes abstraites existent pour crire et brancher son propre systme ou pour tendre celui-ci. Zend_Log, grce aux mock, permet aussi un test facile de l'application.

- 48 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XI - #Zend_View XI-A - Principe


#Zend_View constitue la partie vue du MVC. Il n'est absolument pas obligatoire de fonctionner sous MVC pour l'utiliser. En fait, #Zend_View participe la sparation du code de traitement et de la mise en forme des rsultats. Il permet de crer une sortie vers un ou plusieurs fichiers template, un fichier de vue. Cela fait partie intgrante de MVC mais aussi de toute application bien fonde. #Zend_View n'est donc pas un moteur de template proprement parler, car il ne fusionne pas 2 syntaxes distinctes. Il prpare des donnes qu'il va envoyer un ou plusieurs fichiers de vue. Cette vue va s'occuper des donnes reues et les prsenter. #Zend_Layout, reli #Zend_View constitue une approche de template simple et efficace. En pratique, voici un script simple de traitement qui rend une vue :
<?php // configuration $view = new Zend_View(); $view->setScriptPath('path/to/views/scripts'); $country = "france"; $sqlResult = $db>fetchPairs('SELECT id, name FROM members WHERE country = :country',array('country'=>$country)); $view->result = $sqlResult; echo $view->render('myview.phtml'); ?>

Nous crons d'abord une instance de Zend_View, puis nous lui spcifions o se trouvent les scripts de vue que nous voulons utiliser. setScriptPath() indique notre instance de vue, o chercher les scripts de vue qu'on va lui faire charger. Cela se fait une fois pour toutes, mais il est possible de spcifier le chemin via une autre mthode : addScriptPath() ajoute un dossier dans la liste des dossiers de scripts de vue. Notre instance va chercher dans le dossier spcifi par addScriptPath() d'abord puis, si elle ne trouve pas les vues, elle cherchera alors dans le dossier spcifi par setScriptPath(). C'est un mcanisme classique de pile (FILO) qui permet d'empiler des dossiers de scripts de vue. C'est intressant si l'on veut crer plusieurs looks sur notre site et spcifier un des looks via cette mthode. getScriptPaths() renvoie la liste des dossiers de vues sous la forme d'un tableau. Pour assigner une variable 'myVar' par exemple, on utilise simplement $view->myVar = 'my data'. Une mthode assign($myVar,'my data') existe aussi. On ne peut passer assign() que 2 types : des tableaux de rsultats (comme c'est le cas dans notre exemple) ou des chanes de caractres ; du moment que, dans la vue, on les utilise comme il faut. clearVars() dtruit toutes les variables pralablement passes la vue. render() enfin, retourne le rsultat de la vue, que l'on doit afficher (echo) ou bien capturer dans le buffer de sortie de PHP. Du ct du fichier vue myview.phtml, maintenant, nous pouvons le prsenter comme ceci :
<?php if ($this->result): ?> <!-- Tableau de rendu des membres --> <table> <?php foreach($this->result as $memberId=>$memberName): ?> <tr> <td><?php echo $memberId?></td> <td><?php echo $this->escape(memberName)?></td> - 49 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog) </tr> <?php endforeach; ?> </table> <!-- Pas de membres lister --> <?php else : ?> <p>Pas de rsultats</p> <?php endif; ?>

Ici, j'ai simplement utilis PHP pour dcrire ma vue, mais rien n'empche d'utiliser un moteur de template quelconque. La doc officielle offre un bon exemple. Nous remarquons que toutes les proprits envoyes la vue via assign(), ou en affectation directe, sont disponibles dans le contexte de la vue et sont donc utilisables via la pseudo variable $this :
<?php // script de contrle $view->someVar = 'someVal'; // ou $view->assign($someVar,'someVal'); echo $view->render('myViewFile.phtml'); // rend path/to/views/scripts/myViewFile.phtml ?> <?php // script de vue myViewFile.phtml echo $this->someVar // affiche someVal; ?>

Bien entendu, tant dans la vue, nous avons disposition une mthode d'chappement, la fonction bas niveau implmente par dfaut est htmlspecialchars(), avec le paramtre ENT_COMPAT (pas d'chappement des guillemets simples), sur le jeu de caractres ISO-8859-1. escape() chappe la variable passe en paramtre pour un affichage plus serein. setEscape() spcifie une fonction d'chappement personnalise, qui peut tre n'importe quoi : une fonction PHP ou mme une mthode statique de classe, voire mthode d'un objet :
$view->setEscape('myClass','myEscapeFunction'); $view->setEscape($myObj,'myObjEscapeFunction');

En gnral, on pourra spcifier htmlentities() et, dans le cas d'une fonction telle que celle-ci, qui accepte un paramtre spcifiant l'encodage de caractres, on peut le changer : setEncoding() spcifie une autre fonction d'encodage pour une escape htmlspecialchars(), ou htmlentities():
$view->setEscape('htmlentities'); $view->setEncoding('UTF8');

Ici, l'chappement sera quivalent htmlentities($var, ENT_COMPAT, UTF-8); Je rappelle qu'il n'est pas possible de changer le comportement du quote_style. strictVars() est utilise pour intercepter les appels des variables n'existant pas. Par dfaut, elle est rgle sur false, si vous lui passez true, et que dans votre vue vous appelez $mavue->uneVariableInexistante, alors une erreur NOTICE sera leve. Zend_View est utilis par le modle MVC, et donc par Zend_Controller_*. Ces composants configurent de manire automatique la vue, rendant son utilisation au sein du systme MVC trs intuitive et simple.

XI-B - Helpers (aides au rendu)


Zend_View est accompagn de tout un tas d'helpers, notamment concernant la construction de formulaires HTML. Je ne vais pas tous les prsenter mais juste un exemple.
- 50 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Script de vue d'dition d'une fiche quelconque :

<form action="action.php" method="post"> Nom : <?php echo $this->formText('name', $this->escape($this->name, array('size'=>30, 'maxlength'=>30)) ?> <br />Pays : <?php echo $this->formSelect('pays', 'fr', null, $this->countries) ?> <br />Recevoir la Newsletter? <?php echo $this->formCheckbox('newsletter', 'oui', null, array('oui', 'non')) ?> </form> ?>

Je ne vais pas tout dtailler ici, je vous renvoie l'API. Dans le cas le plus large, la syntaxe est helperFunction($name, $value, $attribs, $options). Ces helpers facilitent la mise en forme d'un formulaire, en particulier avec le fameux problme du <select><option></ option></select>, avec une boucle dans le <option> pour slectionner la valeur dj prsente en base. a se fait trs simplement ici, avec : script de contrle

<?php $view = new Zend_View(); $view->setScriptPath('path/to/views/scripts'); $view->countries = array('fr'=>'France','us' => 'United States','de' => 'Germany'); defaultCountry = $db->fetchOne('SELECT country FROM test WHERE id = 1'); echo $view->render('theView.phtml'); // rend path/to/views/scripts/theView.phtml <?php // script de vue theView?> <form action="action.php" method="post"> Pays : <?php echo $this->formSelect('pays', $this->defaultCountry, null, $this->countries); echo $this->formSubmit('Send','Envoyer'); ?>

Ici, le select est rempli d'options prsentes dans le tableau countries, et defaultCountry est en statut selected. formSubmit a donn naissance <input type="submit" name="send" id="send" value="envoyer" /> script de vue
echo $this->doctype('XHTML1_STRICT'), $this->headLink()->appendStylesheet('/styles/basic.css') ->headLink(array('rel' => 'favicon', 'href' => '/img/favicon.ico'), 'PREPEND') ->prependStylesheet('/styles/moz.css', 'screen', true), $this->headMeta()->appendName('keywords', 'framework php productivity') ->appendHttpEquiv('expires', 'Wed, 26 Feb 1997 08:21:57 GMT') ->appendHttpEquiv('pragma', 'no-cache') ->appendHttpEquiv('Cache-Control', 'no-cache'), $this->headScript()->appendFile('/js/prototype.js') ->appendScript($onloadScript), $this->headStyle()->appendStyle($styles), $this->headTitle('Titre de la page');

Ces helpers sont orients vers le code HTML contenu dans <head>. En plus d'ventuellement utiliser un moteur de templates, nous pouvons crire des helpers personnaliss. Voici tout de suite un exemple, imaginons : script de vue

<?php echo "Bienvenue, $this->showCart()";

La mthode showCart() est une mthode personnalise qui a pour but d'afficher clairement le nombre d'articles dans un panier. La mthode est issue d'un helper personnalis qui pourrait ressembler ceci :

- 51 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog) <?php class Zend_View_Helper_ShowCart { public function showCart($elements) { $output = "Votre panier contient $elements articles"; return htmlspecialchars($output); } }

Une fois encore, on garde les conventions de codage en tte : la classe doit s'appeler Zend_View_Helper_MonHelperPerso pour une mthode nomme monHelperPerso(), ceci se trouvant dans un fichier MonHelperPerso.php. Notez la casse, elle fait partie des conventions de nommage que nous avons rappeles en dbut de tutoriel. Avec les helpers personnaliss, on peut "casser" son code et une logique de sparation comme celle-ci peut tre utilise en complment avec la mthode addHelperPath(). addHelperPath() ajoute un dossier dans la liste des dossiers des helpers (fonctionne sur le mme principe que "scriptPath"). Notre instance de vue va chercher dans le dossier spcifi ici, sinon dans le dossier par dfaut Zend/ View/Helper/. On peut donc ranger ses vues et ses helpers, et ainsi correctement sparer son code si on le souhaite. setBasePath() permet de prciser le dossier de base de la vue, il s'agit en fait du dossier contenant les dossiers scripts/ helpers/ et filters/. Mthode de convenance vitant des appels successifs. Autre fonctionnalit : la rptition de motifs dans plusieurs vues peut tre factorise (extraite, crite part). Ceci grce aux helpers partial() et partialLoop() : controle
$view = new Zend_View(); $view->setBasePath('path/to/views'); // path/to/ views est sens se composer de 3 dossiers scripts/ filters/ helpers/ $view->data = $db->fetchAll("SELECT * FROM livres"); echo $view->render('view.phtml');

tableau.phtml
<tr> <td><?php echo $nom?></td> <td><?php echo $prenom?></td> </tr>

view.phtml
<h1>Liste de nos membres :</h1> <table> <?php echo $this->partialLoop("tableau.html",$this->data)?> </table>

partialLoop() boucle sur le script qu'on lui passe en paramtre. Le tableau de donnes ($this->data) pass en paramtre doit tre de la forme array( array('nom'=>'valeur','prenom'=>'valeur') ). C'est exactement ce que nous donne comme rsultat un fetchAll() (Consultez le chapitre #Zend_Db).

- 52 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XII - Zend_Layout
Zend_Layout travaille de mche avec Zend_View. Vous devez tre familier Zend_View pour comprendre Zend_Layout. #Zend_Layout introduit un pattern "two step view", qui va permettre de rendre une vue dans une vue plus gnrale et donc fonctionnelement "d'habiller" un site. Zend_Layout propose 2 modes de fonctionnement: un coupl la structure MVC de ZendFramework, et un mode totallement dcoupl. Nous utiliserons ce dernier car nous ne parlons pas du systme MVC dans cet article. Quoiqu'il en soit, Zend_Layout possde une dpendance vers Zend_View (Zend_View_Interface plus prcisment) et a besoin d'une vue pour fonctionner.

XII-A - Principe
Le principe de Zend_Layout est simple: crer et grer une vue globale dans laquelle sera rendue une vue particulire (ou plusieurs d'ailleurs). Exemple simple d'utilisation de Zend_Layout
<?php // Cration de la layout $layout = new Zend_Layout(array('layoutPath'=>'path/to/layouts', 'layout'=>'main')); // Cration de la vue $view = new Zend_View(array('basePath'=>'path/to/views')); // partage de la vue la layout $layout->setView($view); // indispensable // Rendu de la vue dans une variable de la layout $layout->content = $view->render('vue.phtml'); // Affichage de la layout echo $layout->render();

Fichier de layout : path/to/layouts/main.phtml


<div class="header"> HEADER ICI </div> // Affichage du contenu de la vue rendue prcdemment dans une variable de layout appele "content" <div class="content"> <?php echo $this->layout()->content; ?> </div> <div class="footer"> FOOTER ICI </div>

Comme on peut le voir, la manipulation de la vue (Zend_View) est classique: cration de l'objet de vue, configuration des chemins (notamment le chemin des scripts de vue), puis rendu banal de la vue comme dja abord dans le chapitre prcdent. Vient ensuite la layout. Il est indispensable de partager l'objet de vue la layout (setView()) car la layout va devoir rendre un script "de vue" et va donc utiliser l'objet Zend_View pour cela. Le tableau du constructeur de Zend_Layout permet de prciser le chemin vers les scripts de layouts, ainsi que le nom de la layout rendre. Dans un site web rel, en gnral, une seule layout est prsente, c'est pour cela qu'on ne prcise pas le nom de celle-ci la mthode render() (comme avec Zend_View), mais on prfre la configurer via le constructeur. Le tableau du constructeur prend comme cls 'layout' qui indique le nom du script de layout rendre lors de l'appel render() (et remarquez que l'extension .phtml se rajoute automatiquement), puis la cl 'layoutPath' permet de prciser l'endroit o se trouvent les scripts de layouts (l'quivalent du 'scriptPath' de la vue Zend_View). Bien sr, des mthodes setLayout() et setLayoutPath() existent aussi. Par la suite, nous rendons la vue classiquement mais nous n'affichons pas son contenu, nous l'enregistrons dans une variable de Zend_Layout, ici appele 'content' pour l'exemple. En ralit, vous pouvez utiliser n'importe quel nom, et vous pouvez mme rendre plusieurs scripts de vue dans plusieurs variables de layout (c'est le but de #Zend_Layout). Enfin, l'affichage est l'affichage de la layout, et non pas d'une vue individuelle.

- 53 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Le script de layout (main.phtml pour nous) est un script de vue, il sera rendu par Zend_View et se comporte de la mme manire. Simplement, l'interieur, vous allez avoir accs votre objet layout en interrogeant l'aide de vue (ViewHelper) appele 'layout'; au moyen de $this->layout(). Vous accdez ainsi aux variables de layout (nous en avons une dans notre exemple: 'content') et vous placez leur contenu o vous voulez.

XII-B - Exemples
Voici un exemple simple d'implmentation "header, corps, footer" pour un site web, bas sur #Zend_Layout :
<?php $layout = new Zend_Layout(); $layout->setLayoutPath('my/layouts'); $layout->setLayout('site'); $view = new Zend_View(array('basePath'=>'path/to/views')); $layout->setView($view); $layout->header = $view->render('header.phtml'); $layout->main = $view->render('mon_contenu.phtml'); $layout->footer = $view->render('footer.phtml'); echo $layout->render();

site.phtml
<div class="header"> <?php echo $this->layout()->header; ?> </div> <div class="content"> <?php echo $this->layout()->main; ?> </div> <div class="footer"> <?php echo $this->layout()->footer; ?> </div>

Comme on peut le noter, c'est tout de mme assez simple. Si je veux changer de "look", je rends une autre layout, comme ceci: Changement de la layout
echo $layout->render('noel'); // va rendre my/layouts/ noel.phtml qui propose une mise en page diffrente de site.phtml

Pour aller plus loin avec #Zend_Layout et utiliser le systme MVC avec,

consultez cet atelier

- 54 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XIII - Zend_Form
#Zend_Form est un composant qui comme son nom l'indique permet de crer et de grer des formulaires Web (x)HTML. Ce composant est extrmement pratique en ce qui concerne la gestion et la prsentation des donnes de manire gnrale. Aussi, si ce n'est dja fait, il est conseill de lire le chapitre sur #Zend_Validate et #Zend_Filter afin de bien comprendre les principes de #Zend_Form Pour rester simple, #Zend_Form se dcompose en plusieurs classes : 1 2 3 Zend_Form : le formulaire en question, comme il est validable, il implmente Zend_Validate_Interface Zend_Form_Element_* : des lments de formulaires, (des champs, des boutons ...), ils hritent tous de Zend_Form_Element, qui implmente aussi Zend_validate_Interface car chaque lment est validable indpendamment Zend_Form_Decorator_* : des dcorateurs. Ces objets ont pour seule responsabilit de prsenter visuellement les lments, et le formulaire contenant les lments

Un formulaire se compose donc d'lments qu'il faut lui ajouter, ainsi que d'autres petites options. Voyons en tout de suite quelques unes : construction d'un formulaire

<?php $form = new Zend_Form(); $form->setAction('/go/here') ->setAttrib('id', 'dvp-form') ->setDescription('formulaire exemple developpez.com') ->setEnctype(Zend_Form::ENCTYPE_URLENCODED) ->setLegend('lgende') ->setMethod('POST') ->setName('dvp-form') ->setView(new Zend_View); echo $form;

Les mthodes parlent plutot d'elles-mmes je pense, inutile de les dtailler. Afficher un formulaire est aussi simple que de faire un "echo" devant l'objet mais attention, la plupart du temps le formulaire Zend_Form aura besoin d'un objet Zend_View car il va en utiliser les aides (aides de vues, ou "View Helpers") pour pouvoir afficher les lments qui le composeront plus tard. Zend_Form est capable d'aller chercher l'objet vue utilis dans le systme MVC de luimme, comme nous n'utilisons pas le modle MVC de Zend Framework ici, nous devons passer manuellement un objet Zend_View Zend_Form, de manire tre tranquilles par la suite. Le code source HTML de ce formulaire est le suivant :
<form id="dvp-form" enctype="application/x-www-form-urlencoded" action="/go/ here" method="post"><dl class="zend_form"> </dl></form>

Il est trs important de noter qu'entre la composition du formulaire et/ou de ses lments et leur rendu HTML respectifs, se situent des objets appels "dcorateurs". Si le rendu HTML ne vous plait pas, pas de panique! Nous le modifierons plus tard grce aux dcorateurs. Notez aussi que la lgende, ou encore la description du formulaire n'apparaissent pas dans la source HTML, l encore, c'est une question de dcorateurs. Certains des paramtres de configuration que nous avons dfinis auraient pu tre utiliss avec setOptions(), ou encore avec setConfig() qui prend comme argument un objet Zend_Config. Notez bien que le composant #Zend_Form plus que tout autre, propose toujours diffrentes mthodes permettant d'arriver au mme rsultat, selon le cas dans lequel vous vous trouvez vous utiliserez l'une ou l'autre des manires de faire.

- 55 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XIII-A - Manipuler des lments de formulaire


Un formulaire ne sert rien s'il n'est pas compos d'lments. Les lments (objets de la classe Zend_Form_Element) possdent au moins autant d'options que l'objet Zend_Form lui-mme. Ainsi, les lments sont configurables de manire totalement indpendante du formulaire auquel ils seront rattachs plus tard. L encore, plusieurs manires de procder : 1 2 3 Vous crez et configurez chaque lment part, puis vous les rajoutez dans le formulaire Vous demandez au formulaire de crer des lments et de les configurer, puis vous les ajoutez au formulaire Vous crez et ajoutez dans le formulaire tous les lments d'un seul coup avec une seule mthode

Quoi que vous choisissiez, et quel que soit l'lment considr, tout lment doit au minimum possder un nom unique qui permettra de l'identifier dans le flot d'lments que votre formulaire comportera. Ainsi, 2 lments peuvent avoir le mme nom, mais si vous ajoutez les 2 au formulaire, alors celui-ci ne considrera que le dernier ajout. Voyons cel : ajout d'lments au formulaire, mthode n=1

<?php // $form est notre formulaire prcedemment cre $text = new Zend_Form_Element_Text('un champ texte'); $envoyer = new Zend_Form_Element_Submit('envoyer'); $form->addElement($text); $form->addElement($envoyer); // peut aussi s'crire comme ceci : // $form->addElements(array($text, $envoyer)); echo $form;

ajout d'lments au formulaire, mthode n=2

<?php // $form est notre formulaire prcedemment cre $text = $form->createElement('text','un champ texte'); $envoyer = $form->createElement('submit','envoyer'); $form->addElements(array($text,$envoyer)); echo $form;

ajout d'lments au formulaire, mthode n=3

<?php // $form est notre formulaire prcedemment cre $form->addElements(array( array('text','un champ texte'), array('submit','envoyer') )); echo $form;

Oui rptons : il existe toujours plusieurs (2, 3 voire 4) manires d'effectuer la mme action avec #Zend_Form Des lments, comme on peut le deviner, il en existe plein, et la documentation officielle vous renseignera leur sujet. Ils se configurent tous des la mme manire (car ils tendent tous Zend_Form_Element), et possdent en plus chacun des options bien eux (par exemple un lment de type 'select' possde une mthode permettant de lui ajouter les options qu'il contiendra). Le code source HTML ressemble maintenant a :
<form id="dvp-form" enctype="application/x-www-form-urlencoded" action="/go/ here" method="post"><dl class="zend_form"> <dt id="unchamptexte-label">&nbsp;</dt> <dd id="unchamptexte-element"> <input type="text" name="unchamptexte" id="unchamptexte" value=""></dd> <dt id="envoyer-label">&nbsp;</dt><dd id="envoyer-element"> <input type="submit" name="envoyer" id="envoyer" value="envoyer"></dd></dl></form>

- 56 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Je rpte que la manire dont sont prsents visuellement les lments et le formulaire (les balises HTML), dpend d'objets dcorateurs que nous verrons plus tard. Nous pouvons tout de mme remarquer que malgr leurs noms respectifs, certains lments comme le "text" ne l'affichent pas visuellement. C'est parce que tous les lments possdent un label. Le label est le nom qu'aura visuellement l'lment (gnralement situ cot de lui pour le dcrire), ce qui n'a rien voir avec son nom propre permettant de l'identifier dans l'objet Zend_Form ou dans la source HTML (grce aux attributs 'id' et 'name'). Nos lments doivent donc tous possder un label, quelques exceptions prs comme l'lment bouton qui prend son nom comme label d'affichage. Ajouter un label un lment revient lui ajouter une option, et des options, il en possde tous un tas. Voyons cel (liste non exhaustive) : setAttrib() permet d'ajouter un attribut HTML l'lment, par exemple $text->setAttrib('class','element'), ou encore $text->setAttrib('disabled','disabled') ce qui rend la saisie impossible dans le champ setDescription() ajoute une description l'lment. Celle-ci pourra tre prsente visuellement lors de l'affichage si l'lment possde un dcorateur permettant cela (c'est le cas par dfaut pour certains d'entre eux) setErrorMessages() affecte les messages d'erreur de validation l'lment, dans un cadre plus gnral, il demeure conseill d'viter les appels cette mthode et d'utiliser un objet Zend_Translate pour l'affectation et la traduction des diffrents messages d'erreur des validateurs d'un lment. setIgnore() prend en paramtre un boolen et informe alors que la valeur de cet lment sera ignore lors de la rcupration de l'ensemble des valeurs depuis le formulaire gnral, une fois celui-ci envoy setOrder() prend en paramtre un entier indiquant l'ordre dans lequel l'lment apparaitra dans le visuel HTML. Pratique pour configurer en dernier des lments devant tre affichs en premiers setName() permet de modifier le nom de l'lment setLabel() permet d'affecter un label l'lment, c'est dire un message descriptif visuel gnralement appos contre l'lment dans la source HTML setRequired() permet d'obliger cet lment tre non vide la saisie (sinon le formulaire sera en erreur lorsqu'on demandera de le valider) setValue() permet d'affecter la valeur par dfaut qu'aura l'lment lors de son affichage HTML ( en gnral il s'agit du tag "value=", cela peut aussi tre un tag "selected") Toutes ces mthodes ont des "get" associs (getAttrib(), getDescription() ...) En plus de cela, certains lments comme le select acceptent des mthodes spcifiques :
<?php $select = new Zend_Form_Element_Select('selection de donnes'); $select>setMultiOptions(array('option 1'=>'valeur 1', 'option 2'=>'valeur 2')); // les options afficher dans le select $select->setValue('option 2'); // selectionne la valeur 2 l'affichage

Il est temps maintenant de faire un formulaire plus complet. Je vais mixer diffrentes manires de procder dans l'exemple suivant : ajout d'lments divers, de diverses manires

<?php // $form est dja configur et vide de tout lment $text = new Zend_Form_Element_Text('un champ texte'); $text->setRequired(true) ->setErrorMessages(array('required'=>'Element requis')) ->setLabel('Voici un champ texte :') ->setDescription('Ce champ est l titre informatif pour le tutoriel') ->setAttrib('size','70'); $form->addElements(array( $text, // type | nom | options | array('select','selection de donnes', array('label'=>'slctionnez une donne :', 'multioptions'=>array('option 1'=>'valeur 1','option 2'=>'valeur 2'), 'value'=>'option 2')),

- 57 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

ajout d'lments divers, de diverses manires


array('submit','envoyer'), )); echo $form

Les "tableaux dans les tableaux de tableaux plein de tableaux" peuvent devenir droutants, mais sont extrmement logiques. Soit je passe par un tableau, soit je sors l'lment et j'utilise sa mthode de configuration approprie. On s'y habitue vite, et cette grande flxibilit dans les manires d'arriver un mme rsultat est un des points forts de #Zend_Form Le code HTML est le suivant :
<form id="dvp-form" enctype="application/x-www-form-urlencoded" action="" method="post"><dl class="zend_form"> <dt id="unchamptexte-label"><label for="unchamptexte" class="required">Voici un champ texte :</label></dt> <dd id="unchamptexte-element"> <input type="text" name="unchamptexte" id="unchamptexte" value="" size="70"> <p class="description">Ce champ est l titre informatif pour le tutoriel</p></dd> <dt id=""><label for="selectiondedonnes" class="optional">slctionnez une donne :</label></dt> <dd id=""> <select name="selectiondedonnes" id="selectiondedonnes"> <option value="option 1" label="valeur 1">valeur 1</option> <option value="option 2" label="valeur 2" selected="selected">valeur 2</option> </select></dd> <dt id="envoyer-label">&nbsp;</dt><dd id="envoyer-element"> <input type="submit" name="envoyer" id="envoyer" value="envoyer"></dd></dl></form>

Voyons quelques options avances utiles. Vous pouvez rcuprer un lment du formulaire en flchant son nom comme proprit de l'objet Zend_Form, et donc piloter l'lment hors du formulaire : rcuprer un lment depuis le formulaire

<?php // soit le formulaire ci-dessus, construit et rempli de nos 3 lments (text, select et submit) : $elementText = $form->unchamptexte; echo $elementText // affiche juste l'lment text

On comprend pourquoi chaque lment doit avoir un nom propre unique. D'ailleurs, mettre des espaces dans son nom n'aura aucun effet, ils seront en toute logique supprims ("un champ texte"=>"unchamptexte"). $form->removeElement() prend en paramtre le nom d'un lment et le supprime du formulaire. $form->getValue() prend en paramtre le nom d'un lment et rcupre sa valeur, s'il en a une par dfaut ou si le formulaire a t envoy et que le champ a t rempli $form->getValues() existe aussi, il retourne, comme on peut se douter, un tableau avec les lments et leurs valeurs associes.

XIII-B - Ajouter des validateurs et valider le formulaire


Le coeur de la puissance de #Zend_Form : la validation du formulaire. Ici, nous ne parlons pas javascript. Il est possible de rendre Zend_Form "ajax", notamment grce Zend_Dojo_Form, mais ceci dpasse le cadre de cet article. La validation du formulaire se produit aprs l'envoi de celui-ci (ou aussi aprs affectation de valeurs ses lments). La page recevant les donnes recre l'objet formulaire Zend_Form dans l'tat, et demande si celui-ci est valide avec les donnes reues. Ceci s'effectue de cette manire en gnral: valider le formulaire

<?php // nous supposons le mme formulaire que dans le souschapitre prcdent, simplement nous modifions sa destination // afin qu'il renvoie vers la mme page que celle l'ayant cre, ceci simplifie les traitements. $form->setAction($_SERVER['SCRIPT_NAME']);

- 58 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

valider le formulaire
if ($_SERVER['REQUEST_METHOD'] == "POST") { // venons-nous ici depuis une mthode POST ? if ($form->isValid($_POST)) { // si le formulaire est valide avec les donnes POST reues $form = "formulaire valid"; // on redfinit la variable $form plus tard affiche } else { $form->populate($_POST); // sinon on remplit tous les champs avec les valeurs reues } echo $form;

isValid() prend en paramtre un tableau, gnralement venu d'HTTP, et envoie chacune des donnes aux lments, puis demande chaque lment de valider cette donne. populate() prend en paramtre un tableau, gnralement venu d'HTTP, et envoie chacune des donnes aux lments en leur spcifiant de se l'affecter comme valeur par dfaut. Une fois que isValid() est appele, si on demande rafficher le formulaire, alors les ventuelles erreurs des validateurs des lments vont tre dcores, et donc affiches. Ce simple petit script et la combinaison des deux mthodes isValid() et populate() permet de valider et de rafficher entirement le formulaire, quelle que soit sa complxit et sa taille, en un seul geste. Gnial ! Mais qu'est ce que la validation des donnes ? C'est trs simple. isValid() demande l'objet Zend_Form de fournir les valeurs chacun de ses lments, et de demander chaque lment de valider cette valeur aprs l'avoir filtre. La validation se passe donc au niveau des lments de formulaire. Il faut, pour chaque lment qui le ncessite, ajouter les validateurs de type Zend_Validate_Abstract. Concernant les validateurs, renseignez vous sur leur fonctionnement dans cet article ou dans la documentation officielle. Pour l'ajout de validateurs, l encore, il existe plusieurs manires de faire, et aussi plusieurs options. Voici un exemple de formulaire email/password les utilisant : ajout de validateurs des lments

<?php // $form est toujours le mme, configur mais vide de tout lment $text = new Zend_Form_Element_Text('email'); $text->setRequired(true) ->setLabel('email :') ->setAttrib('size','30') ->addValidator(new Zend_Validate_StringLength(7));

$form->addElements(array( $text, array('password','motdepasse', array('label'=>'Password :', 'required'=>true, 'validators'=>array('Alnum', array('validator'=>'stringlength', 'options'=>array('min'=>8))) ) ), array('submit','envoyer'), )); $form->addElement('checkbox','caseacocher',array('label'=>'cochez ici svp :')); $form->caseacocher->addValidator(new Zend_Validate_Identical('1')); $email = new Zend_Validate_EmailAddress(); $form->email->addValidator($email); if ($_SERVER['REQUEST_METHOD'] == "POST") { if ($form->isValid($_POST)) { $form = 'valid'; } else { $form->populate($_POST); } } - 59 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

ajout de validateurs des lments


echo $form;

Voyez plutot, les lments possdent une mthode addValidator() qui prend en paramtre soit un objet Zend_Validate_Abstract, soit une chaine dcrivant le nom du validateur, soit encore un tableau avec la cl 'validator' une chaine dcrivant le validateur, et la cl 'options' un paramtre, souvent de type tableau, dcrivant les options passer au constructeur du validateur en question. addValidators() avec un 's' la fin, est indentique mais rajoute une dimension de tableau au tout. Aussi, on peut intgrer les validateurs directement lors du addElement() ou addElements() sur le formulaire. La syntaxe se complique un peu, mais elle respecte la mme rgle interne, et avec un peu de prsentation dans le code, a reste largement lisible. Prcisons tout de mme (la documentation officielle aide) que l'lment de type Checkbox renvoie 0 si non coch, et 1 si coch, ceci par dfaut. Nous voulons qu'elle soit coch, donc nous ajoutons un validateur d'quivalence la valeur 1. Essayez d'envoyer ce formulaire, vous remarquerez alors qu'il est bel et bien valid, et les erreurs s'affichent par dfaut en anglais (c'est personnalisable et trs simple si effectu au moyen de Zend_Translate, voyez la documentation officielle). Aussi, les erreurs d'affichent en dessous, dans des structures "ul-li", pas de panique je rpte encore : la prsentation se fait grce aux dcorateurs que nous verrons bientot. Les validateurs sont enchains sur la valeur reue par l'lment, dans l'ordre dans lequel ils ont t ajouts. Aussi, les validateurs agissent sur la valeur filtre de l'lment. Chaque lment accepte en plus des validateurs, des filtres de types Zend_Filter_Interface avec des mthodes trs semblables celles des validateurs. Nous n'ajouterons pas de filtres sur les donnes dans cet article. Les validateurs sont enchains sur la valeur reue par l'lment, dans l'ordre dans lequel ils ont t ajouts. Ainsi, chaque validateur valide la donne, qui est ensuite passe au validateur suivant. Tous les validateurs en echecs renseignent alors l'objet Element en lui injectant leur message d'erreur (traduit entre temps si Zend_Translate utilis). Dire un lment qu'il est requis ("required") a pour effet d'ajouter un validateur de type "NotEmpty", en haut de la pile des validateurs dja prsents ventuellement dans l'lment. Il est possible de casser la chaine. Exemple : mon champ password contient 3 validateurs : required (not empty), puis Alnum (seuls les caractres alphanumriques sont accpts), et enfin stringlength (la taille du champ doit faire au minimum 8 caractres). Si la chaine insre est compose de caractres exotiques faisant chouer "Alnum", "Stringlength" sera quand mme appel, mme si au final, c'est inutile. Pour demander casser la chaine de validation ds qu'un des validateurs d'un lment choue, il faut le prciser avec l'option "breakChainOnFailure" lors de l'ajout du validateur concern. casser la chaine de validation de email et password

<?php $text = new Zend_Form_Element_Text('email'); $text->setRequired(true) ->setLabel('email :') ->setAttrib('size','30') ->addValidator(new Zend_Validate_StringLength(7), true); // true en deuxime option active le bris de chaine si echec $form->addElements(array( $text, array('password','motdepasse', array('label'=>'Password :', 'required'=>true, 'validators'=>array( array('validator'=>'Alnum', // nous sommes obligs de passer par un tableau ici 'breakChainOnFailure'=>true), array('validator'=>'stringlength',

- 60 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

casser la chaine de validation de email et password


) )

'options'=>array('min'=>8))

), array('submit','envoyer'), ));

$email = new Zend_Validate_EmailAddress(); $form->email>addValidator($email); // on ajoute bien un deuxime validateur l'lment email, aprs son StringLength dja pr // suite

"required" ajoute automatiquement un validateur "NotEmpty" et lui affecte l'option breakChainOnFailure Si vous ne voulez pas l'ajout automatique de cette option, utilisez setAutoInsertNotEmptyValidator(true) sur votre lment Comme vous pouvez vous-mmes crer vos propres validateurs, et vos propres filtres, on sent bien que #Zend_Form rend de grands services. Sachez aussi que chaque validateur ne fait pas que recevoir la donne de l'lment auquel il est affect en entre. Il reoit aussi optionnellement les donnes de tous les lments. Un validateur d'galit de 2 champs mot de passe est tout fait ralisable (ou toute autre ide).

XIII-C - Dcorateurs : grer le rendu HTML


Passons maintenant au rendu HTML. Il faut bien comprendre que le formulaire est un objet contenant des objets lments, qui eux mmes contiennent des validateurs et/ou des filtres. Accessoirement un objet formulaire peut aussi contenir d'autres objets formulaires dans le cas de formulaires multiples (plusieurs pages, ou dcomposs). La prsentation visuelle du formulaire et de ses lments est dlgue entirement des objets dcorateurs (si toutefois vous dcidez de prsenter le formulaire, cela reste factulatif car un formulaire peut servir juste pour de la validation de donnes, mme si ce cas est plutt rare). On en dduit donc qu' la fois Zend_Form, mais aussi tous les Zend_Form_Element, vont contenir des objets dcorateurs. Les dcorateurs de l'objet Zend_Form vont grer le rendu HTML du formulaire, hors lments. Les lments eux, possdent chacun leurs dcorateurs (gnralement ils ont tous les mmes, car on apprcie qu'un formulaire ait un look "uni", mais ce n'est pas obligatoire). Le principe de la dcoration est bas sur l'embelissement successifs d'objets. Chaque dcorateur va rajouter du contenu au contenu prcdent. Voici, par dfaut, les dcorateurs que possdent les Zend_Form_Element : la dcoration par dfaut des lments
$elements->setDecorators(array('ViewHelper'), array('Errors'), array('Description', array('tag' => 'p', 'class' => 'description')), array('HtmlTag', array('tag' => 'dd')), array('Label', array('tag' => 'dt')), );

Notez que les mthodes et les tableaux permettant la gestion des dcorateurs, respectent la mme logique que ceux permettant de crer et d'ajouter des lments dans un formulaire. Pour bien comprendre la technique, lors de la demande du rendu visuel de l'lment, il se passera ceci :
$label->render( $htmlTag->render( $description->render( $errors->render( - 61 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog) $viewHelper->render('')))));

Les dcorateurs reoivent en paramtre l'lment sur lequel ils s'appliquent, et dcorent (prsentent visuellement) chacun un petit morceau de cet lment. Le dcorateur ViewHelper utilise l'aide de vue Zend_View_Helper_* qui se charge de rendre l'lment de formulaire avec ses attributs ventuels ("input", "select" etc...). Puis ensuite, le dcorateur Errors demande l'lment si il possde des messages d'erreurs (renseigns par ses ventuels validateurs), si c'est le cas, alors il les encapsule dans des structures "ul li". Ensuite si l'lment possde une description, celle-ci est dcore par le dcorateur du mme nom, et ainsi de suite ... Chaque dcorateur se charge donc du rendu d'un "petit bout" de ce qui compose un lment (l'lment, ses erreurs, sa description ...), et ce rendu est effectu de diffrentes manires. Soit avant le rendu des dcorateurs prcdents, soit aprs, soit la place de celui-ci, le remplaant (c'est le cas pour le premier dcorateur : ViewHelper effectue son rendu la place de rien du tout. On peut aussi citer HtmlTag qui effectue son rendu la place du rendu prcdent, mais en l'encapsulant d'un tag HTML). le rendu HTML par dfaut d'un lment text

<?php array('ViewHelper'), array('Errors'), // APRES array('Description', array('tag' => 'p', 'class' => 'description')), // APRES array('HtmlTag', array('tag' => 'dd')), // REMPLACE array('Label', array('tag' => 'dt')), // AVANT // -------------------------- ?> <dt id="email-label"><label for="email" class="required">email :</label></dt> <dd id="email-element"> <input type="text" name="email" id="email" value="" size="30"> <ul class="errors"><li>Value is required and can't be empty</li></ul> <p class="description">Une description exemple ici</p></dd>

Rappelez vous bien, chaque dcorateur agit avant, aprs ou la place du contenu dcor prcdent. Cela demande certes une petite gymnastique au dbut, mais on prend trs vite l'habitude. On peut en dduire que si on ajoute par exemple une description un lment, mais que l'on affecte aucun dcorateur permettant de grer cette description dans le rendu HTML final, alors celle-ci n'apparaitra tout simplement jamais. C'est le cas du formulaire Zend_Form qui peut possder une description, mais qui par dfaut n'enregistre aucun dcorateur permettant de l'afficher. Aussi, chaque dcorateur fournit avec #Zend_Form est unique. L'un va remplacer du contenu, l'autre va chercher tel composant de l'lment (la description par exemple) et le faire suivre dans le flux HTML, d'autres encore sont fantmes comme 'Errors' qui surveille les messages d'erreurs, mais s'il n'y en a pas, ne font rien, donnant l'impression qu'ils sont absents. Les dcorateurs par dfaut suffisent en thorie, car ils sont facilement manipulables par CSS, et une petite feuille de style bien mene permet une mise en page complte. Cependant, si on souhaite changer les dcorteurs, il faut noter quelques astuces : 1 2 3 4 Les dcorateurs agissent dans l'ordre dans lequel ils sont enregistrs, et vous aurez compris j'espre que cet ordre est extrmement important. Il n'est pas possible d'ajouter un dcorateur dans la pile, une place spcifique. L'ajout d'un dcorateur le met forcment la suite des autres. Un lment peut ne possder aucun dcorateur, il sera alors totalement invisible, mais comptera dans le processus de validation et sera bien prsent dans la mmoire Il est possible de crer ses propres dcorateurs, une interface et une classe abstraite existent. Cela permet de faire rellement tout ce que l'on souhaite

Exerons nous : nous souhaitons que nos lments (nous verrons le formulaire lui-mme plus tard) soient prsents dans des cellules d'un tableau HTML. Mme si chaque lment peut tre dcor de manire individuelle, on a trs souvent recours aux mmes dcorateurs pour tous les lments. Ainsi, nous pouvons les factoriser et les passer chaque lment.

- 62 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Suivez bien
1 2 3 4

Rendre l'lment de formulaire (qu'on ne peut entour tout de suite) Entour le tout d'un tag "td" Rendre le label de l'lment entour d'un tag 'td' (on peut l'entourer celui-ci) Entourer le tout d'un tag 'tr'

Afin d'arriver au rsultat HTML suivant, pour tous les lments :


<tr><td id="email-label"><label for="email" class="required">email :</label></td> <td> <input type="text" name="email" id="email" value="" size="30"></td></tr> $elementDecorators = array(array('ViewHelper'), array('Errors'), array('decorator'=>array('1er'=>'HtmlTag'),'options'=>array('tag'=>'td')), array('label',array('tag' => 'td')), array('decorator'=>array('2eme'=>'HtmlTag'),'options'=>array('tag'=>'tr'))); $email->setDecorators($elementDecorators); // et ainsi de suita pour tous les lments

L encore, tout en une seule fois nous oblige utiliser plein de tableaux, mais structurs visuellement cela reste comprhensible. Il aurait exister plein de manires de faires diffrentes encore, en utilisant les objets Zend_Form_Decorator_* configurs un un par exemple. Tout ceci ressemble fort la gestion de l'ajout d'lments dans le formulaire que nous avons dja vu ensemble dans les chapitres prcdents. Une technique agrable consiste demander au formulaire d'utiliser tels dcorateurs pour tous les lments y tant dja enregistrs : Demander au formulaire d'affecter des dcorateurs tous les lments le composant
$form->setElementDecorators($elementDecorators);

On peut aussi demander la cration d'un lment, de ne pas lui faire charger ses dcorateurs par dfaut, il est donc "nu" ds la cration, il faut pour cel lui passer l'option 'disableLoadDefaultDecorators' true. Concernant Zend_Form lui-mme, il possde aussi des dcorateurs permettant donc de rendre le formulaire en question. Voici les dcorateurs par dfaut :
$this->addDecorator('FormElements') ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form')) ->addDecorator('Form');

'FormElements' est spcial : il retourne le rendu des lments dcors au auparavent. Nous souhaitons donc ce rendu, remplac par le contenu d'un tag HTML entour autour de lui, remplac par le contenu d'une balise "form" entour autour de lui. Pour continuer notre mise en page en tableau d'exemple, nous devons utiliser : mise en page en tableau du formulaire lui-mme

<?php $formDecorators = array('FormElements', 'Form', array('decorator'=>array('1er'=>'HtmlTag'),'options'=>array('tag'=>'table')), ); $form->setDecorators($formDecorators);

- 63 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XIII-D - Autres fonctionnalits


#Zend_Form regorge d'autres fonctionnalits. Par exemple pour traduire les messages d'erreurs reus par les validateurs des lments, c'est aussi simple que d'enregitrer dans le registre Zend_Registry un objet de type Zend_Translate (configur). Aussi, Zend_Form supporte les sous-formulaires Zend_Form_SubForm. Il devient extrmement simple de grer des formulaires en plusieurs parties, chacun rutilisable n'importe o. Chaque lmnt peut aussi faire partie d'un "groupe d'affichage" ("DisplayGroup"). Le groupe d'affichage possdant des dcorateurs, cela permet de regrouper visuellement des champs ensemble. Zend_Form_Element_File permet de grer l'upload de fichiers de manire trs simple. Zend_Form_Element_Captcha simplifie aussi fortement la manipulation des CAPTCHAs. L'intgralit d'un formulaire peut tre configure grce un seul (ou plusieurs) fichier INI, ou XML, grce l'utilisation astucieuse de Zend_Config Zend_Form offre aussi des options intrssantes concernant les champs sous forme de tableaux (avec des [] ). Si vous souhaitez utiliser vos propres classes comme dcorateurs ou lments, Zend_Form possde en lui Zend_Loader_Pluginloader pour grer vos objets.

XIII-E - Etendre Zend_Form


Plus que tout autre composant, #Zend_Form doit tre tendu car il a t fait pour. Pour vous donner une ide, rendez-vous sur l'atelier Zend Framework prvu cet effet

- 64 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XIV - Zend_Application
Mme si les liaisons avec le systme MVC de #Zend_Application sont nettes, comme toujours ce composant peut tout fait tre utilis hors modle MVC de Zend Framework. A quoi sert-il ? Voici les objectifs de #Zend_Application : 1 2 3 4 5 6 Uniformiser la cration des objets du framework et leur configuration Enregistrer Zend_Loader_Autoloader automatiquement Configurer tous les paramtres PHP.INI simplement (ini_set) Grer le changement d'environnement (prod/dev) facilement Faciliter la configuration de MVC Grer les dpendances entre les objets

#Zend_Application sert surtout crer un moyen unique de configurer (presque) tous les objets du ZendFramework, puis de les stocker un endroit qui permet plus tard de les retrouver simplement. Pour cel nous allons voir plusieurs classes : 1 2 3 Zend_Application, qui sert configurer l'environnement global Zend_Application_Bootstrap_*, qui sert configurer les objets du framework que nous voulons utiliser Zend_Application_Resource_*, qui sert uniformiser la configuration des objets du framework que nous voulons utiliser

Voici un cas simple pour une premire approche. Nous allons utiliser la classe Zend_Application, seule. Le fichier lu par Zend_Application (application.ini ici)
[app] phpsettings.soap.wsdl_cache_enabled = 1 includepaths[] = APP_PATH "/model" includepaths[] = APP_PATH "/foo/bar" autoloadernamespaces[] = "Form" autoloadernamespaces[] = "Table" [dev:app] phpsettings.display_errors = 1 [prod:app] phpsettings.display_errors = 0

Utilisation de Zend_Application
define ('APP_ENV', 'dev'); define ('APP_PATH', __DIR__ . '/application'); require_once 'Zend/Application.php'; $app = new Zend_Application(APP_ENV, APP_PATH .'/config/application.ini');

Rappel : les fichiers ini, lorsque lus par PHP, savent importer les constantes PHP dfinies en leur sein. Nous avons plac le fichier ini sous APP_PATH/config/application.ini, pour l'exemple. Voyez la simplicit : nous crons simplement un objet Zend_Application, en lui passant 2 paramtres : une section charger puis un fichier de configuration qui comporte ces sections. Le fichier de configuration utilis ici est au format .ini mais un fichier .xml ou mme .php peut aussi fonctionner. En interne, Zend_Application utilisera le bon objet Zend_Config_* pour pouvoir lire ce fichier l : nous n'avons donc pas besoin de crer un objet Zend_Config_* la main.

- 65 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Ds sa cration, l'objet Zend_Application va utiliser Zend_Config pour lire le fichier de configuration et va immdiatement prendre les mesures suivantes : 1 2 3 4 Utiliser set_include_path() avec tous les chemins dclars dans les includepaths[] Enregistrer Zend_Loader_Autoloader Utiliser Zend_Loader_Autoloader::registerNamespace() avec tous les prfixes dclars dans les autoloadernamespaces[] Utiliser ini_set() avec tous les paramtres utiliss derrire phpsettings Toutes les cls sont insensibles la casse. Nous aurions pu crire AuToLoaDerNameSpaces[] = "Foo" , en revanche, n'oubliez pas les "s" des pluriels sur les cls, sinon a ne fonctionnera pas. Notez que nous avons dja une uniformisation : la simple cration de l'objet Zend_Application excute toutes ces actions pour nous.

XIV-A - Configurer ses objets (ressources)


Nous allons maintenant utiliser la partie "Bootstrap" de #Zend_Application. Celle-ci va nous permettre de configurer les objets ncessaires une application : un Zend_Log, un Zend_Db, un Zend_Session ... Le tout de manire uniformise, ce qui est fort apprciable. Pour cela, nous allons devoir dclarer une classe, qui tend Zend_Application_Bootstrap_BootstrapAbstract et la prciser Zend_Application grce au fichier de configuration. suite de application.ini
[dev:app] bootstrap.class = DvpBootstrap bootstrap.path = APP_PATH "/Boot.php"

La classe DvPBootstrap, se trouvant dans APP_PATH/Boot.php

<?php class DvPBootstrap extends Zend_Application_Bootstrap_BootstrapAbstract { public function run() { // code pour lancer l'application, laissez vide sinon } protected function _initLog() { // cette mthode va configurer un objet Zend_Log }

Cette classe doit dclarer une mthode run(). Celle-ci est sense contenir le code qui servira lancer votre application. Dans le cas o vous utilisez le modle MVC de Zend Framework, bas sur le composant #Zend_Controller, il est possible d'tendre Zend_Application_Bootstrap_Bootstrap qui tend elle-mme Zend_Application_Bootstrap_BootstrapAbstract, mais dfinit sa mthode run() afin qu'elle lance le contrleur frontal. Ensuite, votre classe de bootstrap devra comporter autant de mthodes nommes _init****() que d'objets diffrents configurer. Dans la classe de bootstrap, vous avez accs aux paramtres de configuration (fichier ini dans notre cas) au moyen des mthodes getOption() ou getOptions(). suite de application.ini : configuration de nos objets
[dev:app] db.params.charset = utf8 db.adapter = pdo_mysql db.params.unix_socket = /var/run/mysqld/mysqld.sock db.params.username = julien - 66 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

suite de application.ini : configuration de nos objets


db.params.password = secret db.params.dbname = dvp

view.doctype = XHTML1_STRICT view.encoding = "utf-8" view.basePath = APP_PATH "/mesvues" log = APP_PATH "/logs/log.log"

Suite de la classe DvPBootstrap

<?php class DvPBootstrap extends Zend_Application_Bootstrap_BootstrapAbstract { public function run() { // code pour lancer l'application, laissez vide sinon } protected function _initLog() { $log = new Zend_Log(new Zend_Log_Writer_Stream($this->getOption('log')); return $log; } protected function _initDatabase() { $options = $this->getOption('db'); $db = Zend_Db::factory($options['adapter'], $options['params']); return $db; } protected function _initVue() { return new Zend_View($this->getOption('view')); }

getOption($param) prend en paramtre une cl du tableau gr par Zend_Config, et la retourne. S'il s'agit d'une feuille: c'est une donne sous forme de chaine, s'il s'agit d'une branche: c'est un tableau. Ceci est le fonctionnement de Zend_Config (Rappel: Zend_Application et le bootstrap utilisent Zend_Config). Dans chaque mthode _init***(), nous configurons donc un objet en tirant sa configuration via getOption(), puis nous le retournons (c'est important). Voyez comme la configuration de chaque objet est bien range dans une mthode, alors que le fichier contenant Zend_Application est lui toujours aussi simple. Faisons en sorte qu'il charge maintenant nos objets en passant dans les mthodes dclares dans le bootstrap : Le bootstrap sait maintenant rcuprer nos objets
define ('APP_ENV', 'dev'); define ('APP_PATH', __DIR__ . '/application'); require_once 'Zend/Application.php'; $app = new Zend_Application(APP_ENV, APP_PATH .'/config/application.ini'); $boot = $app->getBootstrap(); // rcupration de l'objet bootstrap $boot->bootstrap('vue'); // dclenchement de la mthode _initVue() $view = $boot->getResource('vue'); // rcupration de la vue fraichement configure

Sur un objet de bootstrap, bootstrap('foo') permet de passer dans la mthode _initFoo() de sa classe. Notez bien que le nom de la mthode et de la ressource demande sont lis. Zend Framework partira de 'foo', mettra la premire lettre en majuscule 'Foo', puis rajoutera '_init' devant, avant de lancer la mthode : ce stade, il faut qu'elle existe.

- 67 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

getResource('foo') est une mthode du bootstrap qui permet de rcuprer l'objet (appel 'resource') 'foo', configur dans la mthode _initFoo(), condition que celle-ci le retourne bien (n'oubliez pas le return) Vous devez avoir lanc la mthode bootstrap('foo') avant l'appel getResource('foo') sinon le retour de la mthode getResource() vaudra null. Ds lors, chacun de s'organiser comme il le sent, vous avez la procdure suivre pour configurer vos objets et les rcuprer. Notez qu'appeler la mthode bootstrap() sans aucun paramtre fera que le bootstrap chargera toutes les ressources (toutes les mthodes _init**()) dans l'ordre dans lequel elles apparaissent. Vous pourrez donc par la suite les rcuprer avec getResource() sans problme.

XIV-B - Utiliser les plugins pour configurer ses objets (ressources)


Les mthodes _initMonobjet() ont un inconvnient tout de mme : il est difficile de les faire voluer, et un bootstrap va vite se remplir avec beaucoup de mthodes de ce type l. Il existe une solution, intgre dans le composant #Zend_Application, c'est une autre manire de configurer et charger ses objets (ressources), plus flxible. Plutt que d'utiliser des mthodes pour configurer nos ressources, il est possible d'utiliser des classes qui tendent Zend_Application_Resource_Abstract, et il en existe dja pas mal pour les objets les plus utiliss de Zend Framework. Nous appellerons ces classes des "plugins". Afin d'indiquer au bootstrap qu'il doit utiliser un plugin pour charger une ressource, plutt qu'une mthode _initMaRessource(), il convient de suivre ces rgles : 1 2 Ne pas indiquer de mthode _initRessource() dans la classe de bootstrap Prfixer toute configuration de la ressource par "resource." dans le fichier .ini

Le premier point n'est pas obligatoire, mais il est recommand de le suivre; des manipulations supplmentaires sont ncessaires dans le cas contraire. Ds que le bootstrap va rencontrer le mot "resource." dans le fichier .ini, il va chercher un objet Zend_Application_Resource_ correspondant et l'utiliser. Voyons cel : application.ini
[dev:app] resources.db.params.charset = utf8 resources.db.adapter = pdo_mysql resources.db.params.unix_socket = /var/run/mysqld/mysqld.sock resources.db.params.username = julien resources.db.params.password = secret resources.db.params.dbname = dvp

classe DvPBootstrap

<?php class DvPBootstrap extends Zend_Application_Bootstrap_BootstrapAbstract { public function run() { // code pour lancer l'application, laissez vide sinon } // PAS de mthode <i>initDb() }

Zend_Application en action

<?php // rien ne change par rapport avant ... $boot = $app->getBootstrap(); $boot->bootstrap('db'); $db = $boot->getResource('db');

- 68 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

Voyez plutt. bootstrap() et getResource() sont utilises avec une resource nomme "db", mais il n'existe pas de mthode _initDb() dans la classe du bootstrap. Dans le fichier .ini, la ressource s'appelle "db", et puisqu'elle est prfix sur mot-cl "resource.", l'objet de bootstrap sait qu'il faut qu'il utilise la classe Zend_Application_Resource_Db pour configurer un objet du composant #Zend_Db. Il existe actuellement (cela volue) dans Zend Framework, les classes Zend_Application_Resource_XXX avec XXX = Db, Session, Log, Cache, Locale, Translate, FrontController, Module, CacheManager, Dojo, Layout, Mail, MultiDb ... Renseignez-vous sur le manuel pour savoir comment elles fonctionnent, mais la plupart du temps les paramtres utiliss sont ceux de l'objet (ressource) configurer. Voici un exemple :
resources.db.params.charset = utf8 resources.db.adapter = pdo_mysql resources.db.params.unix_socket = /var/run/mysqld/mysqld.sock resources.db.params.username = julien resources.db.params.password = secret resources.db.params.dbname = dvp resources.view.doctype = XHTML1_STRICT resources.view.encoding = "utf-8" resources.view.basePath = APP_PATH "/modules/site/views" resources.log.writer.writerName = Stream resources.log.writer.writerParams.stream = APP_PATH "/logs/log.log" resources.session.use_cookies resources.session.name resources.session.save_path resources.session.save_handler = = = = on my_app tcp://127.0.0.1:11211 memcache

- 69 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Prsentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, confrences PHP) (Blog)

XV - Conclusions
Voil, cet article de prsentation est termin, mais il sera complt et mis jour de temps autre. mon blog pourra vous clairer, ou alors mon repertoire developpez, sans compter sur notre section Zend Framework. Notez que j'ai facilit l'accs aux codes d'exemple dans cet article. Je n'ai pas pris en compte les aspects scurit, j'ai fait des sous-entendus, je n'ai presque pas utilis les exceptions, etc. Dans des cas concrets, il y a bien entendu plus de travail fournir que ce qui est crit ici. Ici, c'est un avant-got, assez complet tout de mme, de Zend Framework, qui comporte beaucoup d'outils et son dveloppement est en perptuelle volution. J'espre vous avoir un peu clair sur ce Framework qui reprsente un atout considrable maitriser, dans tout dveloppement web PHP, en particulier dans un monde professionnel, ou le travail en quipe rgne. Zend a sign l un outil vraiment trs robuste, dans la ligne de PHP lui-mme.

- 70 Copyright 2007 - Julien Pauli. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Vous aimerez peut-être aussi