Zend Framework Presentation

70
 Présentation du Zend Framework - Premiers pas par Julien Pauli (T utoriels, con férences PHP) (Blog) Date de publication : 03/04/2007 Dernière mise à jour : 04/11/2010 Depuis Mars 2006 est apparu le Framework maison de chez Zend, pour PHP5. Pour rappel, Zend est une société qui commercialise tout un tas d'outils pour les entreprises, autour de PHP . Zend Framework est u n d'entre eux si ce n' est qu'il n'est pas commercialisé : distribué sous "New BSD Licence", il est gratuit, libre, conçu par une grande communauté de développeurs interessés dont je fais parti, piloté par Zend, et il propose génération de documents PDF, connecteurs vers de multiples services webs, connecteurs vers des bases de données 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 bibliothéquaire, à la manière de PEAR. Le projet Zend Framework est en perpetuel développement, et certains composants sont développés par les entreprises intéréssées : les Webservices Gdata sont développés par Google eux-mêmes, mais dans le respect de la licence du projet. Zend Framework reprend en tout point le concept de PHP lui-même : libre, ouvert, simple, efficace et puissant : un vrai régal.

Transcript of Zend Framework Presentation

Page 1: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 1/70

Présentation du Zend Framework - Premiers pas

par Julien Pauli (Tutoriels, conférences PHP) (Blog)

Date de publication : 03/04/2007

Dernière mise à jour : 04/11/2010

Depuis Mars 2006 est apparu le Framework maison de chez Zend, pour PHP5. Pour rappel, Zend est une société 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, conçu par une grande communautéde développeurs interessés dont je fais parti, piloté par Zend, et il propose génération dedocuments PDF, connecteurs vers de multiples services webs, connecteurs vers desbases de données diverses et support de MVC...On peut utiliser le Framework en tant que cadre de developpement directif, ou l'utiliser dansle cadre d'un simple support bibliothéquaire, à la manière de PEAR.Le projet Zend Framework est en perpetuel développement, et certains composants sontdéveloppés par les entreprises intéréssées : les Webservices Gdata sont développés par Google eux-mêmes, mais dans le respect de la licence du projet.

Zend Framework reprend en tout point le concept de PHP lui-même : libre, ouvert, simple,efficace et puissant : un vrai régal.

Page 2: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 2/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 2 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

I - Présentation............................................................................................................................................................ 3I-A - Préambule...................................................................................................................................................... 3I-B - Introduction.....................................................................................................................................................4I-C - Pré-requis.......................................................................................................................................................4I-D - Le coeur du Framework................................................................................................................................ 5I-E - Les conventions de nommage - Vocabulaire................................................................................................ 5

II - #Zend_Loader........................................................................................................................................................ 7III - #Zend_Debug #Zend_Version............................................................................................................................ 10IV - #Zend_Registry...................................................................................................................................................11V - #Zend_Config.......................................................................................................................................................13VI - Zend_Cache........................................................................................................................................................16VII - #Zend_Validate.................................................................................................................................................. 19VIII - #Zend_Filter......................................................................................................................................................23

VIII-A - Zend_Filter...............................................................................................................................................23VIII-B - Zend_Filter_Input..................................................................................................................................... 23

IX - #Zend_Db........................................................................................................................................................... 28IX-A - Introduction................................................................................................................................................ 28IX-B - Requêtes simples...................................................................................................................................... 30

IX-C - Récupération de résultats......................................................................................................................... 31IX-D - Insert, Update et Delete............................................................................................................................ 34IX-E - Transactions...............................................................................................................................................35IX-F - Sélections...................................................................................................................................................36IX-G - Passerelle vers les tables......................................................................................................................... 38

IX-G-1 - Généralites........................................................................................................................................38IX-G-2 - L'exemple..........................................................................................................................................38IX-G-3 - Définition des passerelles.................................................................................................................39IX-G-4 - Les résultats (Row)...........................................................................................................................42IX-G-5 - Les jeux de résultats (Rowset).........................................................................................................43IX-G-6 - Gestion des dépendances................................................................................................................44

IX-H - Rappels......................................................................................................................................................45X - #Zend_Log...........................................................................................................................................................46XI - #Zend_ View........................................................................................................................................................ 49

XI-A - Principe...................................................................................................................................................... 49XI-B - Helpers (aides au rendu)...........................................................................................................................50

XII - Zend_Layout...................................................................................................................................................... 53XII-A - Principe..................................................................................................................................................... 53XII-B - Exemples.................................................................................................................................................. 54

XIII - Zend_For m........................................................................................................................................................55XIII-A - Manipuler des éléments de formulaire.................................................................................................... 56XIII-B - Ajouter des validateurs et valider le formulaire.......................................................................................58XIII-C - Décorateurs : gérer le rendu HTML........................................................................................................ 61XIII-D - Autres fonctionnalités.............................................................................................................................. 64XIII-E - Etendre Zend_For m.................................................................................................................................64

XIV - Zend_ Application.............................................................................................................................................. 65XIV-A - Configurer ses objets (ressources)......................................................................................................... 66XIV-B - Utiliser les plugins pour configurer ses objets (ressources)................................................................... 68

XV - Conclusions....................................................................................................................................................... 70

Page 3: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 3/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 3 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

I - Présentation

I-A - Préambule

Le Zend Framework (ZF) fait beaucoup de bruit sur la toile du développement PHP. Il sait se classer dans la vaguedes Framework "reconnus" sous PHP. Google le présente d'ailleurs parmi ses outils pour developpeurs. J'ai décidéde vous y faire goûter du bout des lèvres ;-).

Ce Framework a bien grandi. En l'espace d'un an, il a changé de licence pour s'ouvrir au développementcommunautaire, et il accuse déjà une quarantaine de composants opérationnels. Il est vrai qu'à ses débuts, début2006 (le projet date d'Octobre 2005), tout était différent. Beaucoup de refactorisation et de correction de bugs ontété faits. Une si belle progression n'aurait pu être possible sans un modèle de développement communautaire, maisbien architecturé.Tout le monde peut reporter un bug sur le tracker , proposer ses idées, faire partager ses expériences, tout ceciorchestré par l'équipe de gestion du projet de Zend.

Personnellement, j'ai bien aimé mes débuts sous ZF, c'est en découvrant peu à peu sa structure et son articulationque j'ai décidé de contribuer un peu, tout d'abord via ce tutoriel de présentation. Mon blog regorge d'informationsdiverses concernant ZF, et j'écris aussi d'autres articles ou ateliers techniques. ZendFramework représente aussiune partie de mon travail à titre professionnel, en effet je suis formateur sur ce Framework et j'aide à son déploiementou 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 près tout ce qui le touche,notamment son développement actuel qui tend à se rapprocher d'un style Ruby On Rails, de par certainescaractéristiques. Nul doute que les programmeurs habitués à du "full object", ne seront pas dépaysés (les adeptesde Java par exemple).Je suis contributeur, je participe donc au développement de certains composants ainsi qu'à la correction de bugs età l'amélioration de certaines fonctions.

A la tête du Zend Framework, on trouve Andi Gutmans, qui n'est autre qu'un des 2 architectes responsables du ZendEngine, le moteur de PHP ayant succédé au projet initialement conçu par Rasmus Lerdof.Le but de Zend est simple : faire de ZF un framework calqué sur PHP : aussi simple, intuitif, et puissant, que lelangage PHP lui-même, 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 ZendFramework qu'il est amené à devenir la brique que tout développeur PHP sera à même de savoir utiliser, surtoutdans 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 rassurée lorsqu'un support professionnelest présent derrière un produit, à fortiori libre. Passer le framework sous une licence "ouverte" est donc bienvenude la part de Zend.

ZF n'est pas fermé et peut se relier à d'autres frameworks; de même , il y a 2 moyens d'utiliser ZF : en "glue" : vous

utilisez uniquement les composants dont vous avez besoin, ponctuellement, à la manière de PEAR. Autre méthode :"full-stack" : vous décidez dès le départ de bâtir votre architecture entière sur ZF.Cette perméabilité 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 répondre auxbesoins les plus redondants du développement de sites Internet en PHPZF est la surcouche fonctionnelle de PHP5, testé, sécurisé, développé et pensé par des ingénieurs, architectes etdéveloppeurs d'importance, le tout dans un esprit collaboratif, libre et open source.

Si vous êtes intéressés pour approfondir le vaste sujet que représente le ZendFramework, j'ai co-écrit un ouvrage à

son sujet, vous en apprendrez plus sur sa page dédiée.

Page 4: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 4/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 4 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

I-B - Introduction

Un Framework apporte un cadre standard pour le développement d'applications à interface web.Il agrège différentes classes, ce qui augmente la couverture fonctionnelle d'un langage tout en en simplifiant samanipulation.

Il permet à plusieurs personnes (notamment en Entreprise) de s'organiser autour d'un projet, quelle que soit sa taille.Il introduit des règles de codage et d'architecture qui sont là pour faire en sorte que toutes les personnes relativesau projet parlent la même langue. Tous les développeurs vont ainsi écrire du code à partir du même cadre de travail,et l'échange des données entre eux est très facilité.Les architectes et les chefs de projet techniques s'y retrouvent aussi, car la puissance de la programmation orientéeobjet leur permet d'utiliser des méthodes connues et ayant fait leurs preuves, comme la modélisation UML, le designlogiciel ou les design patterns.La conception objet permet aussi un fort découplage applicatif, la réutilisabilité maximale du code et favorisegrandement 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 collectionmodulaire de classes PHP 5 qui simplifient les tâches courantes du développeur".

Il s'agit pour l'essentiel de fonctionnalités très utilisées comme une couche d'abstraction de bases de données (fondéeprincipalement sur PDO), le support de MVC, la génération de documents PDF, l'envoi d'e-mails, la gestion deflux de syndication Atom et RSS, la gestion de l'internationalisation...Le Zend Framework intègre 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 decontenu basé sur le célèbre moteur Lucène de l'Apache Group, tout un tas d'outils facilitant l'internationalisation, lessessions, etc .

Pour s'assurer du succès de son Framework, Zend s'est appuyé sur un modèle participatif et communautaireimpliquant plus de 180 participants au nombre desquels figurent de grands acteurs comme Yahoo!, Google, IBMet General Electric. La concision du code qu'apporte un Framework de haut niveau, plus fonctionnel que technique,augmente la productivité des développeurs. 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 notammentdu modèle 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 compréhension de cet article, il est conseillé de posséder de bonnes compétences enprogrammation orientée objet (POO), de bonnes notions de conception UML et des Design Patterns, ainsi quequelques connaissances du langage SQL; étant donné que nous ne ferons pas que "survoler" certaines de sesfonctionnalitésVous retrouverez les diagrammes de classe des principaux packages étudiés 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 repère reste l'API en ligne, le mécanicien ne bossant pas sans sa caisse à outils...Histoire de ne pas se perdre dans les méthodes et les objets, on garde un oeil sur le manuel.Attention tout de même, la version originale du manuel est la version anglaise. Les autres versions sont destraductions, effectuées par des groupes de traduction de l'équipe de développement, et peuvent donc êtredésynchronisées, le temps de la traduction. Vérifiez donc les statuts des traductions, ou préférez la doc originale,en anglais.

Commençons par télécharger la dernière version stable de ZF. À ce jour, ce tutoriel est écrit avec ZF 1.11

Page 5: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 5/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 5 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Il est important de vérifier la version du framework utilisée. Celui-ci assure unecompatibilité ascendante, quelques cassures sont à noter, documentez vous: LesChangeLog 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 danscet article.

Rien qu'avec ces quelques composants, nous serons déjà en mesure de faire une petiteappli 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 curiosités.Il n'est pas obligatoire de réaliser un projet à 100% sous ZF. Ainsi, même sans MVC, ZF va tout de même nous simplifier la vie.

Cet article n'a pas pour vocation d'être exhaustif, certaines méthodes ne seront pas

 présentées, elles sont cependant bien présentes dans l'API.

Le coeur du Framework est représenté par le dossier library de l'archive téléchargée. La structure interne de ZF estrégie par des conventions de nommage, que voici :

I-E - Les conventions de nommage - Vocabulaire

#Zend_Db représente un composant que l'on peut aussi appeler  package (en référence à Java), il estmatérialisé par le script /ZF-path/Zend/Db.php, la classe représentée étant Zend_Db.Cette convention de nommage sera utilisée 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 apparaître

l'arborescence du fichier.Si votre application respecte la même norme, alors vous verrez que le développement devient encore plus souple.Comme pour PEAR, chaque underscore ( _ ) dans le nom de la classe représente donc une descente dansl'arborescence, et un lien de dépendance fonctionnelle.Chaque composant donne naissance à une classe, portant le même nom, et chaque composant est une entité duFramework, qui peut contenir d'autres classes qui l'enrichissent et qui dépendent d'elle.Ainsi, Zend_Db_Adapter_Abstract est une classe dont le fichier est /ZF-path/Zend/Db/Adapter/Abstract.php, contenudans le package #Zend_Db

On peut donc dire que tout ce qui descend, dépend. Une dépendance est un lien UML soit direct : héritage, soitindirect : utilisation, implémentation, etc . Mais un des avantages de ZF est son couplage relativement faible. Tousles packages ne dépendant pas les uns des autres, seules quelques liaisons internes sont effectuées, lorsque c'est

nécessaire. Ainsi, vous pouvez sans problème utiliser #Zend_Db, par exemple, sans avoir à dépendre d'un autrepackage.Seules quelques dépendances entre packages sont à noter (elles sont même de temps en temps facultatives) oùc'est réellement nécessaire : #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, entraîne une inclusionde dizaines d'autres (et donc un temps de traitement revu à la hausse).Il est conseillé de placer le répertoire du Framework en dehors de la racine web, sinon, d'interdire son accès, par exemple avec un fichier .htaccess.

Comme pour tout Framework, dans un souci de pratique, il faut d'abord ajouter son répertoire à l'include path dePHP. Ceci se fait soit par l'intermédiaire du fichier php.ini, soit via la fonction set_include_path(). Nous utiliseronsen développement une gestion d'erreur large (E_ALL | E_STRICT).

L'utilisation d'un framework apporte une baisse notable des performances d'uneapplication, ceci est dû à l'inclusion de diz aines de fichiers par requête HTTP.

Page 6: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 6/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 6 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Lors de l'utilisation de MVC notamment, il n'est pas rare qu'une simple petite requête HTTP  provoque l'ouverture de dizaines de fichiers PHP sur le serveur, pour la traiter.Pour absorber et faire disparaitre cet inconvénient de taille, un cache d'opcodes (type APC   ) secondé par un cache applicatif (type Zend_Cache) sont des solutions tout à fait reconnues et utilisées.N'oubliez pas aussi de toujours tourner sur une version de PHP à jour. PHP 5.3 apporte

des améliorations importantes en terme de performances par rapport à la version 5.2 

Page 7: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 7/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 7 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

II - #Zend_Loader 

La classe Zend_Loader comporte déjà toute une série d'outils très pratiques. Ce ne sont que des méthodes statiques,sans dépendances externes (Elles ne necessitent pas d'autres composants, cependant d'autres composants ontbesoin d'elle). Le composant à inclure est #Zend_Loader , il est donc représenté par le fichier /Zend/Loader.php.

Quasiment tous les composants du Framework dépendent 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 levée dans vos applications enverra, au plus bas, une Zend_Exception. Notez queZend_Exception n'étant pas déclarée 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éélémentaire, doit renvoyer sa propre exception, nommée. Cela facilite grandement le débogage, notamment dans lecadre de projets travaillés en équipe. Si tout le monde envoie des 'Exception', toutes simples, on ne peut absolumentpas savoir d'où viennent les erreurs, de même 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.i ni directement. Nous supposerons celà par lasuite.

Nous allons poursuivre avec les méthodes 'helpers' du composant #Zend_Loader . Utiliser des helpers, alors quePHP seul peut représenter les mêmes fonctions, est utile si vous chargez des fichiers dont le nom ou le chemind'accès sont variables (des vérifications sont faites sur le nom). Sinon, un require() fait l'affaire.

loadFile() charge un fichier PHP.

utilisation de Zend_Loader supposant ZF présent dans l'include_path<?php

// manière classique

require('example1.php');

// manière ZF

require('Zend/Loader.php');try {

Zend_Loader::loadFile('example2.php');

} catch (Zend_Exception $e) {

  echo $e->getMessage();

}

<?php

// manière classique avec once

require_once('example1.php');

// manière ZF avec once

require('Zend/Loader.php');try {

Zend_Loader::loadFile('example2.php', null, true);} catch (Zend_Exception $e) {

  echo $e->getMessage();}

La grande différence avec PHP, comme pour tous les outils du Framework Zend, est qu'ils s'appuient sur une gestiond'Exception interne, que vous pouvez contrôler comme vous le souhaitez. Si un fichier comporte des caractèresinterdits, une Zend_Exception sera levée.

Page 8: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 8/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 8 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Plus répandu déjà, loadClass() charge une classe en utilisant loadFile(). Cette méthode s'utilise surtout avec lesmécanismes 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 méthode, et enregistre la fonction d'autoload de ZendFramework sur la pile des autoloaders.Avec l'autoload, dès que PHP rencontre une classe qu'il ne connait pas (c'est à dire dont le fichier la définissant n'apas encore été inclu), il va utiliser la fonction d'autoload pour chercher le fichier correspondant à cette classe. Lafonction d'autoload de ZF lui fait utiliser loadClass()Après que le fichier ait été trouvé, loadClass() s'assure que la classe a été chargée suivant les conventions denommage. loadClass() effectue donc 2 actions : charge le fichier de la classe, et vérifie le nom de la classe dansce fichier.

Pour de plus amples informations sur l'autoload,   parcourez cet atelier Zend 

Framework 

Une fois l'autoload activé grâce à 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 préfixe de classe (CommeZend_ pour le Zend Framework). Il faut ensuite ajouter le dossier contenant ce dossier espace de noms dans l'includepath de PHP, et déclarer 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 définie dans APP_PATH/mesclasses/Dvp/Class.php

$class = new Dvp_Class;

// JP_Exemple est définie dans APP_PATH/mesclasses/JP/Exemple.php

$class2 = new JP_Exemple;

?>

L'utilisation de l'autoload est aujourd'hui très largement répandue et recommandée dans les projets webs.Sinon, loadC lass() et loadFile() acceptent un second paramètre $dirs, chaîne ou tableau représentant un (des)dossier(s) dans lequel (lesquels) rechercher le fichier.

isReadable() est une copie de son homologue PHP, à la seule différence qu'isReadable() parcourt l'include path.

Pour gérer correctement l'extensibilité de ses applications, la classe Zend_Loader_PluginLoader  vous propose decharger manuellement une classe en précisant uniquement son suffixe. Cela permet notamment de charger unensemble de préfixes 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');

Page 9: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 9/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 9 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 existeet possède 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 levée */

Se servir de ce composant manuellement est plutôt rare, en revanche le ZendFramework l'utilise lui en interne trèssouvent. Dès lors qu'on vous demandera de préciser le nom d'une classe par une chaine représentant son préfixe,alors Zend_Loader_PluginLoader est utilisé en interne. C'est notamment le cas pour les formulaires, les vues, etc...

Page 10: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 10/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 10 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

III - #Zend_Debug #Zend_Version

#Zend_Debug ne contient actuellement qu'une méthode (utile) statique de débbuguage.dump(): est une amélioration très appréciée de var_dump() qui rajoute des <pre> de formatage pour un confortde lisibilité amélioré. C'est le remplaçant des echo() et autres print_r() var_dump(), extrêmement pratiques en

débuguage. setSapi():, permet de spécifier manuellement le SAPI sur lequel PHP tourne, le formatage de la sortiene sera plus encadré de <pre> mais de PHP_EOL (End Of Line, dépendant de l'OS sous lequel PHP tourne).En théorie vous n'aurez pas besoin d'utiliser cette méthode sauf cas très spécifiques.

#Zend_Version ne contient qu'une seule méthode statique de comparaison de version.compare(): compare la version passée en paramètre, avec la version actuelle de Zend_Framework. Elle utiliseversion_compare() de PHP, elle renvoie cependant uniquement un String. Intéressant à noter, la constanteZend_Version::VERSION contient la version actuelle du Zend Framework (par exemple "1.8.3"). Ceci pourra êtreutilisé pour de la detéction d'environnement par exemple.

Page 11: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 11/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 11 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

IV - #Zend_Registry

Ce composant est issu du design pattern Registre. Le Registre est un pattern qui fournit un mécanisme destockage de données, destiné à favoriser le mélange global des objets dans une application.C'est une alternative à l'utilisation de variables globales. Le registre de ZF s'utilise de manière statique ou dynamique,

nous utiliserons plutôt les méthodes statiques. Le Framework l'utilise lui-même en interne pour son mélange dedonnées. set() et get() en sont les méthodes principales :

Enregistrement d'un objet dans le registre<?php

$config = new Zend_Config_Ini('./

config.ini', 'database'); // $config représente un objet de configuration

Zend_Registry::set('conf', $config);

Dans cet exemple, un objet de configuration (que nous verrons juste après) est crée et enregistré dans le registresous le nom de 'conf', qui va nous servir à récupérer 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 définir la couleur et la marque des voitures instancesde Voiture. Ceci est très 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 dépendant du nom d'une variable précisément.Dans l'exemple ci-dessus, je peux à tout moment changer le nom de la variable $config, la classe Voiture utilise leregistre et non le nom de la variable directement, déclarée ailleurs.Précisons à nouveau : le registre de ZF renvoie toujours la même instance d'un objet (mais pas d'un tableau mêmesi ce cas d'utilisation est plus que rare). Ainsi, n'importe où dans un script :

Récupération 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 génie logiciel, il faut garder absolument sous contrôle la notion de dépendance (ou aussi de couplage) : leregistre mélange tout, il faut l'utiliser à bon escient et aussi rarement que possible. Préférez toujours l'injection de dépendances : 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 méthode en lui passant directement l'objet en paramètre ; elle retourne TRUE s'il, FALSE sinon.

Page 12: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 12/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 12 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

setInstance() est une méthode qui permet carrément d'implémenter son propre pattern Registre étendantZend_Registry . Si votre application doit se brancher sur une structure comportant déjà un r egistre, cette méthodepermettra de l'utiliser.

Zend_Registry est un composite : il auto gère sa(ses) propre(s) instance(s). Zend_Registry étend ArrayObject, de la SPL.

Page 13: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 13/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 13 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 = 'localhost';

$db_name = 'name_of_database';

$db_user = 'myname';

$db_pass = 'secret';?>

Sur de gros projets, cela ne tient plus la route et il devient difficile d'accéder 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 ouconfig.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 subtilités.

Config.ini :

[database]

username = foopassword = bar

hostname = localhost

[voiture]marque = ma-marque-de-voiture

couleur = vert

Avec ce fichier de configuration, le script suivant va encapsuler nos données 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->propriétés et, mieux encore, le parseur gère aussi l'héritage.Par exemple, un fichier de config unique, mais dont les paramètres sont écrasés, avec une gestion d'utilisateurs :

Config.ini :

[database]

name = databasehostname = localhost

[developers : database]

name = dev-database

username = developers

password = dev-password

[teamleaders : database]

Page 14: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 14/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 14 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Config.ini :username = team-leaders

password = tl-password

Chargement de sections différentes à 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?>

Ici, nous passons au constructeur le nom de la section à charger comme 2ème paramètre. "Developers : database"signifie que developers hérite des propriétés de database. Il peut en redéfinir d'autres ou écraser les propriétésparentes (héritage OO avec visibilité protected). Notez que le fait de charger une section fait entrer notre objet dedans.

Nous pointons donc $config->leparamètre directement, et non plus $config->lasection->leparamètre.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 paramètre ini, depuis le framework par défaut. Ce comportement peut être

changé via une 3ème 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 seuleforcée, lui.De plus, getSectionName() retourne la section qui a été précédemment chargée, et areAllSectionsLoaded()retourne true si vous n'avez pas choisi de section dans votre constructeur (en passant à null le paramètre de section).

Zend_Config est un design pattern composite. Chaque section représente une instancede l'objet Zend_Config nichée dans son père. Les interfaces Countable et Iterator , de laSPL, sont utilisées.Il s'agit de la représentation des données sous forme d'un arbre, chaque noeud est unebranche à l'extrémité de laquelle se trouve une feuille : la donnée.

Nous pouvons en plus des sections, créer un héritage avec le point '.'. Ce séparateur est modifiable.

Config.ini :

[site]debug = 1

db.hostname = localhost

log.writter = database

[dev : site]

[prod : site]

debug = 0db.hostname = mydbprod

Chargement de la section 'dev'$config = new Zend_Config_Ini('./config.ini', 'dev');

Page 15: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 15/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 15 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 // 1echo $config->prod ->debug // 0echo $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 données au formats Y aml et Json.

Page 16: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 16/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 16 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

VI - Zend_Cache

#Zend_Cache est un composant fort sympathique pour mettre tout un tas de données diverses et variées dans uncache. Il convient dès lors de définir un peu de vocabulaire.Une façade de cache, aussi appelée en anglais (et dans la doc officielle) "frontend" , représente le type de données

que l'on veut pouvoir mettre en cache. Un support de cache, en anglais "backend" , représente l'endroit dans lequelles données vont être stockées.Le composant #Zend_Cache permet donc de lier une façade à un support, et c'est ce couple là qui sera utilisé.

Concernant les façades, il est possible de mettre en cache :

Page 17: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 17/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 17 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Différentes façades Zend_Cache1 Zend_Cache_Frontend_Output  : sortie standard2 Zend_Cache_Frontend_Function : résultat de l'appel d'une fonction3 Zend_Cache_Frontend_Class : résultat de l'appel des méthodes statiques d'une classe4 Zend_Cache_Frontend_File : fichier 5 Zend_Cache_Frontend_Page : page HTTP complète

6 Zend_Cache_Frontend_Capture : page HTTP complète avec intégration au modèle MVC de ZendFramework

Toutes ces façades spécialisées héritent d'une façade hautement générique : Zend_Cache_Core. Celle-ci fournit desméthodes bas niveau de gestion du cache, comme save(), load(), clean(), remove() ...

Les supports eux, sont aussi nombreux :

Page 18: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 18/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 18 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Différents supports Zend_Cache1 Zend_Cache_Backend_File : stocke les données de cache dans un fichier 2 Zend_Cache_Backend_Sqlite : stocke les données de cache dans SQLite3 Zend_Cache_Backend_Memcached  : stocke les données de cache dans un serveur ou une ferme

Memcache en utilisant l'extension ext/memcache4 Zend_Cache_Backend_LibMemcached  : stocke les données de cache dans un serveur ou une ferme

Memcache en utilisant l'extension ext/memcached5 Zend_Cache_Backend_Apc  : stocke les données de cache dans le cache OPCode APC6 Zend_Cache_Backend_Xcache : stocke les données de cache dans le cache OPCode Xcache7 Zend_Cache_Backend_ZendServer  : stocke les données de cache dans la distribution PHP intégrée

ZendServer 8 Zend_Cache_Backend_ZendPlatform : stocke les données de cache dans le serveur d'application

ZendPlatform9 Zend_Cache_Backend_TwoLevels : stocke les données de cache dans deux supports différents, en

permettant la gestion de la bascule de l'un à l'autre10 Zend_Cache_Backend_BlackHole : stocke les données de cache dans rien du tout : simulacre servant pour 

les tests11 Zend_Cache_Backend_Static  : stocke les données de cache provenant de Capture dans des fichiers

Ce qu'il faut savoir, c'est que les supports basés sur les fichiers sont lents, mais par contre ils permettent souventde stocker des quantités de données énormes.A l'inverse, un support basé sur la mémoire vive (Memcached, APC, XCache, Sqlite dans certains cas) sontextrêmement rapides, mais en général limités en capacité.

L'utilisation de #Zend_Cache est donc plutôt simple : Zend_Cache possède une méthode factory() qui va créer uncache, c'est à dire une association entre une façade et un support.Il convient de les paramétrer, et la doc officielle détaille très bien tout cela.

<?php

$bO = array();

$fO = array('lifetime' => 60,  'automatic_serialization' => true);

$cache = Zend_Cache::factory('Core', 'APC', $fO, $bO);

Ce code crée un cache générique (qui va servir à tout faire : Zend_Cache_Core), avec comme support de stockage :APC. APC ne nécessite aucune donnée de configuration, nous passons un tableau vide en quatrième paramètre.Core ne nécessite aucune option, mais les paramètres par défaut ne vont pas nous arranger. Nous passonsdonc 2 options : lifetime est très importante : il s'agit de la durée de vie des infos dans le cache (en secondes).automatic_serialization indique à Zend_Cache_Core de sérialiser la donnée de manière automatique si celle-ci lenécessite : par exemple un tableau ou un objet.

Utilisation du cache<?php// ...

if (($donnees = $cache->load('mesdonnées')) === false) {

  $donnees = $db->findBigData();  $cache->save($donnees, 'mesdonnées');}

Simplicité extrême : load() demande de charger des données stockées à l'index "mesdonnées". Si cette méthoderetourne false, alors c'est que les données n'étaient pas présentes dans le cache. Nous les récupérons donc depuisun 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 très pratiques et font de #Zend_Cache unesolution souple et efficace dans son domaine.

Enfin si vous devez gérer plusieurs objets de cache (ce qui est souvent le cas), Zend_Cache_Manager saura alorsmémoriser leurs informations respectives et vous fournir une passerelle simple vers les objets de cache stockés.

Page 19: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 19/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 19 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

VII - #Zend_Validate

La sécurité est un point que tout bon développeur doit avoir en permanence à l'esprit. Je ne vais pas faire un coursde sécurité ici, mais juste vous parler des composants #Zend_Validate et #Zend_Filter qui agissent selon le mêmemodèle, ils seront traités ensemble car possèdent beaucoup de ressemblances.

Zend_Validate est un conteneur de validateurs qui va permettre de créer des chaînes de validateurs sur mesure, quivont nous simplifier la vie face à des situations courantes en développement web.

Un validateur est une fonction qui vérifie si une donnée respecte un schéma. Un filtre au contraire, modifie la donnée selon un schéma semblable.

Je ne vais montrer que quelques exemples, mais l'API en ligne regorge d'autres méthodes sympathiques. Onnotera Zend_Validate_* { Alnum, Alpha, Between, Hostname, Int, Ip, Regex (...) }Nous pouvons créer des instances de chacun de ces validateurs et les utiliser individuellement, mais nous pouvonsaussi les chaîner dans Zend_Validate : On aura bien compris qu'un validateur va servir à valider les données reçuespar l'utilisateur, c'est un composant de la catégorie sécurité des applications web, dont on va pouvoir user et abuser,sa méthode principale est isValid().Un validateur commence par retourner true, puis teste la valeur soumise à travers sa classe et ses conditions, dèsque l'une d'elle n'est pas remplie, son retour vaut false.Plutôt que d'instancier un validateur à chaque fois, et de lui soumettre isValid(), la méthode statique raccourcie is()peut s'avérer pratique pour un validateur précis :

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 paramètre, passez votre valeur, en deuxième paramètre, un string représentant le validateur (qui doit êtreatteignable et lisible), le troisième paramètre sert pour les options du validateur.Lorsqu'un validateur retourne false : la donnée n'est donc pas valide, des méthodes permettent de savoir pourquoi.getMessages() renvoie les messages d'avertissement que le validateur retourne, destinés à etre affichés.getErrors() lui, va renvoyer des codes d'erreurs, qui sont présents sous forme de constantes dans la classe duvalidateur, ceux-ci ne sont pas destinés à être affichés, mais à permettre un traitement adéquat de l'erreur, voyons ca :

Exemple d'utilisation plus avancée 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 donnée : la valeur doit être comprise entre 2 et 8. Nous lui fournissons '25' et nousaffichons les messages d'échec du validateur.Tous les validateurs ont des messages par défaut, qui sont personnalisables par setMessages(). Etant donné qu'unvalidateur peut générer plusieurs messages, getMessages() retourne un tableau, qu'il faut donc passer via un foreach,par exemple.

Page 20: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 20/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 20 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 ent

$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 spécial sur une condition d'échec du validateur en s'appuyant sur desconstantes de classe. Par exemple, le validateur Digit vérifie que la chaine passée de contient bien que des chiffres,mais vérifie aussi si celle-ci n'est pas vide. Nous pouvons effectuer un traitement spécial dans ce cas :

Exemple d'utilisation avancée 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 chiff  foreach ($validator->getMessages() as $message) {

  echo "$message\n";

  }  }

}

Utilisons le principe de chaînage des validateurs maintenant : nous avons toute une série de validateurs individuelsà disposition, que nous ajouterons à un validateur personnalisé grâce à addValidator(). Lors de l'appel à isValid(),tous les validateurs vont passer en revue la donnée passée en paramètre, puis chacun écrira dans un journal si ouiou non, son test est passé. On pourra récupérer le journal après via getMessages(), pour affichage, ou getErrors()pour un traitement.

Création 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 donnée est validée

} else {  // itération sur les messages d'erreur

  foreach ($chaine->getMessages() as $message) {

  echo "$message\n";  }

}

?>

Dans notre exemple ci dessus, nous créons un validateur composé d'une chaine de validateurs individuels associés,

qui vérifie si $data est un entier - supérieur à 8.

Page 21: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 21/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 21 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Dans le cas où notre donnée n'est pas un entier, le validateur va tout de même continuer sa chaine, et passer dansGreaterThan. Les validateurs sont utilisés dans leur ordre d'ajout à la chaine de validation et g etMessages() va alorsretourner tous les messages d'echec : ceux de Int, et ceux de GreaterThan.Il est possible de lui spécifier de s'arrêter de valider, dès qu'un des validateurs de la chaine échoue, ceci grâce à undeuxième paramètre pour addValidator() :

Création d'une chaine de validateurs avec arrêt en cas d'erreur sur un validateur <?php

$chaine = new Zend_Validate();

$chaine->addValidator(new Zend_Validate_Int(), true) // true en second paramètre

  ->addValidator(new Zend_Validate_GreaterThan(8));

if ($chain->isValid($data)) {

  // la donnée est validée

} else {  // itération sur les messages d'erreur

  foreach ($chaine->getMessages() as $message) {

  echo "$message\n";  }

}

?>

Dans l'exemple si dessus, nous avons mis à true le deuxième paramètre pour addValidator()concernant le validateur Int. Ainsi, si notre donnée ($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 même possible d'écrire ses propres validateurs, en implémentant Zend_Validate_Interface , et enrédéfinissant les méthodes isValid(), getMessages() et getErrors(), par exemple nous souhaitons un mot de passede 8 caractères minimum, avec au moins une lettre majuscule, une minuscule, et un chiffre :

Création d'un validateur personnalisé<?php

class MyValid_PasswordStrength extend s Zend_Validate_Abstract

{

  const LENGTH = 'length';  const UPPER = 'upper';

  const LOWER = 'lower';

  const DIGIT = 'digit';

   protected  $_messageTemplates = array(  self::LENGTH => "'%value%' doit avoir une longueur d'au moins 8 caractères",

  self::UPPER => "'%value%' doit contenir au moins une lettre majuscule",

  self::LOWER => "'%value%' doit contenir au moins une lettre minuscule",

  self::DIGIT => "'%value%' doit contenir au moins un chiffre"

);

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

Page 22: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 22/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 22 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Création d'un validateur personnalisé  $this->_error(self::DIGIT);  $isValid = false;  }

  return $isValid;  }

}

Nous allons tout de même dire un petit mot du gros validateur que représente Zend_Validate_EmailAddress

Zend_Validate_EmailAddress utilise Zend_Validate_Hostname pour au final permettre de vérifier si l'adresse emailest bien formée et si la partie pseudonyme respecte la RFC2822. Concernant la partie domaine, il est vérifié si ellerespecte la syntaxe d'un nom DNS du type nomdhote.org.Il est possible de régler le filtre pour prendre en compte les adresses IP (et donc vérifier leur syntaxe), ou alors lesnoms de domaines locaux.Une fonction pour vérifier si le domaine accepte les Emails est prévue. Elle vérifie dans l'enregistrement du DNS laprésence d'un champ MX signifiant que le domaine est apte à recevoir des emails.

Page 23: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 23/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 23 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

VIII - #Zend_Filter 

#Zend_Filter va se décomposer 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 donnée selonson modèle, et non pas juste vérifier qu'elle respecte ce modèle. Zend_Filter  est un conteneur de filtres qui vapermettre de créer des chaînes de filtres sur mesure.Nous pouvons créer des instances de chacun de ces filtres et les utiliser individuellement, mais nous pouvons aussiles chaîner 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 déjà incorporés dans le Framework, vous pouvez écrire vos propres filtres en implémentantl'interface Zend_Filter_Interface. La seule méthode à définir est filter()

Si vous n'avez pas envie de charger une instance de la classe de votre filtre, et d'appliquer la méthode filter, vouspouvez passer par la méthode raccourcie get() de Zend_Filter , qui fonctionne sur le même principe que is(), deZend_Validate.

VIII-B - Zend_Filter_Input

Zend_Filter_Input en revanche, se voit reservé un paragraphe complet. Il mèle #Zend_Validate et #Zend_Filter , quisont très semblables en fonctionnement, afin de fournir un moyen de valider/filtrer les données d'entrée d'un script,typiquement on pensera à $_GET et $_POST.On crée une instance d'Input, une 'boite' ou 'box', composée à la fois de validateurs, et de filtres, puis nous passonsnos variables d'entrée à l'interieur, pour récupérer des variables saines en sortie. Le plan est donc :

Déclarer des règles de validation et de filtrage - Créer une instance Zend_Filter_Input avec les règles précédemmentdéfinies - Passer les données dans cette moulinette - Récupérer les données saines, et éventuellement les messagesd'erreur.

chainage de filtres ET de validateurs sur un tableau d'entrées<?php

$filters = array(  'nom' => 'StringTrim'

);

$validators = array(  'nom' => 'Alpha',

  'annee' => array( 'Int',

  array('Between', 1900, 2000)

));

Page 24: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 24/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 24 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

chainage de filtres ET de validateurs sur un tableau d'entrées$box = new Zend_Filter_Input($filters,$validators);

$box->setData($_GET); // filtrage et validation de toute l'entrée 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 spécifie quelle est la donnée d'entréeà analyser. Notez bien que chaque règle écrite dans les validateurs et les filtres, est un tableau dont la clé doitreprésenter le nom de la variable à analyser, la valeur représente une chaine épelant le nom du validateur/filtre àappliquer, on peut aussi fournir une instance personnalisée.Nous aurions pu utiliser la syntaxe équivalente $box = new Zend_Filter_Input($filters,$validators,$_GET); aussigetInvalid() retourne les problèmes rencontrés par le validateur. Les filtres eux ne rencontrent pas de problème, ilsappliquent leur(s) filtre(s), bêtement, 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 appliqués sur les valeurs, puis les validateurs  passent derrière. Il n'est donc pas necessaire, et déconseillé, d'appliquer le filtreZend_Filter_HtmlEntities sur les entrées, car celui-ci pourrait fausser le jugement desvalidateurs qui passent aprèsLe filtre Zend_Filter_HtmlEntities est de toute façon appliqué en fin de traitement automatiquement, la récupération 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') // jéjé

?>

Ici j'ai spécifié que je veux juste que ma variable 'nom', contenu dans mon tableau $_GET, soit non vide. Jelui passe volontairement des caractères spéciaux, comme 'é' (%9E), qui seront convertis automatiquement par Zend_Filter_Input , après y avoir fait passé les filtres d'abord, et les validateurs ensuite. On comprend ainsi que si

Page 25: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 25/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 25 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

 j'avais voulu passer du Zend_Filter_HtmlEntitiesen filtre, mon validateur passant après les filtres aurait pu être troublédans son jugement, qu'il aurait porté sur une variable déja modifiée.Vous pouvez changer le filtre d'echappement si celui-ci (htmlentities) ne vous convient pas, ce qui sera cependantrarement le cas. Procédez 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 défaut avec Zend_Filter_HtmlEntities) les données,une fois celles-ci d'abord filtrées, puis validées.

Ce n'est pas terminé, car d'autres options toutes aussi agréables, viennent compléter la classe Zend_Filter_Input .Par exemple la clause spéciale notée *, qui permet d'appliquer un filtre à toutes les valeurs contenues dans uneentrée (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 desvalidateurs, et pour valeur, le message de cet echec, nous avons d'autres méthodes :getUnknown() nous renvoie les champs qui sont présents dans la requête, mais qui n'ont pas été prévus dans unedes règles. Logiquement donc : des champs injectés :

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 cettesortie :

http://monserveur/cescript.php?adresse=Abc&uneinjection=injection<?php

abc // ok, mon filtre StringToLower a été appliqué

Page 26: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 26/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 26 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

http://monserveur/cescript.php?adresse=Abc&uneinjection=injectionarray(1) {

  ["uneinjection"] => string(9) "injection"}

hasUnknown() renvoie true si un champ a été injecté, et getUnknown() renvoie un tableau contenant les variables

injectées dans le script (par $_GET ici)De la même manière hasMissing() et getMissing() existent aussi, pour spécifier cette fois le contraire : si des champson été prévus dans les règles, mais n'apparaissent pas dans la variable d'entrée filtrée.Cependant, par défaut, Zend Framework ne les traite que si on le lui spécifie, via une constante de classe, et lavaleur 'required' :

Traitement des champs requis, mais absents dans le tableau d'entrée<?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 règle %rule%, mais n\'est pas fournit');

$box = new Zend_Filter_Input($filters,$validators,$_GET,$options);

if ($box->hasMissing()){Zend_Debug::Dump($box->getMissing());

}

?>

Intérrogé sans fournir de paramètre 'adresse', ce script va nous renvoyer :

array(1) {

  ["adresse"] => array(1) {

  [0] => string(71) "Le champ adresse est requis par la règle adresse, mais n'est pas fournit"

  }}

Nous avons utilisé une variable $options pour passer un message d'erreur que notre classe Zend_Filter_Input devranous retourner, comme déja vu.Notez que ce paramètre est le 4ème paramètre de l'instanciation de la classe, le 3ème représentant les donnéesà passer dans la boite.Attention, ceci est utilisé pour la métacommande 'required', si vous voulez personnaliser chaque message d'erreur 

de chaque validateur, procédez comme suit :

La métacommande 'messages', permet de personnaliser les messages d'erreurs, elle se fournit via un tableau indexédont la clé représente le numéro du validateur, relativement à sa position d'insertion :

Utilisation de la métacommande '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

Page 27: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 27/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 27 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Utilisation de la métacommande 'messages' 

1=>'Le champ adresse doit faire 10 caractères' // validateur d'index 1 : StringLength

)

));

$box = new Zend_Filter_Input($filters,$validators,$_GET);

?> 

D'autres métacommandes sont encore disponibles.Même si cette classe semble un peu complexe (nombreux tableaux imbriqués), elle suit évidemment une logiquequ'il suffit de capter (un peu d'entrainement et c'est bon), et elle s'avère non pas pratique, mais indispensable.

Page 28: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 28/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 28 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

IX - #Zend_Db

IX-A - Introduction

Ce composant est bien entendu d'une importance extrême. Il régit toute la couche d'abstraction aux bases dedonnées. C'est la partie du tutoriel la plus longue car elle détaille, dans un cas précis mais quelque peu commun(MySQL, via PDO), les différents cheminements des objets dans la jungle que représente #Zend_Db.Ce composant traite en effet plusieurs classes et plusieurs manières d'aborder la base de données. Il y a les couchesd'accès, les aides aux requêtes, les conteneurs de résultats (Rows), les jeux de résultats (Rowsets) pour le TDG

( Table Data Gateway) et la gestion des relations entre les tables.

Il est donc possible d'exécuter des requêtes simples, manuelles, de bien des façons différentes, ou alors de traiter des requêtes préparées, des transactions ; si bien qu'on a tendance à être un peu perdu au début et que des coupsd'oeil fréquents à l'API s'imposent.Je vais donc m'efforcer de détailler le coeur du composant, le parcours des classes et les méthodes résultantes sur les objets instanciés.

#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 dernières distrib de PHP, mais les driversne sont pas forcément présents ou activés sur les serveurs) d'utiliser PDO, car il s'agit de l'interface de branchementde PHP (Php Data Object), et l'extension PDO demeure très puissante pour piloter un SGBD.Seuls MySQLi, Oracle et DB2 sont disponibles hors PDO pour Zend_Framework, mais il existe des bibliothèques(non officielles) pour d'autres SGBD.De notre coté, nous parlerons de MySQL via PDO, vous devez donc posséder l'extension PDO activée sur votreserveur, mais c'est la configuration courante de PHP depuis PHP5.1.Vous devez aussi posséder le driver PDO de votre SGBD, je vous renvoie à la doc sur PDO pour plus d'info : certainsdrivers sont disponibles dans les binaires PHP depuis PHP 5.1, d'autres sont téléchargeables sur  PECL. Nous netraiterons 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 possède sa propre couche d'abstraction, mais la manipulation de #Zend_Db est quasiment la même,quelque soit le SGBD utilisé.

Le système complexe de #Zend_Db est basé sur de multiples héritages de méthodes. Ainsi, lorsqu'on veut seconnecter via un driver, cela crée un objet qui hérite de méthodes générales, puis les méthodes propres au driver sont rajoutées ou bien redéfinissent les méthodes générales. Il en résulte donc tout un arsenal de méthodesdisponibles. Tous les résultats (Statements) sont gérés par  Zend_Db_Statement , les résultats PDO le sont par Zend_Db_Statement_PDO , là encore, via la POO, tout est redéfini, factorisé et hérité. Les Exceptions envoyées sontdes instances de Zend_Db_Adapter_ExceptionNotez qu'un profiler, Zend_Db_Profiler , est aussi de la partie et permet de faire du profiling sur sa base. Le profilingest l'action d'écouter l'état de sa base lors de requêtes et notamment de déterminer le temps d'exécution de chaquerequête, le nombre de requêtes effectuées, et ainsi d'optimiser au mieux l'interfaçage de votre application avec votrebase de données, de manière à faire en sorte que celle-ci ne devienne pas un goulot d'étranglement pour votreapplication. Nous ne détaillerons pas le profiling dans ce tutoriel.

Les adaptateurs qui composent  #Zend_DB utilisent le profiler Zend_Db_Profiler eninterne. Celui-ci n'est pas activé par défaut car il consomme un peu de ressources pour ses calculs. L'activer est très simple.Un autre objet Zend_Db_Profiler_Firebug existe aussi : il envoie ses résultats dansFireBug.

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

• Zend_Db• Zend_Db_Adapter  • (Zend_Db_Profiler) non traité

Page 29: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 29/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 29 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

• Zend_Db_Select• Zend_Db_Expr  • (Zend_Db_Statement) peu utilisé de manière 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 méthode : une fabrique d'objets de connexion Factory(). Le design Pattern

AbstractFactory est utilisé, il est très classique et très simple.

Utilisation de la fabrique de Zend_Db pour créer 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'interfaçage avec votre base. Vous verrez par la suite que nousn'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 = pdo_mysql

database.params.host = 127.0.0.1database.params.username = developper

database.params.password = mypassword

database.params.dbname = myapp

Voyez comme Zend_Db joue avec Zend_Config . Très 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 méthodes de Zend_Db_Adapter_Abstract , puisZend_Db_Adapter_Pdo_Abstract , pour finir en une instance de la classe Zend_Db_Adapter_Pdo_Mysql . Voyezcomme l'architecture interne de ZF a été développée de manière souple et adaptable : nous passons sous 3 couchespour obtenir un objet connexion de bas niveau. Il faut dire qu'il existe un tas de SGBD différents, et ceux-ci ont lafâcheuse tendance à différer quelque peu au niveau des méthodes des drivers.ZF fait donc son boulot comme il faut : le développeur n'a que faire de ce qu'il se passe dessous.

Attention toutefois, lors de la création de l'objet $db, la fabrique ne teste pas si la connexion a réussi. La connexionne s'effectue que lors de l'appel d'une requête, ce qui peut être gênant. En général, on aime bien lorsqu'on crée uneconnexion, la tester. Et ne pas attendre de balancer une requête 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 méthode héritée de Zend_Db_Adapter_Abstract , getConnection(). Elleeffectue une connexion, puis retourne l'identifiant de connexion PDO (dont nous n'avons pas besoin en réalité)

Rappel de sécurité : il faut stocker ses identifiants d'accès aux bases de données dansdes fichiers HORS de la racine web.

Essai explicite de la connection<?php

// $params = array(...);

Page 30: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 30/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 30 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Essai explicite de la connectiontry {  $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 générique. Nous pourrions par exemple voir :SQLSTATE[28000] [1045] Access denied for user 'developer'@'localhost' (using password: YES)ou tout autre message nous signalant un problème (driver PDO introuvable, extension PDO non compilée, etc .)

Je ne détaille pas le schéma de la base de données, ca sera fait plus tard. Les requêtessont élémentaires, et ne concernent ici qu 'une seule table.Ce qu'il faut noter, ce sont les méthodes utilisées, et la présentation des résultats. Notreconnecteur étant configuré, exécutons une requête simple :

IX-B - Requêtes simplesquery() prépare une requête et l'exécute pour retourner un résultat issu de Zend_Db_Statement , dans notre casc'est un Zend_Db_Statement_PDO :

Utilisation de la méthode query() pour requêter 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 pasdéboussolé ; si ce n'est pas le cas, je vous conseille quand même un petit tour sur le manuel PHP, rubrique PDO.

Ceci au regard de la suite de ce tutoriel, concernant notamment les différents 'fetch_modes' (modes de captures derésultat) qu'offre PDO.Dans le cadre de l'utilisation de ZF, il n'est en théorie pas nécessaire de toucher aux fetch_modes de PDO, car c'estZF qui va s'en charger quand ca sera nécessaire. Vous pouvez toutefois spécifier un mode de capture via la méthodesetFetchMode() sur l'objet $db. Les modes PDO suivants sont acceptés : PDO::FETCH_{LAZY - ASSOC - NAMED- BOTH - NUM - OBJ}, le reste ne l'est pas : ceci est un choix de l'équipe de développement car le Frameworkrisque de ne pas être compatible avec. Leur utilisation lèvera donc systématiquement une exception, il est conseilléde ne pas se soucier du tout des fetch_mode bas niveau de PDO, et d'utiliser plutôt les méthodes de capture queZend Framework propose : c'est lui qui va piloter PDO pour vous, si vous utilisez un cas très particulier, vous pouveztoujours redéfinir des méthodes et créer votre propre interfaçage avec le SGBD.

Nous pouvons appliquer la méthode fetchAll() sur le résultat :

Utilisation de méthodes de Zend_Db_Statement<?php

$rows = $result->fetchAll();?>

$rows est de la forme :

array(2) {

  [0] => array(2) {

  ["num"] => string(1) "1"

  ["nom"] => string(3) "Foo"

  }

  [1] => array(2) {

  ["num"] => string(1) "2"

  ["nom"] => string(3) "Bar"  }

}

Page 31: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 31/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 31 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

A peu près toutes les méthodes de la classe PDOStatement sont applicables sur les résultats, fetchObject(), fetch(),fetchColumn()...Ce genre de requête étant rare, voyons une requête 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 requête échappée, c'est un string, on peut l'echo

$result = $db->query($sql);$data = $result->fetchAll();

La méthode quoteInto() s'applique sur l'objet de bas niveau $db et retourne la requête (non le résultat) en échappantles caractères avec la méthode 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 même chose, mais en spécifiant un alias SQL :

<?php

$order  = $db->quoteIdentifiers("order"); // `order`$column = $db->quoteColumnAs("order", "o"); // `order` AS `o`

Voyez la backquote ajoutée. C'est le caractère d'échappement spécial de Mysql pour sa syntaxe. Pour obtenir savaleur, getQuoteIdentifierSymbol() est là.Il est de même possible, et c'est plus courant, d'envoyer une requête directement via query(), en envoyant plusieursparamètres :

<?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 données sont automatiquement échappées ici.query() prépare la requête puis l'exécute pour retourner un jeu de résultats. Dans le cas où l'on souhaite conserver sa requête et profiter pleinement du mécanisme des requêtes préparées, il est possible de préparer ses requêtesmanuellement avec prepare() et ses amies, adeptes de PDO ou de mysqli, c'est le même mécanisme :Ici la requête est préparée, mais utilisée tout de suite, ceci est donc exactement équivalent à query(), qui prépareses requêtes 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 - Récupération de résultats

Bon, ceci est un peu long, c'est décomposé en 2/3 étapes : on prépare optionnellement la requête, on l'exécute et

on capture le jeu de résultats sur lequel nous appliquons une méthode de récupération (fetch***).

Page 32: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 32/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 32 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Il est possible de relier les 4 étapes en 1 seule, et ce via 6 méthodes qui vont toutes préparer, échapper les paramètres,exécuter la requête et récupérer le jeu de résultats. La seule différence entre elles est la manière de récupérer ce jeu de résultats.Elles exécutent directement une requête et retournent un jeu de résultats formaté de manière concrète. Selon lasituation, on choisira une méthode plutôt que l'autre et elles sont toutes adaptées à des situations courantes dudéveloppement web.

Ces méthodes 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 résultat, le nombrede dimensions des tableaux de retour, les clés et les valeurs :

fetchAll() renvoie tous les résultats 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 résultat 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 accéder aux résultats suivants après, utilisez cette méthode lorsque vous savez pertinamentqu'un seul résultat vous sera retourné (recherche par clé primaire).fetchOne() renvoie la valeur du premier résultat trouvé :

<?php

$result = $db->fetchOne('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France');

?>

string(1) : 1

1 est le numéro id du premier membre dont le pays est 'France'. Il est donc inutile de sélectionner plusieurs champsavec fetchOne(), seul le premier champ du premier résultat est retourné, il en résulterait un gaspillage de ressources.

fetchCol() renvoie tous les résultats sous forme de tableau à 1 dimension ne comportant que les valeurs de lapremière colonne :

<?php

$result = $db->fetchCol('SELECT id, name FROM membres WHERE country = :country', array('country'=>'France');

?>

array(2) {

Page 33: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 33/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 33 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

  [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 sélectionner plusieurs colonnes,seule la première est renvoyée.

fetchAssoc() renvoie tous les résultats sous forme d'un tableau à 2 dimensions dont la clé de dimension 1 est lerésultat 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() crée un tableau associatif. Changeons un peu la requête :

<?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 résultats sous forme d'un tableau à 1 dimension dont la clé est la donnée de lapremière colonne et la valeur est la donnée de la 2ème 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 sélectionner plus de 2 colonnes. La première colonne donnant la clé du tableau dans le résultat,il faut que ca soit une clé primaire de table, sinon le tableau va être écrasé par les données suivantes satisfaisantla requête :

<?php

Page 34: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 34/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 34 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

$result = $db->fetchPairs('SELECT country, name FROM membres WHERE country = :country', array('country'=>'France');?>

// $result contient :

array(2) {

  ["France"] => string(3) "Bar" // écrasement du résultat pour name='Foo'

}

Ces 6 méthodes s'adaptent donc à des situations du web et vous permettent de choisir la manière dont le résultatdoit vous être présenté.Si aucun résultat ne correspond à la requête, le retour est une identité à FALSE, c'est-à-dire qu'en castant le retour en bool, on obtient FALSE. Ainsi, si une chaîne doit être retournée, le booléen FALSE est renvoyé à sa place, mais siun tableau multidimensionnel doit être retourné, un tableau vide à une dimension est retourné (ce qui est équivalenten identité à FALSE).

Mémorisez bien : Ces 6 méthodes executent ET récupèrent le résultat (chacune à samanière), en une seule opération. Si vous voulez décomposer, pour pouvoir "fetcher" vousmême, dans un while, par exemple, utilisez alors la syntaxe vue plus haut, à base dequery().

IX-D - Insert, Update et Delete

Nous allons désormais tenter l'insertion, la mise à jour ou l'effacement de données. Nous allons commencer à écrirede moins en moins de syntaxe SQL et, pour rester clair, les noms des variables sont explicites. De cette manière, je n'écris pas la requête SQL réelle mais elle va se deviner très facilement, même si elle peut paraitre idiote danssa sémantique SQL, c'est pour le principe :

insert() insère des données dans une table, elle prend 2 paramètres :

insertion de données

<?php$rows = array (

  'name'  => 'David',  'country' => 'England',

);

$table = 'membres';

$affectedRows = $db->insert($table, $rows);$idInsere = $db->lastInsertId();?>

Les données sont échappées automatiquement. La valeur de retour est le nombre de lignes affectées.De même, lastInsertId() retourne le numéro identifiant de la dernière insertion, si celle-ci est une colonne autoincrémentée, comme c'est le cas très souvent des clé primaires, souvent aussi nommées "id".

update() met à jour des données dans une table, elle prend 3 paramètres :

Mise à jour de données<?php

$set = array (

  'country' => 'france',

);

$table = 'membres';

$where[] = 'name = David';

$where[] = 'country = England';

$affectedRows = $db->update($table, $set, $where);?>

Page 35: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 35/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 35 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Les données du SET sont échappées automatiquement, mais c'est à vous d'échapper le WHERE si c'est nécessaire.La valeur de retour est le nombre de lignes affectées. la clause WHERE est mise dans un tableau, si il y a plusieursarguments comme c'est le cas ici, un AND est automatiquement effectué.

Enfin, delete() supprime des enregistrements dans une table, elle prend 2 paramètres :

Suppression de données

<?php

$table = 'membres';

$where = $db->quoteInto('name = ?', 'Foo');

$deletedRows = $db->delete($table, $where);?>

Vous devez échapper le WHERE si nécessaire. La valeur de retour est le nombre de lignes affectées (suppriméesici). N'oubliez pas la clause WHERE, sinon toutes les données seront supprimées ;-) 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 fonctionnalités<?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 même. Ici on est en surcouche de PDO, donc toutes sescaractéristiques s'y appliquent.Les transactions existent quel que soit le SGBD piloté, car même s'il ne les supporte pas, lui, ou le moteur de stockagede la table intérrogée; PDO les émulera. C'est une des caractéristiques sympathiques de PDO.

D'origine, le mode 'autocommit' est activé dans l'adaptateur, qui transmet donc cet état à PDO ; cela signifie que touterequête envoyée au SGBD est systématiquement validée. Bien entendu, pour utiliser les transactions, votre SGBDet votre moteur de stockage doivent pouvoir les gérer. C'est le cas d'INNODB pour MySQL mais pas de MyISAM.

Page 36: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 36/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 36 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Si vous utilisez MyIsam, tout se passera comme si les transactions n'existaient pas, mais pas de message d'erreur :PDO émule les méthodes relatives aux tr ansactions, il les fait exister mais elles ne peuvent f onctionner que si cotéSGBD, tout est OKbeginTransaction() Désactive l'autocommit et démarre une transactioncommit() Valide la transaction courante et réactive l'autocommitrollback() Annule la transaction courante et réactive l'autocommit

Très 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 méthodes proposées par Zend Framework concernant lestransactions sont les mêmes que celles pr oposées par PDO dans PHP.

IX-F - Sélections

Et maintenant, nous allons voir grâce à Zend_Db_Select  comment effectuer des requêtes complexes (jointures,prédicats, etc .) sans écrire la moindre syntaxe SQL. Cependant, la rigueur reste de mise. Zend_Db_Select vapermettre d'écrire la syntaxe d'une requête SQL, manière objets, en s'affranchissant du SGBD utilisé en dessous :l'adapter va convertir la syntaxe objet en une syntaxe compréhensible pour le SGBD (car je rappelle que tous lesSGBD ne respectent pas forcément la norme SQL, et une syntaxe SQL [manuelle] peut donner lieu a des erreurssur un SGBD, mais pas sur un autre).En plus d'apporter cet avantage, lorsqu'il s'agit d'écrire des requêtes à la volée, vous allez voir que c'est bien plussimple de manipuler un objet, avec toutes ses méthodes pratiques.En effet, Zend_Db_Select est dite à interface 'fluent' : chaque méthode exprime de par son orthographe, ce qu'ellefait. Et chaque méthode retourne $this, donc on peut flécher et chainer les méthodes les unes à la suite des autres.Essayons un "SELECT id, name FROM membres WHERE country = 'usa' ORDER BY name ASC LIMIT 2" (syntaxeSQL pour MySQL - notre cas donc -).

select() permet d'écrire une requête de sélection complète, en utilisant un pourcentage infirme de langage SQL. Ellepermet aussi l'échappement automatique des caractères, elle gère tous les SGBD que gère l'Adapter, elle va traduirenotre requête façon objet en requête SQL compatible avec le SGBD interrogé via l'Adapter.

Exemple de requêtage de manière objet avec Zend_Db_Select<?php

$select = $db->select(); // récupération 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);?>

Page 37: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 37/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 37 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Bien entendu, les jointures sont possibles. En voici un exemple très 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 WHEREmessages.id = '2'" C'est la traduction MySQL.C'est tout simple, j'ai changé aussi la manière 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'exécution de la requête et nondans son corps.On peut effectuer tout type de jointure,  joinLeft(), joinRight(), joinFull(), joinCross(), joinNatural(). Les jointurespar défaut récupèrent *, mais on peut bien entendu les monter comme on le souhaite, de manière très propre. La

doc officielle vous y aidera.Les valeurs externes passées dans un select() sont toutes échappées automatiquement, pour éviter l'échappementautomatique, la classe Zend_Db_Expr permet de former une variable de clause non echappée.Pour effectuer un SELECT FOR UPDATE (spécifique Mysql), la méthode forUpdate() est là.

La méthode select() crée un objet Zend_Db_Select qui retourne lui-même, à chaque modification, ce qui nous permetd'enchaîner les actions par de multiples -> se succédant.Zend_Db_Select possède de même une méthode magique  __toString(), qui permet d'afficher la requête textuelletraduite par l'Adapter, par un simple <?php echo $select;?>. Utilisez-la pour bien voir comment la requête a été traduite(tout est échappé, les colonnes sont traduites par 'table.colonne'...). Vous pouvez aussi demander à visualiser unélément précis de la requête.

getPart() retourne une partie précise de la requête, demandée 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 précise de la requête, demandée via une constante de classe, exactement comme la syntaxede getPart()

Un petit mot sur limitPage() : permet d'effectuer une pagination, avec sélection automatique de la tranche de résultat :

<?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 méthode de retour de résultat déjàvu. Ici, limitPage() demande sur la liste de tous les membres, organisée par id inverse, de sélectionner pile la bonnepartie pour afficher la page 3, en ayant chaque contenant 10 résultats.Zend_Db_Select possède encore having(), group(), distinct(), forUpdate()...

Page 38: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 38/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 38 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

IX-G - Passerelle vers les tables

IX-G-1 - Généralites

Pour terminer, nous allons passer à la gestion de la passerelle vers les tables dont l'utilisation se rapproche de celle deRubyOnRails ou de CakePHP. L'accès aux données et aux tables est une partie très importante dans la modélisationd'applications n-tiers.Dans Zend Framework, une couche d'accès aux tables et aux enregistrements de celles-ci est prévue par défaut,mais toutes les classes mères sont abstraites. On pourra donc personnaliser entièrement les processus d'accès, sicelui par défaut de ZF ne nous convient pas.L'accès aux tables et à leurs enregistrement dans ZendFramework est matérialisé par Zend_Db_Table / Zend_Db_Table_Row  / Zend_Db_Table_Rowset , ils héritent 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 : elleimplémente le design pattern Table Data Gateway, elle effectue les requêtes personnalisées : elle représente unetable de la base de données (il y aura donc [au moins] autant de classes que de tables à mapper).

Ce schéma est modifiable. Toute table doit obligatoirement posséder une clé primaire sur au moins une colonne detable, Zend Framework ne sait pas traiter les tables qui n'ont pas de clé primaire lorsque vous utilisez la passerelleZend_Db_Table.En général, une table d'entités comporte une clé primaire, sur une colonne (il est de coutume de l'appeler 'id') quiest auto incrémentée. 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 même livre qu'une seule fois : dans la table emprunts, la clé primaire sera composéede 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 même membre, empruntant un même livre.Mais s'il existe plusieurs exemplaires de ce livre, alors on aura une clé primaire dans la table emprunts unique, enplus des 2 clés étrangères membres et livres. Un membre pourra donc emprunter plusieurs fois le même (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 représente une table (ou une vue) du SGBD, elle sert des objets Zend_Db_Table_Row . Ce sont lesrésultats mappés (propriétés = colonne de table). On les appellera les résultats. Ils implémentent le design patternRow Data GatewayZend_Db_Table_Rowset est un conteneur de résultats pourvu d'un itérateur, on appellera cela un jeu de résultats.C'est un design pattern connu aussi : le dataset.

Un résultat ne comporte pas d'accesseurs : on modifie une propriété directement par affectation. Par contre desméthodes existent pour récupérer des références de tables, lorsque les tables sont liées entre elles par une intégritéréférentielle (clés étrangères).La couche d'accès aux données agit donc en mode LazyLoading, elle ne charge pas automatiquement les collections

dépendantes, nous allons voir ça :Voici l'exemple utilisé ici, il est très 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 Ponçon');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');

Page 39: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 39/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 39 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

 

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 DELETECASCADE 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 décrit juste avant. Membres - Livres - Emprunts.Emprunts possède une clé primaire sur 2 colonnes, un livre peut être emprunté plusieurs fois (il a des exemplaires),mais un même membre ne peut pas posséder plusieurs exemplaires d'un même livre).La table emprunts répond 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 avionsvoulu retoucher le mécanisme interne de la passerelle, nous aurions étendu Zend_Db_Table, dans laquelle nousaurions modifié la logique (ce qui est très pratique pour personnaliser totalement sa couche d'accès aux données).On placera les fichiers des passerelles (qui comportent donc des classes), qui ne sont autre que notre logiquemétier, dans un répertoire /modele qui se trouvera hors racine web, car il n'a pas besoin de s'y trouver. On rajouterasimplement son chemin dans l'include_path, au début des scripts (en attendant un système automatisé, prévu; vouspouvez toujours créer le votre).

Comme je vous l'ai dit, je fonctionne dans cet article avec l'autoload activé, pour économiser des lignes. Toutes lesclasses sont supposées incluses et disponibles.

IX-G-3 - Définition 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);

Page 40: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 40/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 40 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

modele/Membres.php }

}

modele/Livres.php<?php

class Livres extends Zend_Db_Table_Abstract{

   protected  $_name = 'Livres';  protected  $_primary = 'isbn';

}

La variable $_name représente le nom de la table SQL, et la variable $_primary représente la clé primaire (c'estun array si la clé est multi-colonnes).Ici, je les ai précisés, mais le mécanisme de Zend Framework permet de s'en affranchir. Si on ne spécifie pas la cléprimaire, ZF va utiliser DESCRIBE TABLE pour se la chercher lui-même. Si le nom de la table n'est pas précisé, alorsle 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 spécifier la config de sa table dans la définition de saclasse, de plus, on peut vouloir nommer sa classe, et donc son fichier de classe, différement du nom de sa table ;-).

$_sequence est un booléen à true par défaut dans l'abstraction. Il signifie que nos clés primaires sont en auto-incrémentation, on ne le spécifie donc pas.Il peut contenir aussi un string pour agir sur les séquences, une notiond'unicité de clé qu'utilise PostgreSQL ou encore DB2Le système de passerelle vers les tables de Zend Framework ne fonctionne qu'avec des tables ayant une cléprimaire(ou une séquence)

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 rôle 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 défaut

));

}

$_referenceMap sert à lier les tables. Le principe est simple : toute table recevant une clé étrangère, doit remplir cetattribut de classe pour préciser quelles tables, et quelles clés sont liées avec elle.

La clé primaire d'emprunts est sur 2 colonnes. C'est spécifié par un array.La definition des références est très importante et indique la logique de notre base de données au Framework.Pour les emprunts, dans la table emprunts, un membre est un emprunteur. C'est en fait le rôle UML qui relie les2 classes dans un Diagrammes de Classes de Conception. On fait référence à la classe Membres, et la colonneest num.Il est possible qu'il y ait plusieurs colonnes (même si c'est rare). Lorsqu'on a plusieurs rôles, par exemple un membre

est l'emprunteur d'un livre mais il pourrait aussi être son auteur. On aurait alors une 2ème clé de membres dansemprunts, et on aurait par exemple matérialisé le rôle par "Auteur" ; en plus du rôle "emprunteur". Il y a autant derôles UML que de dépendances entre les tables.Si la clé de référence est une clé sur plusieurs colonnes, on les spécifiera dans un array(), dans le même ordrequ'elles ont été définies dans la classe parent.

Si on ne spécifie pas la clé de la table parente (refColumns), alors la clé primaire déclarée est prise par défaut.

Page 41: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 41/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 41 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Je vous conseille quand même de spécifier la refColumns, je sais que les programmeurs sont paresseux (Lazy), maisrien qu'en lisant la définition des références, on a tout de suite le schéma de la base et des classes en visuel. C'esttrès agréable lorsqu'on reprend 1 an après le projet (même si on a commenté son code).

En plus de ceci, les classes passerelles des tables ont nécessairement besoin de notre adaptateur, rappelez vousnotre objet $db qui sert à manipuler la base au plus bas niveau. Forcément, les classes passerelles en ont besoin,

et plutôt que de le passer en paramètre aux objets à chaque fois, vu que nous n'utilisons qu'une seule base et uneseule connexion, nous allons dire à tout le système de passerelle que l'adaptateur par défaut est $db.Dans le script principal, juste après avoir crée notre objet $db, nous le déclarons en tant qu'adaptateur par défautaux passerelles :

Déclaration de l'adaptateur par défaut 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 objetsde connexion, mais des méthodes simplifient la tâche, ou alors redéfinissez une classe, tout reste possible.findByNom() est une méthode que j'ai écrite moi-même, elle va permettre de chercher des membres par leur nom.Regardez comment elle est écrite.On récupère l'adaptateur, car c'est lui qui possède la méthode d'échappement quoteInto(). On échappe le paramètre,casté au préalable en string, et on envoie ca à fetchRow(). L'échappement des paramètres n'est pas automatique,nous devons donc utiliser les méthodes quote(), quoteInto() ou quoteIdentifier(), de l'adaptateur. Nous les avonsdéjà vues.Dans les classes métier, on définira donc toute la logique métier d'accès aux données (findByNom(), mais aussi desméthodes du style findLivreLePlusRecent(), ou encore findPaniersVides()...), et c'est le contrôleur qui accèdera à

cette logique, dans un modèle MVC.

Outre les méthodes métier que nous pouvons écrire, il y en a déjà pas mal qui sont implémentées dans ZF. Ainsi,sur des instances des classes Membres, Livres ou Emprunts :find() recherche des enregistrements par clé primaire. Vous récupérez un jeu de résultats (Rowset) contenant lesenregistrements correspondants. Si on passe à find() un tableau, alors on cherche plusieurs enregistrements :

Recherche par clé primaire<?php

// ... Définition de l'adaptateur et des classes passerelles ...

$membre = new Membres();

$membresTrouves = $membre->find(array(1,2));?>

createRow() retourne un résultat vide, prêt à etre rempli ou utilisé.fetchAll() exécute une requête personnalisée, retournant un jeu de résultats (on choisira la méthode fetchAll()lorsqu'on sait que notre requête est susceptible de retourner plusieurs résultats).fetchRow() exécute une requete personnalisée, retournant un résultat (on choisira la méthode fetchRow() lorsqu'onsait que notre requête ne retourne qu'un seul résultat ; 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 dépendantes...)getDependantTables() nous rappelle les tables dépendantes de l'objet, que nous avons configurées au préalable,il s'agit d'un tableau PHP.

Page 42: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 42/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 42 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

insert() et update, sont identiques à celles déjà vues mais mappées sur la table en cours (on ne spécifie pas lenom de la table, juste les paires colonne->valeur). select(), génère un objet Zend_Db_Table _Select , comparable àZend_Db_Select (déja vu plus haut), mais verrouillé sur la table dont il est issu.

Les méthodes fetchAll() et  fetchRow() acceptent en paramètre un objet Zend_Db_Table_Select, tout comme le font les méthodes de l'adaptateur. Cet objet sert 

à diriger la requête, qui par défaut est de type "select *".

IX-G-4 - Les résultats (Row)

Nous venons de décrire les schémas de passerelle de nos tables ainsi que la plupart des méthodes applicables sur les classes de définition étendant Zend_Db_Table_Abstract . Lorsque nous cherchons un résultat (fetch***), selon laméthode utilisée, nous nous retrouverons avec soit une instance de Zend_Db_Table_Row (un résultat unique), soitune instance de Zend_Db_Table_Rowset (un jeu de résultats uniques Zend_Db_Table_Row ).(Ces 2 conteneurs de données spéciaux sont redéfinissables de manière très simple, si le coeur vous en dit.)Pour l'exemple, createRow() nous retourne un unique résultat, ce qui est logique ; en revanche, find() peut trouver plusieurs résultats. La méthode find() retourne donc un jeu de résultats, fetchAll() retourne un jeu, tandis que

fetchRow() retourne un résultat. C'est très important car selon le type d'objet retourné, nous ne pourrons utiliser lesmêmes méthodes dessus. Si on nous retourne un jeu de résultat, on ne pourra pas appliquer les méthodes d'unrésultat dessus. Faites y attention, cela a tendance à embrouiller au début. Même si la logique est tout à fait de mise,il faut la comprendre, lorsqu'on y est pas habitué.

Récupération, 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 résultat, toutes les colonnes SQL sont mappées en tant que propriétés de l'objet. Attention, en utilisant PDO,le paramètre PDO::CASE_NATURAL lui est passé par Zend Framework. Cela signifie que les échanges entre leSGBD et l'OS se font en casse naturelle. Ainsi sous Windows, et concernant MySQL (je n'ai pas d'infos pour d'autresSGBDs) la casse n'est pas existante, et une colonne appelé 'MACOLONNE', pourra être appelée via 'macolonne',mais pas sous Linux, qui respecte la casse. Il est conseillé de toujours appeler ses noms de tables/colonnes, enminuscules, pour éviter les ennuis de plateforme. Dans tous les cas, ZF utilise lui-même en interne la casse naturelle,il est possible de changer le mode, les méthodes sont là, mais ça va troubler ZF, de manière générale, il vaut mieuxlaisser ZF gérer les paramètres PDO pour nous. Nous n'utilisons pas PDO nous programmeurs mais bel et bien leFramework qui, lui, utilise PDO comme il le souhaite (dans nos exemples, basés sur PDO)Regardez, $julien->date_naissance signifie que j'accède à 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 méthodesave().

Ainsi, sur un résultat, je peux aussi utiliser :save() sauvegarde le résultat en base. Notez que si celui ci n'existe pas (issu d'un createRow(), par exemple) alorsune requête SQL "insert" sera utilisée, sinon "update" sera utilisé.delete() efface (dans la base bien sûr) le résultat.toArray() est très pratique et transforme le résultat en un tableau du type 'nom_de_la_colonne' => 'valeur-correspondante'.setFromArray() est du même style, elle attribue des valeurs à notre objet suivant un tableau passé en paramètre dutype 'nom_de_la_colonne' => 'valeur-correspondante'. Ceci est très utilisé lors de récupération de formulaires, pour remplir rapidement un résultat et le sauvegarder.D'autres méthodes find* existent, décrites plus bas dans la section gestion des relations.

Page 43: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 43/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 43 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

IX-G-5 - Les jeux de résultats (Rowset)

Certaines méthodes, donc, renvoient un jeu de résultats. Un jeu de résultats (Zend_Db_Table_Rowset ) est un simpleconteneur de résultats implémentant les interfaces SeekableIterator et Countable de la SPL. J'aurai aimé seekableaussi, mais ca n'est pas le cas.

Bref il s'agit d'un conteneur de résultats, itérable via un foreach et comportant toutes les méthodes héritées de la SPL(current(), count(), next()). Un genre de ResultSet, pour les habitués de Java ;-)

<?php// ...

$tableLivres = new Livres();

$deuxLivres = $tableLivres->find(array('978-2212116762','978-2841773381'));foreach ($deuxLivres  AS $ceLivre){echo $ceLivre->titre.'<br />';}

?>

Ici je récupère les 2 livres par leur clé primaires (Isbn), et j'affiche leur titre. Si je ne veux qu'un enregistrement, jeprocède comme suit :

<?php

// ...

$tableLivres = new Livres();

$leLivre = $tableLivres->find('978-2212116762')->current();$leLivre->titre = 'Best Practices PHP 5';$leLivre->save();?>

Je suis obligé de spécifier que je veux dans le jeu de résultats le premier (et unique) résultat, en l'atteignant par current(). Les autres méthodes d'accès proviennent de la SPL et d'Iterator.En implémentant aussi Countable, j'ai accès à une méthode count() pour compter le nombre de résultats retournés(attention, mon code n'a ici aucun sens sémantique, selectionner tous les résultats 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 données';

?>

Une méthode toArray(), comparable à celle d'un résultat, est disponible sur un jeu de résultats. Elle renvoie untableau multidimensionnel de résultats :

<?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 Ponçon"

}[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é) "

Page 44: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 44/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 44 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

["auteur"] => string(15) "Philippe Rigaux"}

}

*/

?>

IX-G-6 - Gestion des dépendancesNous allons nous pencher sur la gestion des dépendances sous ZF. Si les termes 'Lazy mode', et 'full mode' vousdisent quelque chose, sachez que ZF est lazy. Lors de la récupération d'un enregistrement, il est possible de faireréférence à ses parents ou à ses enfants. Ce n'est que lors de l'appel de la référence que le résultat est chargé.Si par exemple je récupère un membre, je peux facilement afficher les titres des livres qu'il emprunte. Ou encore,si j'ai un enregistrement représentant un 'emprunt', je peux retrouver, grâce à des méthodes spéciales, le membrey faisant référence ou bien le livre.Zend Framework tire toute sa puissance de PHP5 et, grâce aux méthodes magiques __get(), __set() et surtout __call(), il va intercepter les appels de méthodes pour nous, de manière très intuitive. Je vais vous donner un exemple.Avant toute chose, sachez que ces méthodes ne s'appliquent que sur un résultat. On ne peut pas les appliquer sur des instances de jeu de résultats, ce qui est logique.

Je récupère 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 récupère le membre n°=1, n'oubliez pas que le retour de find()est systématiquement un jeu de résultats (Rowset), je dois donc passer par  current() (méthode deZend_Db_Table_Rowset_Abstract) pour récupérer mon résultat.

Sur un résultat, je peux trouver ses dépendances par rôle. En effet, Zend_Db_Table_Row est doté d'une méthodemagique, qui va intercepter les appels du style find<tableClass>Via<IntersectionTableClass>().$monMembre->findLivresViaEmprunts() retourne donc un jeu de résultats représentant tous les livres - empruntéspar monMembre. Le foreach est un itérateur, n'oubliez pas $sesLivres est un jeu de résultats : en itérant dessus,on récupère des résultats représentatifs de livres. Sur ces résultats, nous avons accès aux propriétés de l'objet, icic'est titre qui nous intéresse.

find<tableClass>Via<IntersectionTableClass>() récupère un jeu de résultats dans un schéma àcardinalités de type 'plusieurs à plusieurs'. C'est un raccourci de commodité de la méthodefindManyToManyRowset('tableClass','tableClass', 'role'). Pensez bien cardinalités dans un modèle conceptuel.Un membre peut emprunter zéro ou plusieurs livres. Un livre peut être emprunté par zéro ou plusieurs membres(on a dit qu'on raisonnait de cette manière, 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 procède 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>() récupère un jeu de résultats d'une table dépendante, dans un schéma '1 à plusieurs'. C'est

un raccourci de commodité de la méthode findDependentRowset('tableClass','role'). 1 livre peut avoir plusieursréférences dans la table emprunts, nous récupérons donc un jeu de résultats sur lequel nous itérons.

Page 45: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 45/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 45 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Agissons enfin dans le dernier sens : nous avons un résultat de type emprunts, et nous voulons connaître le nomdu membre à qui il appartient :

<?php

// ...

$tblEmprunts = new Emprunts();

$monEmprunt = $tblEmprunts->find('2','978-2841773381')->current();echo $monEmprunt->findParentMembres()->nom.'<br />';

findParent<tableClass>() récupère un jeu de résultats d'une table parente. C'est un raccourci de commodité de laméthode findParentRow('tableClass','role'). De type '1 à 1' (1 emprunt donné ne fait référence qu'à un membre),nous récupérons un unique résultat, sur un Row donc.

Je n'ai pas parlé des rôles mais il est possible d'y faire référence. Si par exemple un membre emprunte un livremais peut aussi être son auteur, alors lister les livres écrits par un membre se fera de la manière $leMembre->findLivresViaEmpruntsByAuteur().Tout est automatique, Zend Framework se charge pour nous de faire les jointures nécessaires. Je n'ai pas non plustesté les résultats de mes requêtes : un find(), peut par exemple ne retourner aucun résultat, à vous de le gérer.Idem pour l'effet de cascade des SGBDs. ZF inclue un système de cascade, qui permet d'agir à la manière d'unSGBD, en actionnant en cascade les résultats (DELETE ou UPDATE) : je n'en parle pas ici, car la gestion de l'intégritéde la base doit être laissée à la charge du SGBDR et non de l'application qui tourne dessus. Le staff de ZF nous leprécise clairement : se reposer sur la gestion de l'intégrité référentielle via ZF n'est pas recommandé et peut mener àdes comportements hasardeux. Mes tables sont au format Innodb, un format de table gérant les relations et l'intégrité, je ne m'occupe en rien de cela dans mon code applicatif.

  Abuser des méthodes de récupération des dépendances va générer une chargeinsoutenable pour le SGBD. Ces méthodes sont là, mais en pratique on les utilise très très peu. Utiliser une méthode de récupération de dépendance dans une boucle foreach, par exemple, amène à une dégradation certaine des performances de l'application.Créez vous même vos jointures, limitez les champs retournés (*, ne sert que très trèsrarement), et si possibles, utilisez des vues et des procédures stockées. N'agissez pas à

l'aveugle en vous reposant sur le framework, ayez toujours en tête les requêtes envoyéesà votre SGBD. ZF ne fait que proposer une interface avec les SGBDs, à vous de l'utiliser de manière correcte, réfléchie et sensée.

Les 3 méthodes de récupération des dépendances que nous vennons de voir, prennent optionnellement en paramètre un objet Zend_Db_Table_Select, très pratique pour limiter les colonnes des résultats, et ne pas choisir '*', comme c'est le cas par défaut.

IX-H - Rappels

#Zend_Db et tous ses amis n'est pas une solution ORM. Un ORM est un système qui masque totalement les données

manipulées dans l'application, du support qui va servir à les faire persister (une base de données très souvent).Le système 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.

Page 46: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 46/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 46 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

X - #Zend_Log

Ce composant plutôt petit est très facile d'utilisation. Il va servir à journaliser des évènements divers : une exceptionlevée, la base de données qui ne répond plus, une tentative d'intrusion...Plutôt que d'écrire à la main le code, #Zend_Log est relativement complet. Sa classe, Zend_Log va utiliser des

Zend_Log_Writer_*** afin de définir le(s) support(s) qui va contenir les logs. On a le choix entre un flux (fichier, sortiestandard...) ou une table de base de données.Pour les tests, on a un objet déguisé (Mock), ou un NULL, qui va neutraliser la journalisation.Enfin, les messages loggués pourront être mis en forme, via des Zend_Log_Formatter_** , et même filtrés.

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 problème');?>

Sur le journaliseur, j'ai 7 méthodes à disposition, qui vont dépendre du degré de gravité de l'erreur survenue. Ces 8degrés sont compatibles RFC-3164 et viennent du protocole BSD syslog, compatibles PEAR log.

EMERG 0 : Urgence : le système est inutilisable

ALERT 1 : Alerte: une mesure corrective doit êtreprise immédiatement

CRIT 2 : Critique : états critiquesERR 3 : Erreur: états d'erreur  WARN 4 : Avertissement: états d'avertissementNOTICE 5 : Notice: normal mais état significatif  

INFO 6 : Information: messages d'informationsDEBUG 7 : Debug: messages de déboguages

Issu de la doc officielle. Ainsi si j'applique une méthode err() à mon objet de log, je journalise une erreur de niveau 3.Mais qu'est ce qui est enregistré, réellement ? Et bien il s'agit de 4 infos, timestamp - message - priority -priorityName. Pour rajouter un paramètre à prendre en compte lors d'un évènement de journalisation, indiquez-lepar 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 déconner');

Et voilà, mon journal retiendra en plus la mémoire utilisée par PHP à cet instant-là : à chaque fois que je journaliseraiun évènement.Ici, ils sont retenus dans un fichier. Pour les enregistrer en base de données, et bien j'instancie un nouveau support, je peux en utiliser autant que je veux, j'écrirai donc mon log à plusieurs endroits différents, mais avec toujours uneseule méthode :

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

Page 47: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 47/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 47 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Enregistrement du journal à plusieurs endroits$dbWriter = newZend_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 évènement de type 'notice' va être enregistré dans le fichier ET dans la base de données. J'ai pris soin delui fournir une instance de Zend_Db_Adapter (voir chapitre sur #Zend_Db).Je lui ai dit aussi que je veux utiliser la table nommée 'logTable', et que sur cette table, à chaque évènement du journal, la colonne 'date_col' enregistre le paramètre 'timestamp' du journal, et 'message_col', enregistre le paramètre'message'. Facile quand même...

Si un jour j'ai envie de débogguer et de désactiver mon journal, alors je le fais à l'endroit où je l'ai configuré (et nonà chaque endroit ou je journalise... vla la galère!), et je lui passe un support spécial de leurre, en désactivant lesautres réels, évidemment.Il s'agit du Zend_Log_Writer_Null , je peux même chainer en faisant un $log = new Zend_Log(newZend_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 propriété publique qui contient un tableau où sont stockés lesévènements du journal, on y accède donc par $mock->events[**]['message'], par exemple.

Je vais vite fait parler des formateurs, qui servent à formater les évènements 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');

Page 48: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 48/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 48 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 méthode Zend_Log::factory(), elle permet de décrire des objets log avecune seule méthode prenant en paramètre 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 etclasses abstraites existent pour écrire et brancher son propre système ou pour étendre celui-ci.Zend_Log, grâce aux mock, permet aussi un test facile de l'application.

Page 49: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 49/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 49 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 séparation du code de traitement et de la mise en forme des résultats. Il permetde créer une sortie vers un ou plusieurs fichiers template, un fichier de vue. Cela fait partie intégrante de MVC maisaussi de toute application bien fondée.

#Zend_View n'est donc pas un moteur de template à proprement parler, car il ne fusionne pas 2 syntaxesdistinctes. Il prépare des données qu'il va envoyer à un ou plusieurs fichiers de vue. Cette vue va s'occuper desdonnées reçues et les présenter.#Zend_Layout, relié à #Zend_View constitue une approche de template simple et efficace. En pratique, voici unscript 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 créons d'abord une instance de Zend_View , puis nous lui spécifions où se trouvent les scripts de vue que nousvoulons utiliser.

setScriptPath() indique à notre instance de vue, où chercher les scripts de vue qu'on va lui faire charger. Cela sefait une fois pour toutes, mais il est possible de spécifier le chemin via une autre méthode :

addScriptPath() ajoute un dossier dans la liste des dossiers de scripts de vue. Notre instance va chercher dans ledossier spécifié par addScriptPath() d'abord puis, si elle ne trouve pas les vues, elle cherchera alors dans le dossier spécifié par setScriptPath(). C'est un mécanisme classique de pile (FILO) qui permet d'empiler des dossiers descripts de vue. C'est intéressant si l'on veut créer plusieurs looks sur notre site et spécifier un des looks via cetteméthode.

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 méthode

assign($myVar,'my data') existe aussi. On ne peut passer à assign() que 2 types : des tableaux de résultats (commec'est le cas dans notre exemple) ou des chaînes de caractères ; du moment que, dans la vue, on les utilise commeil faut.clearVars() détruit toutes les variables préalablement passées à la vue.

render() enfin, retourne le résultat de la vue, que l'on doit afficher (echo) ou bien capturer dans le buffer de sortiede PHP.Du côté du fichier vue myview.phtml, maintenant, nous pouvons le présenter 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>

Page 50: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 50/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 50 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

 </tr>

<?php endforeach; ?></table>

<!-- Pas de membres à lister -->

<?php else : ?>

<p>Pas de résultats</p>

<?php endif; ?>

Ici, j'ai simplement utilisé PHP pour décrire ma vue, mais rien n'empêche d'utiliser un moteur de template quelconque.La doc officielle offre un bon exemple. Nous remarquons que toutes les propriétés envoyées à la vue via assign(), ouen affectation directe, sont disponibles dans le contexte de la vue et sont donc utilisables via la pseudo variable $this :

<?php

// script de contrôle

$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.phtmlecho $this->someVar // affiche someVal;?>

Bien entendu, étant dans la vue, nous avons à disposition une méthode d'échappement, la fonction bas niveauimplémentée par défaut est htmlspecialchars(), avec le paramètre ENT_COMPAT (pas d'échappement desguillemets simples), sur le jeu de caractères ISO-8859-1.

escape() échappe la variable passée en paramètre pour un affichage plus serein.

setEscape() spécifie une fonction d'échappement personnalisée, qui peut être n'importe quoi : une fonction PHP oumême une méthode statique de classe, voire méthode d'un objet :

$view->setEscape('myClass','myEscapeFunction');$view->setEscape($myObj,'myObjEscapeFunction');

En général, on pourra spécifier  htmlentities() et, dans le cas d'une fonction telle que celle-ci, qui accepte unparamètre spécifiant l'encodage de caractères, on peut le changer :

setEncoding() spécifie 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 utilisée pour intercepter les appels à des variables n'existant pas. Par défaut, elle est réglée sur false, si vous lui passez true, et que dans votre vue vous appelez $mavue->uneVariableInexistante, alors une erreur NOTICE sera levée.

Zend_View est utilisé par le modèle MVC, et donc par Zend_Controller_*. Ces composantsconfigurent de manière automatique la v ue, rendant son utilisation au sein du systèmeMVC très 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 présenter mais juste un exemple.

Page 51: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 51/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 51 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 détailler 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 problème du <select><option></option></select>, avec une boucle dans le <option> pour sélectionner la valeur déjà présente en base. Ça se faittrès simplement ici, avec :

script de contrôle<?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 présentes 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 orientés vers le code HTML contenu dans <head>. En plus d'éventuellement utiliser un moteur detemplates, nous pouvons écrire des helpers personnalisés. Voici tout de suite un exemple, imaginons :

script de vue<?php

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

La méthode showCart() est une méthode personnalisée qui a pour but d'afficher clairement le nombre d'articles dansun panier. La méthode est issue d'un helper personnalisé qui pourrait ressembler à ceci :

Page 52: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 52/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 52 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

<?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 tête : la classe doit s'appeler Zend_View_Helper_MonHelperPerso pour une méthode nommée monHelperPerso(), ceci se trouvant dans unfichier MonHelperPerso.php.Notez la casse, elle fait partie des conventions de nommage que nous avons rappelées en début de tutoriel.

Avec les helpers personnalisés, on peut "casser" son code et une logique de séparation comme celle-ci peut êtreutilisée en complément avec la méthode addHelperPath().

addHelperPath() ajoute un dossier dans la liste des dossiers des helpers (fonctionne sur le même principe que

"scriptPath"). Notre instance de vue va chercher dans le dossier spécifié ici, sinon dans le dossier par défaut Zend/View/Helper/.On peut donc ranger ses vues et ses helpers, et ainsi correctement séparer son code si on le souhaite.

setBasePath() permet de préciser le dossier de base de la vue, il s'agit en fait du dossier contenant les dossiersscripts/ helpers/ et filters/. Méthode de convenance évitant des appels successifs.

Autre fonctionnalité : la répétition de motifs dans plusieurs vues peut être factorisée (extraite, écrite à part). Cecigrâce 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 paramètre. Le tableau de données ($this->data) passé enparamètre doit être de la forme array( array('nom'=>'valeur','prenom'=>'valeur') ).C'est exactement ce que nous donne comme résultat un fetchAll() (Consultez le chapitre #Zend_Db).

Page 53: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 53/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 53 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

XII - Zend_Layout

Zend_Layout  travaille de mèche avec Zend_View . Vous devez être familier à Zend_View  pour comprendreZend_Layout . #Zend_Layout introduit un pattern "two step view", qui va permettre de rendre une vue dans une vueplus générale 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 découplé. Nous utiliserons ce dernier car nous ne parlons pas du système MVC dans cet article. Quoiqu'il en soit, Zend_Layout possède une dépendance versZend_View (Zend_View_Interface plus précisément) et a besoin d'une vue pour fonctionner.

XII-A - Principe

Le principe de Zend_Layout est simple: créer et gérer une vue globale dans laquelle sera rendue une vue particulière(ou plusieurs d'ailleurs).

Exemple simple d'utilisation de Zend_Layout

<?php

// Création de la layout$layout = new Zend_Layout(array('layoutPath'=>'path/to/layouts', 'layout'=>'main'));

// Création 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 précédemment dans une variable de layout appelée "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: création de l'objet de vue, configurationdes chemins (notamment le chemin des scripts de vue), puis rendu banal de la vue comme déja abordé dans lechapitre précédent.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 préciser le chemin vers les scripts de layouts, ainsi que lenom de la layout à rendre.Dans un site web réel, en général, une seule layout est présente, c'est pour cela qu'on ne précise pas le nom decelle-ci à la méthode render() (comme avec Zend_View ), mais on préfère la configurer via le constructeur.Le tableau du constructeur prend comme clés '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 depréciser l'endroit où se trouvent les scripts de layouts (l'équivalent du 'scriptPath' de la vue Zend_View ). Bien sûr,des méthodes setLayout() et setLayoutPath() existent aussi.

Par la suite, nous rendons la vue classiquement mais nous n'affichons pas son contenu, nous l'enregistrons dans unevariable de Zend_Layout , ici appelée 'content' pour l'exemple. En réalité, vous pouvez utiliser n'importe quel nom, etvous pouvez même 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.

Page 54: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 54/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 54 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Le script de layout (main.phtml pour nous) est un script de vue, il sera rendu par  Zend_View et se comporte de lamême manière. Simplement, à l'interieur, vous allez avoir accès à votre objet layout en interrogeant l'aide de vue(ViewHelper) appelée 'layout'; au moyen de $this->layout(). Vous accédez ainsi aux variables de layout (nous enavons une dans notre exemple: 'content') et vous placez leur contenu où vous voulez.

XII-B - ExemplesVoici un exemple simple d'implémentation "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 même 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 différente de site.phtml

Pour aller plus loin avec #Zend_Layout et utiliser le système MVC avec, consultez cet atelier 

Page 55: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 55/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 55 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

XIII - Zend_Form

#Zend_Form est un composant qui comme son nom l'indique permet de créer et de gérer des formulaires Web(x)HTML. Ce composant est extrêmement pratique en ce qui concerne la gestion et la présentation des données demanière générale. Aussi, si ce n'est déja fait, il est conseillé de lire le chapitre sur #Zend_Validate et #Zend_Filter 

afin de bien comprendre les principes de #Zend_FormPour rester simple, #Zend_Form se décompose en plusieurs classes :

1 Zend_Form : le formulaire en question, comme il est validable, il implémente Zend_Validate_Interface2 Zend_Form_Element_* : des éléments de formulaires, (des champs, des boutons ...), ils héritent tous de

Zend_Form_Element , qui implémente aussi Zend_validate_Interfacecar chaque élément est validableindépendamment

3 Zend_Form_Decorator_*  : des décorateurs. Ces objets ont pour seule responsabilité de présenter visuellement les éléments, et le formulaire contenant les éléments

Un formulaire se compose donc d'éléments qu'il faut lui ajouter, ainsi que d'autres petites options. Voyons en toutde 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('légende')  ->setMethod('POST')

  ->setName('dvp-form')  ->setView(new Zend_View);

 

echo $form;

Les méthodes parlent plutot d'elles-mêmes je pense, inutile de les détailler. Afficher un formulaire est aussi simpleque de faire un "echo" devant l'objet mais attention, la plupart du temps le formulaire Zend_Form aura besoin d'unobjet Zend_View car il va en utiliser les aides (aides de vues, ou "View Helpers") pour pouvoir afficher les élémentsqui le composeront plus tard. Zend_Form est capable d'aller chercher l'objet vue utilisé dans le système MVC de lui-même, comme nous n'utilisons pas le modèle MVC de Zend Framework ici, nous devons passer manuellement unobjet Zend_View à Zend_Form, de manière à ê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 très important de noter qu'entre la composition du formulaire et/ou de ses éléments et leur rendu HTMLrespectifs, se situent des objets appelés "décorateurs". Si le rendu HTML ne vous plait pas, pas de panique! Nousle modifierons plus tard grâce aux décorateurs.Notez aussi que la légende, ou encore la description du formulaire n'apparaissent pas dans la source HTML, làencore, c'est une question de décorateurs.

Certains des paramètres de configuration que nous avons définis auraient pu être utilisés avec setOptions(), ouencore avec setConfig() qui prend comme argument un objet Zend_Config.Notez bien que le composant #Zend_Form plus que tout autre, propose toujours différentes méthodes permettantd'arriver au même résultat, selon le cas dans lequel vous vous trouvez vous utiliserez l'une ou l'autre des manières

de faire.

Page 56: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 56/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 56 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

XIII-A - Manipuler des éléments de formulaire

Un formulaire ne sert à rien s'il n'est pas composé d'éléments. Les éléments (objets de la classe Zend_Form_Element )possèdent au moins autant d'options que l'objet Zend_Form lui-même.Ainsi, les éléments sont configurables de manière totalement indépendante du formulaire auquel ils seront rattachés

plus tard. Là encore, plusieurs manières de procéder :

1 Vous créez et configurez chaque élément à part, puis vous les rajoutez dans le formulaire2 Vous demandez au formulaire de créer des éléments et de les configurer, puis vous les ajoutez au formulaire3 Vous créez et ajoutez dans le formulaire tous les éléments d'un seul coup avec une seule méthode

Quoi que vous choisissiez, et quel que soit l'élément considéré, tout élément doit au minimum posséder un nomunique qui permettra de l'identifier dans le flot d'éléments que votre formulaire comportera.Ainsi, 2 éléments peuvent avoir le même nom, mais si vous ajoutez les 2 au formulaire, alors celui-ci ne considèreraque le dernier ajouté. Voyons celà :

ajout d'éléments au formulaire, méthode n°=1

<?php// $form est notre formulaire précedemment crée

$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'éléments au formulaire, méthode n°=2<?php

// $form est notre formulaire précedemment crée

$text  = $form ->createElement('text','un champ texte');$envoyer = $form ->createElement('submit','envoyer');

$form ->addElements(array($text,$envoyer));echo $form;

ajout d'éléments au formulaire, méthode n°=3<?php

// $form est notre formulaire précedemment crée

$form ->addElements(array(  array('text','un champ texte'),  array('submit','envoyer')));

echo $form;

Oui répétons : il existe toujours plusieurs (2, 3 voire 4) manières d'effectuer la même action avec #Zend_Form

Des éléments, comme on peut le deviner, il en existe plein, et la documentation officielle vous renseignera à leur sujet. Ils se configurent tous des la même manière (car ils étendent tous Zend_Form_Element ), et possèdent en pluschacun des options bien à eux (par exemple un élément de type 'select' possède une méthode permettant de luiajouter 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>

Page 57: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 57/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 57 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Je répète que la manière dont sont présentés visuellement les éléments et le formulaire (les balises HTML), dépendd'objets décorateurs que nous verrons plus tard.Nous pouvons tout de même remarquer que malgré leurs noms respectifs, certains éléments comme le "text" nel'affichent pas visuellement. C'est parce que tous les éléments possèdent un label.Le label est le nom qu'aura visuellement l'élément (généralement situé à coté de lui pour le décrire), ce qui n'a rienà voir avec son nom propre permettant de l'identifier dans l'objet Zend_Form ou dans la source HTML (grâce aux

attributs 'id' et 'name').Nos éléments doivent donc tous posséder un label, à quelques exceptions près comme l'élément bouton qui prendson nom comme label d'affichage.

Ajouter un label à un élément revient à lui ajouter une option, et des options, il en possède tous un tas. Voyons celà(liste non exhaustive) :setAttrib() permet d'ajouter un attribut HTML à l'élément, par exemple $text->setAttrib('class','element'), ou encore$text->setAttrib('disabled','disabled') ce qui rend la saisie impossible dans le champsetDescription() ajoute une description à l'élément. Celle-ci pourra être présentée visuellement lors de l'affichage sil'élément possède un décorateur permettant cela (c'est le cas par défaut pour certains d'entre eux)setErrorMessages() affecte les messages d'erreur de validation à l'élément, dans un cadre plus général, il demeureconseillé d'éviter les appels à cette méthode et d'utiliser un objet Zend_Translate pour l'affectation et la traduction

des différents messages d'erreur des validateurs d'un élément.setIgnore() prend en paramètre un booléen et informe alors que la valeur de cet élément sera ignorée lors de larécupération de l'ensemble des valeurs depuis le formulaire général, une fois celui-ci envoyésetOrder() prend en paramètre un entier indiquant l'ordre dans lequel l'élément apparaitra dans le visuel HTML.Pratique pour configurer en dernier des éléments devant être affichés en premierssetName() permet de modifier le nom de l'élémentsetLabel() permet d'affecter un label à l'élément, c'est à dire un message descriptif visuel généralement apposécontre l'élément dans la source HTMLsetRequired() permet d'obliger cet élément à être non vide à la saisie (sinon le formulaire sera en erreur lorsqu'ondemandera de le valider)setValue() permet d'affecter la valeur par défaut qu'aura l'élément lors de son affichage HTML ( en général il s'agitdu tag "value=", cela peut aussi être un tag "selected")Toutes ces méthodes ont des "get" associés (getAttrib(), getDescription() ...)

En plus de cela, certains éléments comme le select acceptent des méthodes spécifiques :

<?php

$select = new Zend_Form_Element_Select('selection de données');

$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 différentes manières de procéder dansl'exemple suivant :

ajout d'éléments divers, de diverses manières<?php

// $form est déja configuré et vide de tout élément

$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 données', array('label'=>'séléctionnez une donnée :',

 'multioptions'=>array('option 1'=>'valeur 1','option 2'=>'valeur 2'),

  'value'=>'option 2')),

Page 58: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 58/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 58 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

ajout d'éléments divers, de diverses manièresarray('submit','envoyer'),));

echo $form

Les "tableaux dans les tableaux de tableaux plein de tableaux" peuvent devenir déroutants, mais sont extrêmement

logiques. Soit je passe par un tableau, soit je sors l'élément et j'utilise sa méthode de configuration appropriée.On s'y habitue vite, et cette grande fléxibilité dans les manières d'arriver à un même résultat est un des points fortsde #Zend_FormLe 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 champtexte :</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="selectiondedonnées" class="optional">séléctionnez une donnée :</label></dt>

<dd id=""><select name="selectiondedonnées" id="selectiondedonnées">

  <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 avancées utiles.Vous pouvez récupérer un élément du formulaire en fléchant son nom comme propriété de l'objet Zend_Form, etdonc piloter l'élément hors du formulaire :

récupérer un élément depuis le formulaire<?php// soit le formulaire ci-dessus, construit et rempli de nos 3 éléments (text, select et submit) :

$elementText = $form ->unchamptexte;

echo $elementText // affiche juste l'élément text

On comprend pourquoi chaque élément doit avoir un nom propre unique. D'ailleurs, mettre des espaces dans sonnom n'aura aucun effet, ils seront en toute logique supprimés ("un champ texte"=>"unchamptexte").$form->removeElement() prend en paramètre le nom d'un élément et le supprime du formulaire.$form->getValue() prend en paramètre le nom d'un élément et récupère sa valeur, s'il en a une par défaut ou si leformulaire a été envoyé et que le champ a été rempli $form->getValues() existe aussi, il retourne, comme on peutse douter, un tableau avec les éléments et leurs valeurs associées.

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 estpossible de rendre Zend_Form "ajaxé", notamment grâce à Zend_Dojo_Form, mais ceci dépasse le cadre de cetarticle.La validation du formulaire se produit après l'envoi de celui-ci (ou aussi après affectation de valeurs à ses éléments).La page recevant les données recrée l'objet formulaire Zend_Form dans l'état, et demande si celui-ci est valide avecles données reçues. Ceci s'effectue de cette manière en général:

valider le formulaire<?php

// nous supposons le même formulaire que dans le sous-

chapitre précédent, simplement nous modifions sa destination// afin qu'il renvoie vers la même page que celle l'ayant crée, ceci simplifie les traitements.

$form ->setAction($_SERVER['SCRIPT_NAME']);

Page 59: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 59/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 59 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

valider le formulaire

if ($_SERVER['REQUEST_METHOD'] == "POST") { // venons-nous ici depuis une méthode POST ?

  if ($form ->isValid($_POST)) { // si le formulaire est valide avec les données POST reçues

  $form = "formulaire validé"; // on redéfinit la variable $form plus tard affichée

  } else {  $form ->populate($_POST); // sinon on remplit tous les champs avec les valeurs reçues

}echo $form;

isValid() prend en paramètre un tableau, généralement venu d'HTTP, et envoie chacune des données aux éléments,puis demande à chaque élément de valider cette donnée. populate() prend en paramètre un tableau, généralementvenu d'HTTP, et envoie chacune des données aux éléments en leur spécifiant de se l'affecter comme valeur par défaut.

Une fois que isValid() est appelée, si on demande à réafficher le formulaire, alors les éventuelles erreurs desvalidateurs des éléments vont être décorées, et donc affichées.Ce simple petit script et la combinaison des deux méthodes isValid() et populate() permet de valider et de réafficher entièrement le formulaire, quelle que soit sa compléxité et sa taille, en un seul geste. Génial !

Mais qu'est ce que la validation des données ?C'est très simple. isValid() demande à l'objet Zend_Form de fournir les valeurs à chacun de ses éléments, et dedemander à chaque élément de valider cette valeur après l'avoir filtrée.La validation se passe donc au niveau des éléments de formulaire. Il faut, pour chaque élément qui le nécessite,ajouter les validateurs de type Zend_Validate_Abstract .Concernant les validateurs, renseignez vous sur leur fonctionnement dans cet article ou dans la documentationofficielle. Pour l'ajout de validateurs, là encore, il existe plusieurs manières de faire, et aussi plusieurs options. Voiciun exemple de formulaire email/password les utilisant :

ajout de validateurs à des éléments<?php// $form est toujours le même, configuré mais vide de tout élément

$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);  }}

Page 60: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 60/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 60 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

ajout de validateurs à des élémentsecho $form;

Voyez plutot, les éléments possèdent une méthode addValidator() qui prend en paramètre soit un objetZend_Validate_Abstract , soit une chaine décrivant le nom du validateur, soit encore un tableau avec à la clé 'validator'une chaine décrivant le validateur, et à la clé 'options' un paramètre, souvent de type tableau, décrivant 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 intégrer les validateurs directement lors du addElement() ou addElements() sur le formulaire. Lasyntaxe se complique un peu, mais elle respecte la même règle interne, et avec un peu de présentation dans lecode, ça reste largement lisible.

Précisons tout de même (la documentation officielle aide) que l'élément de type Checkbox renvoie 0 si non coché,et 1 si coché, ceci par défaut. 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'affichentpar défaut en anglais (c'est personnalisable et très 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 jerépète encore : la présentation se fait grâce aux décorateurs que nous verrons bientot.

Les validateurs sont enchainés sur la valeur reçue par l'élément, dans l'ordre dans lequel ils ont été ajoutés. Aussi, les validateurs agissent sur la valeur filtrée de l'élément. Chaque élément accepteen plus des validateurs, des filtres de types Zend_Filter_Interface avec des méthodes trèssemblables à celles des validateurs. Nous n'ajouterons pas de filtres sur les données danscet article.

Les validateurs sont enchainés sur la valeur reçue par l'élément, dans l'ordre dans lequel ils ont été ajoutés. Ainsi,chaque validateur valide la donnée, qui est ensuite passée 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 élément qu'il est requis ("required") a pour effet d'ajouter un validateur de type "NotEmpty", en haut de lapile des validateurs déja présents éventuellement dans l'élément.

Il est possible de casser la chaine. Exemple : mon champ password contient 3 validateurs : required (not empty),puis Alnum (seuls les caractères alphanumériques sont accéptés), et enfin stringlength (la taille du champ doit faireau minimum 8 caractères).Si la chaine insérée est composée de caractères exotiques faisant échouer "Alnum", "Stringlength" sera quand mêmeappelé, même si au final, c'est inutile.Pour demander à casser la chaine de validation dès qu'un des validateurs d'un élément échoue, il faut le préciser 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(newZend_Validate_StringLength(7), true); // true en deuxième 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 obligés de passer par un tableau ici  'breakChainOnFailure'=>true),  array('validator'=>'stringlength',

Page 61: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 61/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 61 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

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 deuxième validateur à l'élément email, après son StringLength déja pr

// suite

"required" ajoute automatiquement un validateur "NotEmpty" et lui affecte l'optionbreakChainOnFailureSi vous ne voulez pas l'ajout automatique de cette option, utilisez setAutoInsertNotEmptyValidator(true) sur votre élément 

Comme vous pouvez vous-mêmes créer vos propres validateurs, et vos propres filtres, on sent bien que #Zend_Formrend de grands services.

Sachez aussi que chaque validateur ne fait pas que recevoir la donnée de l'élément auquel il est affecté en entrée.Il reçoit aussi optionnellement les données de tous les éléments. Un validateur d'égalité de 2 champs mot de passeest tout à fait réalisable (ou toute autre idée).

XIII-C - Décorateurs : gérer le rendu HTML

Passons maintenant au rendu HTML. Il faut bien comprendre que le formulaire est un objet contenant des objetséléments, qui eux mêmes contiennent des validateurs et/ou des filtres.Accessoirement un objet formulaire peut aussi contenir d'autres objets formulaires dans le cas de formulairesmultiples (plusieurs pages, ou décomposés).La présentation visuelle du formulaire et de ses éléments est déléguée entièrement à des objets décorateurs (si

toutefois vous décidez de présenter le formulaire, cela reste factulatif car un formulaire peut servir juste pour de lavalidation de données, même si ce cas est plutôt rare). On en déduit donc qu'à la fois Zend_Form, mais aussi tousles Zend_Form_Element , vont contenir des objets décorateurs.

Les décorateurs de l'objet Zend_Form vont gérer le rendu HTML du formulaire, hors éléments. Les éléments eux,possèdent chacun leurs décorateurs (généralement ils ont tous les mêmes, car on apprécie qu'un formulaire ait unlook "uni", mais ce n'est pas obligatoire).Le principe de la décoration est basé sur l'embelissement successifs d'objets. Chaque décorateur va rajouter ducontenu au contenu précédent.Voici, par défaut, les décorateurs que possèdent les Zend_Form_Element :

la décoration par défaut des éléments

$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 méthodes et les tableaux permettant la gestion des décorateurs, respectent la même logique que ceuxpermettant de créer et d'ajouter des éléments dans un formulaire.Pour bien comprendre la technique, lors de la demande du rendu visuel de l'élément, il se passera ceci :

$label->render(

  $htmlTag->render(  $description->render(  $errors->render(

Page 62: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 62/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 62 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

  $viewHelper->render('')))));

Les décorateurs reçoivent en paramètre l'élément sur lequel ils s'appliquent, et décorent (présentent visuellement)chacun un petit morceau de cet élément.Le décorateur ViewHelper utilise l'aide de vue Zend_View_Helper_* qui se charge de rendre l'élément de formulaireavec ses attributs éventuels ("input", "select" etc...).

Puis ensuite, le décorateur Errors demande à l'élément si il possède des messages d'erreurs (renseignés par seséventuels validateurs), si c'est le cas, alors il les encapsule dans des structures "ul li". Ensuite si l'élément possèdeune description, celle-ci est décorée par le décorateur du même nom, et ainsi de suite ...

Chaque décorateur se charge donc du rendu d'un "petit bout" de ce qui compose un élément (l'élément, ses erreurs,sa description ...), et ce rendu est effectué de différentes manières.Soit avant le rendu des décorateurs précédents, soit après, soit à la place de celui-ci, le remplaçant (c'est le cas pour le premier décorateur : ViewHelper effectue son rendu à la place de rien du tout. On peut aussi citer HtmlTag quieffectue son rendu à la place du rendu précédent, mais en l'encapsulant d'un tag HTML).

le rendu HTML par défaut d'un élément text<?php

array('ViewHelper'),array('Errors'), // APRES

array('Description', array('tag' => 'p', 'class' => 'description')), // APRESarray('HtmlTag', array('tag' => 'dd')), // REMPLACEarray('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 décorateur agit avant, après ou à la place du contenu décoré précédent. Cela demandecertes une petite gymnastique au début, mais on prend très vite l'habitude.

On peut en déduire que si on ajoute par exemple une description à un élément, mais que l'on affecte aucun décorateur permettant de gérer 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 posséder une description, mais qui par défaut n'enregistre aucundécorateur permettant de l'afficher.

Aussi, chaque décorateur fournit avec #Zend_Form est unique. L'un va remplacer du contenu, l'autre va chercher tel composant de l'élément (la description par exemple) et le faire suivre dans le flux HTML, d'autres encore sontfantômes comme 'Errors' qui surveille les messages d'erreurs, mais s'il n'y en a pas, ne font rien, donnant l'impressionqu'ils sont absents.Les décorateurs par défaut suffisent en théorie, car ils sont facilement manipulables par CSS, et une petite feuillede style bien menée permet une mise en page complète. Cependant, si on souhaite changer les décorteurs, il fautnoter quelques astuces :

1 Les décorateurs agissent dans l'ordre dans lequel ils sont enregistrés, et vous aurez compris j'espère que cetordre est extrêmement important.

2 Il n'est pas possible d'ajouter un décorateur dans la pile, à une place spécifique. L'ajout d'un décorateur lemet forcément à la suite des autres.

3 Un élément peut ne posséder aucun décorateur, il sera alors totalement invisible, mais comptera dans leprocessus de validation et sera bien présent dans la mémoire

4 Il est possible de créer ses propres décorateurs, une interface et une classe abstraite existent. Cela permetde faire réellement tout ce que l'on souhaite

Exerçons nous : nous souhaitons que nos éléments (nous verrons le formulaire lui-même plus tard) soient présentésdans des cellules d'un tableau HTML.

Même si chaque élément peut être décoré de manière individuelle, on a très souvent recours aux mêmes décorateurspour tous les éléments. Ainsi, nous pouvons les factoriser et les passer à chaque élément.

Page 63: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 63/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 63 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Suivez bien1 Rendre l'élément de formulaire (qu'on ne peut entouré tout de suite)2 Entouré le tout d'un tag "td"3 Rendre le label de l'élément entouré d'un tag 'td' (on peut l'entourer celui-ci)4 Entourer le tout d'un tag 'tr'

Afin d'arriver au résultat HTML suivant, pour tous les éléments :

<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 éléments

Là encore, tout en une seule fois nous oblige à utiliser plein de tableaux, mais structurés visuellement cela restecompréhensible.Il aurait exister plein de manières de faires différentes encore, en utilisant les objets Zend_Form_Decorator_* configurés un à un par exemple. Tout ceci ressemble fort à la gestion de l'ajout d'éléments dans le formulaire quenous avons déja vu ensemble dans les chapitres précédents.Une technique agréable consiste à demander au formulaire d'utiliser tels décorateurs pour tous les éléments y étantdéja enregistrés :

Demander au formulaire d'affecter des décorateurs à tous les éléments le composant

$form ->setElementDecorators($elementDecorators);

On peut aussi demander à la création d'un élément, de ne pas lui faire charger ses décorateurs par défaut, il est donc"nu" dès la création, il faut pour celà lui passer l'option 'disableLoadDefaultDecorators' à true.Concernant Zend_Form lui-même, il possède aussi des décorateurs permettant donc de rendre le formulaire enquestion. Voici les décorateurs par défaut :

$this->addDecorator('FormElements')  ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))  ->addDecorator('Form');

'FormElements' est spécial : il retourne le rendu des éléments décorés au auparavent.Nous souhaitons donc ce rendu, remplacé par le contenu d'un tag HTML entouré autour de lui, remplacé par lecontenu 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-même<?php

$formDecorators = array('FormElements',  'Form',

  array('decorator'=>array('1er'=>'HtmlTag'),'options'=>array('tag'=>'table')),);

$form ->setDecorators($formDecorators);

Page 64: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 64/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 64 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

XIII-D - Autres fonctionnalités

#Zend_Form regorge d'autres fonctionnalités. Par exemple pour traduire les messages d'erreurs reçus par lesvalidateurs des éléments, c'est aussi simple que d'enregitrer dans le registre Zend_Registry un objet de typeZend_Translate (configuré).

Aussi, Zend_Form supporte les sous-formulaires Zend_Form_SubForm. Il devient extrêmement simple de gérer desformulaires en plusieurs parties, chacun réutilisable n'importe où.Chaque élémént peut aussi faire partie d'un "groupe d'affichage" ("DisplayGroup"). Le groupe d'affichage possédantdes décorateurs, cela permet de regrouper visuellement des champs ensemble.Zend_Form_Element_File permet de gérer l'upload de fichiers de manière très simple.Zend_Form_Element_Captcha simplifie aussi fortement la manipulation des CAPTCHAs.L'intégralité d'un formulaire peut être configurée grâce à un seul (ou plusieurs) fichier INI, ou XML, grâce à l'utilisationastucieuse de Zend_Config Zend_Form offre aussi des options intéréssantes concernant les champs sous forme de tableaux (avec des [] ).Si vous souhaitez utiliser vos propres classes comme décorateurs ou éléments, Zend_Form possède en luiZend_Loader_Pluginloader pour gérer 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 idée, rendez-vous sur  l'atelier Zend Framework prévu à cet effet

Page 65: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 65/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 65 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

XIV - Zend_Application

Même si les liaisons avec le système MVC de #Zend_Application sont nettes, comme toujours ce composant peuttout à fait être utilisé hors modèle MVC de Zend Framework.A quoi sert-il ? Voici les objectifs de #Zend_Application :

1 Uniformiser la création des objets du framework et leur configuration2 Enregistrer  Zend_Loader_Autoloader automatiquement3 Configurer tous les paramètres PHP.INI simplement (ini_set)4 Gérer le changement d'environnement (prod/dev) facilement5 Faciliter la configuration de MVC6 Gérer les dépendances entre les objets

#Zend_Application sert surtout à créer 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 Zend_Application, qui sert à configurer l'environnement global2 Zend_Application_Bootstrap_* , qui sert à configurer les objets du framework que nous voulons utiliser 3 Zend_Application_Resource_* , qui sert à uniformiser la configuration des objets du framework que nous

voulons utiliser 

Voici un cas simple pour une première 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 définiesen leur sein.Nous avons placé le fichier ini sous APP_PATH/config/application.ini, pour l'exemple.

Voyez la simplicité : nous créons simplement un objet Zend_Application, en lui passant 2 paramètres : 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 même .php peut aussi fonctionner. Eninterne, Zend_Application utilisera le bon objet Zend_Config_* pour pouvoir lire ce fichier là : nous n'avons donc pas

besoin de créer un objet Zend_Config_* à la main.

Page 66: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 66/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 66 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Dès sa création, l'objet Zend_Application va utiliser  Zend_Config  pour lire le fichier de configuration et vaimmédiatement prendre les mesures suivantes :

1 Utiliser  set_include_path() avec tous les chemins déclarés dans les includepaths[]2 Enregistrer  Zend_Loader_Autoloader 3 Utiliser  Zend_Loader_Autoloader::registerNamespace() avec tous les préfixes déclarés dans les

autoloadernamespaces[]4 Utiliser  ini_set() avec tous les paramètres utilisés derrière phpsettings

Toutes les clés sont insensibles à la casse. Nous aurions pu écrire AuToLoaDerNameSpaces[] = "Foo" , en r evanche, n'oubliez pas les "s" des pluriels sur les clés, sinon ça ne fonctionnera pas.

Notez que nous avons déja une uniformisation : la simple création de l'objet Zend_Application exécute toutes cesactions pour nous.

XIV-A - Configurer ses objets (ressources)

Nous allons maintenant utiliser la partie "Bootstrap" de #Zend_Application. Celle-ci va nous permettre deconfigurer les objets nécessaires à une application : un Zend_Log , un Zend_Db, un Zend_Session ... Le tout demanière uniformisée, ce qui est fort appréciable. Pour cela, nous allons devoir déclarer une classe, qui étendZend_Application_Bootstrap_BootstrapAbstract et la préciser à Zend_Application grâce 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 méthode va configurer un objet Zend_Log

  } }

Cette classe doit déclarer une méthode run(). Celle-ci est sensée contenir le code qui servira à lancer votre application. Dans le cas où vous utilisez le modèle MVC de Zend Framework, basé sur lecomposant #Zend_Controller , il est possible d'étendre Zend_Application_Bootstrap_Bootstrap qui étend elle-mêmeZend_Application_Bootstrap_BootstrapAbstract , mais définit sa méthode run() afin qu'elle lance le contrôleur frontal.Ensuite, votre classe de bootstrap devra comporter autant de méthodes nommées _init****() que d'objets différentsà configurer.Dans la classe de bootstrap, vous avez accès aux paramètres de configuration (fichier ini dans notre cas) au moyendes méthodes getOption() ou getOptions().

suite de application.ini : configuration de nos objets

[dev:app]

db.params.charset = utf8

db.adapter = pdo_mysqldb.params.unix_socket = /var/run/mysqld/mysqld.sock

db.params.username = julien

Page 67: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 67/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 67 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

suite de application.ini : configuration de nos objetsdb.params.password = secret

db.params.dbname = dvp

view.doctype = XHTML1_STRICTview.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 paramètre une clé du tableau géré par Zend_Config , et la retourne. S'il s'agit d'unefeuille: c'est une donnée sous forme de chaine, s'il s'agit d'une branche: c'est un tableau. Ceci est le fonctionnementde Zend_Config (Rappel: Zend_Application et le bootstrap utilisent Zend_Config ).Dans chaque méthode _init***(), nous configurons donc un objet en tirant sa configuration via getOption(), puis nousle retournons (c'est important).

Voyez comme la configuration de chaque objet est bien rangée dans une méthode, alors que le fichier contenantZend_Application est lui toujours aussi simple. Faisons en sorte qu'il charge maintenant nos objets en passant dansles méthodes déclarées dans le bootstrap :

Le bootstrap sait maintenant récupérer 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(); // récupération de l'objet bootstrap

$boot->bootstrap('vue'); // déclenchement de la méthode _initVue()$view = $boot->getResource('vue'); // récupération de la vue fraichement configurée

Sur un objet de bootstrap, bootstrap('foo') permet de passer dans la méthode _initFoo() de sa classe. Notez bienque le nom de la méthode et de la ressource demandée sont liés.Zend Framework partira de 'foo', mettra la première lettre en majuscule 'Foo', puis rajoutera '_init' devant, avant delancer la méthode : à ce stade, il faut qu'elle existe.

Page 68: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 68/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 68 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

getResource('foo') est une méthode du bootstrap qui permet de récupérer l'objet (appelé 'resource') 'foo', configurédans la méthode _initFoo(), à condition que celle-ci le retourne bien (n'oubliez pas le return)Vous devez avoir lancé la méthode bootstrap('foo') avant l'appel à getResource('foo') sinon le retour de la méthodegetResource() vaudra null .

Dès lors, à chacun de s'organiser comme il le sent, vous avez la procédure à suivre pour configurer vos objets et

les récupérer. Notez qu'appeler la méthode bootstrap() sans aucun paramètre fera que le bootstrap chargera toutesles ressources (toutes les méthodes _init**()) dans l'ordre dans lequel elles apparaissent. Vous pourrez donc par lasuite les récupérer avec getResource() sans problème.

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

Les méthodes _initMonobjet() ont un inconvénient tout de même : il est difficile de les faire évoluer, et un bootstrapva vite se remplir avec beaucoup de méthodes de ce type là.Il existe une solution, intégrée dans le composant #Zend_Application, c'est une autre manière de configurer etcharger ses objets (ressources), plus fléxible.

Plutôt que d'utiliser des méthodes pour configurer nos ressources, il est possible d'utiliser des classes qui étendentZend_Application_Resource_Abstract , et il en existe déja pas mal pour les objets les plus utilisés de Zend Framework.Nous appellerons ces classes des "plugins".Afin d'indiquer au bootstrap qu'il doit utiliser un plugin pour charger une ressource, plutôt qu'une méthode _initMaRessource(), il convient de suivre ces règles :

1 Ne pas indiquer de méthode _initRessource() dans la classe de bootstrap2 Préfixer 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 supplémentaires sontnécessaires dans le cas contraire.Dès 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 = julienresources.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 méthode <i>initDb()

}

Zend_Application en action<?php

// rien ne change par rapport à avant ...

$boot = $app->getBootstrap();$boot->bootstrap('db');

$db = $boot->getResource('db');

Page 69: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 69/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 69 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Voyez plutôt. bootstrap() et getResource() sont utilisées avec une resource nommée "db", mais il n'existe pas deméthode _initDb() dans la classe du bootstrap.Dans le fichier .ini, la ressource s'appelle "db", et puisqu'elle est préfixé sur mot-clé "resource.", l'objet de bootstrapsait 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 paramètresutilisés sont ceux de l'objet (ressource) à configurer. Voici un exemple :

resources.db.params.charset = utf8resources.db.adapter = pdo_mysql

resources.db.params.unix_socket = / var/run/mysqld/mysqld.sockresources.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 = on

resources.session.name  = my_app

resources.session.save_path = tcp://127.0.0.1:11211

resources.session.save_handler =  memcache

Page 70: Zend Framework Presentation

5/9/2018 Zend Framework Presentation - slidepdf.com

http://slidepdf.com/reader/full/zend-framework-presentation-559ca10bd52b2 70/70

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 70 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même 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 Ede dommages et intérêts

XV - Conclusions

Voilà, cet article de présentation est terminé, mais il sera complété et mis à jour de temps à autre. mon blog pourravous éclairer, ou alors mon repertoire developpez, sans compter sur notre section Zend Framework.Notez que j'ai facilité l'accès aux codes d'exemple dans cet article. Je n'ai pas pris en compte les aspects sécurité,

 j'ai fait des sous-entendus, je n'ai presque pas utilisé les exceptions, etc . Dans des cas concrets, il y a bien entenduplus de travail à fournir que ce qui est écrit ici.Ici, c'est un avant-goût, assez complet tout de même, de Zend Framework, qui comporte beaucoup d'outils et sondéveloppement est en perpétuelle évolution.J'espère vous avoir un peu éclairé sur ce Framework qui représente un atout considérable à maitriser, dans toutdéveloppement web PHP, en particulier dans un monde professionnel, ou le travail en équipe règne. Zend a signélà un outil vraiment très robuste, dans la lignée de PHP lui-même.