|

|
php.MVC
– Guide de l'utilisateur
20/05/2005
20:50 -
Page 31/32
|
|
Description
|
|
Domaine
|
PHP
|
|
Sujet
|
Guide utilisateur du framework php.MVC
|
|
Version
|
1.00
|
|
Objet
|
Traduction française de la documentation
utilisateur disponible sur le site internet officiel du framework
php.MVC
|
|
Source
|
http://www.phpmvc.net/
|
|
Table des
matières
|
I)Introduction à
php.MVC 1
II)Les avantages 2
III)Le concept du pattern
MVC 3
IV)L'organisation et les
fichiers du répertoire du serveur web 4
A)Les
librairies php.MVC 5
B)Les
applications web php.MVC 6
V)La carte des objets de
l'application 7
VI)Les principaux
composants 8
VII)Le fichier xml de
configuration système de l'application 9
VIII)Le Contrôleur 11
IX)ActionForm 15
A)Utilisation
de classes "ActionForm" 16
B)La
classe "AbstractBaseForm" 16
C)La
classe "SalesReportForm" 18
X)Action 22
A)La
classe AbstractBaseAction 22
B)La
classe SalesReportAction 23
XI)La vue 27
XII)L'ActionDispatcher 30
|
I)Introduction
à php.MVC
php.MVC
est un framework "Modèle Vue Contrôleur" (MVC)
pour les applications web PHP. php.MVC implémente le design
pattern MVC2. Ce modèle permet aux pages web ou autres
contenus (vue), d’être séparés de la
logique métier de l’application (modèle).
L’utilisation de cette philosophie de conception permet aux
designers et aux programmeurs de se concentrer sur leur domaine
d’expertise.
Le
framework fournit un seul point d’entrée de contrôle
de l'application (contrôleur). Le contrôleur est
responsable de l’allocation des requêtes http à
l’action (Action) appropriée à partir de la
définition du fichier de configuration XML de l'application.
Le Modèle contient la logique métier de l'application.
Quand
le traitement d'une requête est terminé, le Contrôleur
appelle la ressource appropriée (composant vue), qui est
habituellement implémentée par un fichier template. La
réponse http résultante est alors retournée au
navigateur client, ou renvoyée via un autre protocole comme
SMTP par exemple.
php.MVC
est un portage PHP du projet Jakarta Struts. php.MVC supporte
actuellement plusieurs traits de Jakarta Struts, incluant la
déclaration de configuration XML de l'application, via un
outil de mapping XML/Objet (le Digester). Par exemple, le mapping des
différents composants logiques action/métier aux
ressources des pages appropriées, peuvent être spécifiés
dans le fichier de configuration de l'application.
La
figure 1 montre une vue d'ensemble de haut niveau du framework :

Figure
1 : vue d'ensemble conceptuelle de php.MVC
Comme
on peut le voir sur la figure 1, le framework consiste en 3
composants principaux : Le "Front Controller", le "Main
Controller" et le "Dispatcher" de la requête.
Nous allons regarder chacun des ces composants plus en détails.
Partout
dans ce guide nous ferons référence à un exemple
d'application et à ses fichiers sources.
II)Les
avantages
Le
pattern "Modèle Vue Contrôleur" pour la
conception d'application web est aujourd'hui un standard dans le
monde Java. Il y a plusieurs très bons livres et ressources
disponibles sur ce sujet, ce qui aide à accélérer
l'apprentissage d'une équipe de développement.
Des efforts conséquents
sont requis à l'apprentissage d'utilisation d'un framework
comme php.MVC. Cependant pour les développeurs professionnels
d'applications web, cet effort est largement récompensé
par les bénéfices d'utilisation d'un design pattern
reconnu tel que MVC :
Renforcement de la
modularité et du découpage de l'application
Augmentation de la
séparation des rôles développeurs/designers
Augmentation de la
maniabilité du code
Augmentation de
l'extensibilité du code (habilité à s'adapter
au changement)
Pourquoi ne pas construire
son propre framework :
Ce n'est pas une
entreprise banale
Cela vaut-il le temps
et la dépense engendrés par une telle entreprise
La licence open
source de php.MVC vous donne un accès complet au code source
Les connaissances
acquises sous php.MVC sont transférables sur Jakarta Struts
Des compétences
dans des framework non standards ne seront pas aussi
commercialisables
Les développeurs
expérimentés en Struts deviendront rapidement
productifs en utilisant php.MVC
php.MVC est basé
sur le standard industriel Jakarta Struts. Pourquoi réinventer
la roue ?
III)Le concept du pattern MVC
Le
framework php.MVC consiste en un agencement complexe de plusieurs
classes. Heureusement nous n'avons pas à connaître en
détail la façon dont fonctionnent toutes ces classes
afin d'utiliser le framework. Le schéma ci-dessous montre les
principaux éléments que vous devez connaître afin
de commencer à utiliser le framework.

Figure
2 : le flux requête/réponse MVC
A la
figure 2 on peut voir comment une requête http classique d'un
client web (navigateur web) peut interagir avec les principales
classes du framework et nos classes d'application, afin de produire
une réponse http (contenu web) à retourner au client
web.
Pour
démarrer le processus, un client va envoyer une requête
à notre application php.MVC. Par exemple pour consulter le
rapport de vente d'une entreprise particulière :
http://www.myhost.com/mycompany/Main.php?do=salesReport.
Le
framework (par le biais du contrôleur) va maintenant traiter
cette requête en utilisant une information clé, appelée
le "request path". Dans ce cas particulier, le "path"
est donné en tant que "salesReport". Nous verrons
plus tard comment configurer le comportement de l'application et
attacher notre validation de formulaire, la manipulation du code
métier et les ressources réponses appropriées
(habituellement les pages "template"), en utilisant le
fichier XML de configuration de l'application.
Maintenant
nous voulons restreindre l'accès au rapport, à des
personnes autorisées uniquement. L'utilisateur va devoir
saisir des informations d'authentification basiques sur le formulaire
original questionnant le rapport, habituellement un pseudo et un mot
de passe.
Pour
valider ces accès utilisateurs à notre rapport
professionnel, nous utilisons une classe appelée "ActionForm".
Actuellement nous étendons la classe "ActionForm" du
framework avec notre propre classe de validation de formulaire,
appelée "SalesActionForm" :
class
SalesActionForm extends ActionForm { ... }
A
l'intérieur de notre classe "SalesActionForm", nous
pouvons contrôler la validité de notre utilisateur et
décider de l'action appropriée. Si l'utilisateur rate
notre test d'authentification, nous pouvant le rediriger vers le
formulaire d'origine pour qu'il puisse essayer à nouveau. Si
l'authentification utilisateur est correcte, le contrôleur
pourra alors appeler le code métier via une classe "Action".
Nous
aurons défini la classe "Action" pour manipuler
cette demande dans notre fichier de configuration XML. De nouveau
nous étendons la classe "Action" avec notre propre
classe appelée "SalesAction" :
class
SalesAction extends Action { ... }
Comme nous aurons défini
la classe "Action" pour manipuler cette requête
(path) dans notre fichier de configuration XML de l'application, le
contrôleur est maintenant configuré pour acheminer cette
requête à notre classe particulière d'application
"SalesAction". Dans notre classe "SalesAction"
nous pouvons accéder à nos classes métiers et
nos sources de données comme convenu (le modèle). Dans
notre scénario actuel nous pouvons extraire les informations
de vente par compagnie de notre base de données, et construire
le rapport demandé. Par exemple, nous pouvons créer des
objets à utiliser dans notre template de rapport de vente :
//Sales
report items - per zone (individual object instances) $item1 = new
Item('Northern Zone Sales' , $salesNorth); $item2 = new
Item('Southern Zone Sales' , $salesSouth);
En fin
de compilation de notre rapport de vente de la société,
nous chargeons le contrôleur d'utiliser une ressource
particulière (la vue) pour traiter la présentation de
notre rapport. Nous le faisons en retournant un objet pré
configuré appelé "Forward" :
return
$mapping->findForwardConfig('salesReportSuccess');
Cet
objet "Forward" contient le chemin vers notre rapport de
vente "salesReport.tpl", comme défini dans le
fichier de configuration XML.
Le
contrôleur passe maintenant la requête à
l'ActionDispatcher. L'ActionDispatcher est responsable de charger la
ressource indiquée, "salesReport.tpl" dans ce cas.
Les variables et objets de rapport du template peuvent maintenant
accéder aux données appropriées que nous avons
préparées précédemment dans notre classe
"SalesAction".
Le
fragment de code ci-dessous montre comment nous pouvons avoir accès
aux données du rapport en utilisant le système "phpTAL
templating" pour générer nos vues de présentation.
L'objet "$item1" peut être utilisé pour
récupérer la variable de classe "$item1->value"
:
... <!--
//Sales report items - per zone (individual object instances)
-->
<table class='salesTable'> <tr>
<td class='salesItemDesc' tal:content="item1/salesNorth">
Sales report->value will appear here </td> ...
Le
Contrôleur sauvegarde maintenant les résultats de
traitement de notre ressource (le template) et renvoi ce buffer à
l'utilisateur comme réponse HTTP (la page web de rapport).
Dans la plupart des cas nous étendrons la classe
"ActionDispatcher" fourni par le framework, avec notre
propre classe personnalisée pour traiter nos besoins
particuliers.
IV)L'organisation
et les fichiers du répertoire du serveur web
Dans
cette section nous regarderons l'anatomie d'une application web
simple de type php.MVC, et les emplacements spécifiques
d'application et de librairie.
La
figure 3 montre comment une application php.MVC et les principales
librairies php.MVC peuvent être déployées.

Figure
3 : la structure du répertoire du serveur web
A)Les librairies php.MVC
Nous
pouvons voir dans la figure 3 que les fichiers de librairie php.MVC
ont été installés dans un répertoire
appelé "Dev", qui renferme d'autres bibliothèques
communes qui peuvent être utilisées sur ce serveur web
par des applications php.MVC ou par d'autres programmes. Ce
répertoire "Dev" est placé en dehors du
répertoire racine du serveur web. Du fait de ne pas être
placé à la racine web, les bibliothèques sont
protégées des accès web directs des
utilisateurs.
Si
nous devons installer les librairies php.MVC au niveau de la racine
web, nous pouvons utiliser un fichier ".htaccess" pour
contrôler les accès à ce répertoire. Voici
un exemple de fichier Apache ".htaccess" :
#Options
the .htaccess files in directories can override. #Edit
apache/conf/httpd.conf to AllowOverride in .htaccess #AllowOverride
AuthConfig
#Stop the directory list from being shown Options
–Indexes
#Controls who can get stuff from this
server. Order Deny,Allow Deny from all Allow from localhost
Ceci informe le serveur
web apache de :
Interdire tout accès
au répertoire contenant ce fichier .htaccess et à tous
ses sous répertoires. Dans cet exemple cela représente
le répertoire "/WEB-INF" des librairies php.MVC et
tous les autres fichiers et sous répertoires qu'il contient.
Permettre l'accès
au "localhost" : cela se réfère à la
machine hôte du serveur web. Ce qui permet à un
développeur de pouvoir accéder aux répertoires
de test dans la librairie sur ce serveur web et de lancer les tests
unitaires si nécessaire.
Les
fichiers de librairie php.MVC ne devraient exiger aucune nouvelle
modification pour une utilisation normale. Pour accéder aux
classes de librairie par notre application, nous définissons
la variable "$appServerRootDir" dans le fichier
d'application "Main.php" :
$appServerRootDir
= 'D:/Dev/PHP/phpmvc-base'; //no trailing slash
B)Les applications web php.MVC
A la
figure 3 nous voyons que le développeur a créé
un répertoire, au niveau de la racine web, appelé
"SalesReports" qui contiendra l'application.
Dans
le niveau supérieur du répertoire d'application
"SalesReports", nous avons plusieurs sous répertoires
et le fichier "Main.php". Le répertoire "art"
est utilisé pour contenir les images de l'application et sera
accessible au web. Le répertoire "style" est utilisé
pour contenir les feuilles de style de l'application et sera aussi
accessible au web. Ces répertoires peuvent être renommés
pour convenir aux préférences des développeurs.
Nous pouvons avoir accès à ces ressources à
partir de nos templates :
<link
rel='stylesheet' type='text/css' href="./style/mystyles.css">
Le
répertoire "/WEB-INF" : c'est l'endroit où
nous plaçons les classes et les ressources de l'application.
Le répertoire "/WEB-INF" ne doit pas être
accessible au web et est donc protégé par un fichier
".htaccess". Dans cet exemple nous avons un répertoire
"classes" et un répertoire "tpl". Le
développeur est libre de créer des répertoires
et des sous répertoires si nécessaires dans le
répertoire "/WEB-INF" et de les nommer selon ses
besoins. La seule exigence est que l'on doit déclarer les
chemins de ces répertoires dans le fichier "ModulePaths.php",
comme nous le verrons bientôt. Dans l'exemple au-dessus, le
répertoire de classes contient les classes d'application et
d'autres ressources comme des fichiers de propriété. La
répertoire "tpl" contient les ressources
d'application de type "Vue", comme les fichiers "template".
Dans
le répertoire "/WEB-INF" on va aussi trouver les
fichiers ".htaccess", "ModulePaths.php",
"phpmvc-config.xml", "phpmvc-config_1_1.dtd",
"phpmvc-config.data" et "prepend.php". Le fichier
".htaccess" a été présenté
précédemment.
Le
fichier "ModulePaths.php" est utilisé pour définir
les chemins spécifiques d'application à nos classes et
ressources. Nous pouvons définir les chemins d'application
comme ceci :
$appDirs
= array(); $appDirs[] = ''; // starting with the sub-application
home directory $appDirs[] = 'WEB-INF'; $appDirs[] =
'WEB-INF/classes'; $appDirs[] = 'WEB-INF/tpl';
Le
fichier "phpmvc-config.xml" est le composant central d'une
application php.MVC. C'est là que nous configurons notre
application en utilisant des noeuds XML pour définir des
comportements et des propriétés. Nous regarderons le
fichier "phpmvc-config.xml" plus en détail
ci-dessous.
Le
fichier "phpmvc-config_1_1.dtd" contient les "Définitions
de Type de Document" (DTD) pour le fichier "phpmvc-config.xml".
Le DTD spécifie ce qui peut et ne peut pas être inclus
dans le fichier "phpmvc-config.xml" et est la référence
unique au comportement de l'application. Les meilleurs éditeurs
XML utilisent le fichier DTD pour valider le fichier
"phpmvc-config.xml".
Le
fichier "phpmvc-config.data" contient les données de
configuration sérialisées pour l'application. Ces
données de configuration sont régénérées
chaque fois que le fichier "phpmvc-config.xml" est modifié.
Astuce : si votre application ne répond pas correctement,
retouchez (avec un espace d'édition) le fichier
"phpmvc-config.xml" et relancer l'application pour forcer
la régénération des données de
configuration sérialisées.
Le
fichier "prepend.php" est utilisé pour inclure des
fichiers d'application. Nous n'aurons pas à inclure les
classes d'application et les fichiers de template que le framework
trouvera, pourvu que nous ayons spécifié les chemins
correctement, comme décrit ci-dessus. Cependant nous pouvons
devoir inclure d'autres fichiers de classe et des ressources, comme
indiqué ci-dessous :
include_once
'Locale.php'; include_once 'PropertyMessageResources.php';
Le
fichier "Main.php" est le seul point d'entrée pour
une application et est placé dans le répertoire racine
de l'application. Toutes les requêtes sur une application
php.MVC particulière sont traitées par le fichier
"Main.php" de l'application. Le fichier "Main.php"
est aussi utilisé pour définir des paramètres
qui aident à configurer l'application à l'arrivée
d'une requête.
Comme
nous pouvons le voir ci-dessous, le chemin de la librairie php.MVC
doit être défini dans la variable "$appServerRootDir"
:
$appServerRootDir
= 'D:/Dev/PHP/phpmvc-base'; // no trailing slash
Ensuite le chemin de
l'application est défini dans la variable "$moduleRootDir"
:
$moduleRootDir
= 'C:/WWW/SalesReports'; // no trailing slash
Où "SalesReports"
est le répertoire racine de l'application.
Nous
définissons aussi le chemin de notre "ActionDispatcher"
d'application. Chaque application php.MVC utilisera habituellement un
"ActionDispatcher" personnalisé qui sera adapté
aux exigences spécifiques de l'application. Nous définissons
la variable "ActionDispatcher" comme ceci :
$actionDispatcher
= 'ReportActionDispatcher';
L'ActionDispatcher est
détaillé plus en détail plus tard dans ce guide.
La
variable "$osType" est un paramètre facultatif qui
peut être défini si le framework php.MVC a un problème
en détectant le système d'exploitation (OS) de l'hôte.
Normalement le framework devrait détecter automatiquement le
système d'exploitation de l'hôte et configurer les
chemins d'application en conséquence. S'il apparaît que
les chemins d'application ne soient pas corrects, nous pouvons
manuellement définir le paramètre "OS" comme
ceci :
$osType
= 'UNIX';
Pour les
systèmes d'exploitation de type Unix et Linux. Et comme ceci :
$osType
= 'WINDOWS';
Pour les
systèmes d'exploitation de type Windows.
Les
paramètres restants dans le fichier "Main.php" ne
devraient pas normalement exiger de modification.
Note :
l'utilisation du fichier "Main.php" pour définir les
paramètres d'initialisation de l'application changera à
l'avenir, avec la mise en oeuvre d'une sorte de "FrontController"
"web.xml" de chargement et de configuration du système.
V)La
carte des objets de l'application
La figure 4 montre le
rapport entre les classes principales et les ressources dans un
exemple d'application php.MVC, selon la perspective de développeurs
d'application.

Figure
4 : la carte des objets de SalesReport
On
peut voir l'ensemble des classes "ActionForm" à
gauche dans la figure 4. Nous pouvons utiliser des classes dérivées
"ActionForm" pour manipuler nos validations de formulaires
HTML et d'autres tâches de formulaire associées.
L'exemple ci-dessus utilise une classe "AbstractBaseForm"
qui contient une logique commune qui peut être utilisée
par plusieurs classes dérivées "ActionForm"
de notre application. La classe "SalesReportForm" est une
implémentation concrète de la classe
"AbstractBaseForm". Les classes "ActionForm" sont
couvertes plus en détail ultérieurement.
Les
classes "Action", comme vu dans la figure 4, manipule
habituellement le traitement d'une requête après une
validation initiale dans la classe "ActionForm" liée.
De nouveau nous voyons l'utilisation d'une classe de base
("AbstractBaseAction") qui peut contenir une logique
commune utilisée par plusieurs classes "Action"
dérivées. La classe "SalesReportAction" étend
la classe "AbstractBaseForm" pour fournir une
implémentation concrète de la logique utilisée
pour manipuler cette requête. De la classe "SalesReportAction"
nous pouvons appeler nos classes métiers (par exemple :
"ReportsBusinessClass") et accéder à d'autres
ressources et bases de données. Les classes "Action"
sont traitées ultérieurement.
La
classe "ActionDispatcher" est responsable de traiter une
ressource de vue prédéfinie (d'habitude un template de
page) pour cette requête "Action" et peut être
vue dans la partie basse de la figure 4. Nous étendons
habituellement la classe "ActionDispatcher" fournie par le
framework avec notre propre classe dispatcher personnalisée,
"ReportActionDispatcher" dans l'exemple ci-dessus. Nous
regarderons le Dispatcher d'Action ultérieurement.
VI)Les
principaux composants
Dans les sections suivantes nous examinerons les
composants fondamentaux de la librairie php.MVC.
le fichier de
configuration XML est "le tableau de contrôle" d'une
application php.MVC. Il définit comment nous lions les divers
composants à un chemin de requête http.
le contrôleur
consiste aux classes du framework php.MVC qui sont responsables de
router les requêtes HTTP aux classes "Action" et
"ActionForm" et aux ressources "Vue"
correspondantes, comme défini dans le fichier
phpmvc-config.xml de l'application.
Les classes
"ActionForm" sont utilisées pour manipuler les
vérifications et les manipulations de formulaires web.
Les classes "Action"
sont utilisées pour accéder à nos classes
métier. Nous pouvons diriger le flux d'application aux
ressources basées sur des conditions d'exécution.
La classe
"ActionDispatcher" manipule le traitement des ressources
(template).
VII)Le
fichier xml de configuration système de l'application
Le
fichier "phpmvc-config.xml" est le composant principal de
configuration d'une application php.MVC. Chaque application web
php.MVC a son propre fichier "phpmvc-config.xml",
habituellement placé dans les répertoires "WEB-INF"
des applications. Chaque fois que ce fichier est modifié le
contrôleur appelle le Digester XML, qui fait à son tour
l'analyse syntaxique (parsing) du fichier "phpmvc-config.xml"
et convertit les noeuds XML en une hiérarchie d'objets de
configuration. Ces objets de configuration sont alors stockés
dans le fichier "phpmvc-config.data", placé
habituellement dans le même répertoire que le fichier
"phpmvc-config.xml". Pour les requêtes suivantes le
contrôleur charge le fichier de cache "phpmvc-config.data",
en économisant ainsi du temps de traitement.
La
figure 5 montre un fichier "phpmvc-config.xml" typique vu
en tant qu'arborescence de noeuds et d'attributs XML.

Figure
5 : Représentation d'un fichier de configuration XML
phpmvc-config.xml
Dans
la figure 5 nous pouvons voir comment les sections de la
configuration touchent aux composants d'application correspondants.
Nous avons défini un élément "Action"
avec un attribut de chemin unique appelé "salesReport".
C'est l'identificateur clef pour cette action et les composants liés.
L'utilisateur demande ce chemin d'action (habituellement via une
liaison) avec une URL du type :
http://www.myhost.com/mycompany/Main.php?do=salesReport
Dans le nœud
d'action "salesReport" nous avons un attribut appelé
"name", avec la valeur "salesReportForm". Cela
informe le contrôleur que nous voulons utiliser le "form-bean"
nommé "salesReportForm" pour manipuler les
validations requises pour ce noeud d'action. Nous pouvons voir le
noeud du form-bean "salesReportForm" défini dans le
noeud "form-beans" au-dessus du noeud "action-mappings".
Notez aussi l'attribut nommé "validate" avec une
valeur booléenne à vrai, qui informe le contrôleur
d'appeler la méthode "validate()" de notre
form-bean.
Dans
le noeud d'action ainsi que dans le noeud "form-bean"
associé, il y a un attribut appelé "type".
Nous utilisons ces attributs pour définir nos classes de
"form-bean" et d'action. Par exemple l'attribut "type"
du noeud d'action définit une classe "Action"
appelée "SalesReportAction" et l'attribut "type"
du noeud du "form-bean" définit une classe
"ActionForm" appelée "SalesReportForm".
Les
éléments suivants intéressant sont les noeuds
"forward" dans le noeud d'action. Nous utilisons ces noeuds
"forward" pour définir les URI des ressources
(normalement des templates) qui comprennent la présentation
(Le composant "Vue" du framework). L'attribut "name"
du noeud "forward" définit un identifiant par lequel
nous pouvons récupérer cet élément
"forward". L'attribut "path" définit la
ressource ou le template que nous associerons avec cette action. Par
exemple dans le premier noeud "forward" nous définissons
un attribut appelé "salesReportSuccess" avec un
chemin de ressource "salesReport.tpl" et dans le deuxième
noeud "forward" nous définissons un attribut appelé
"salesReportFailure" avec un chemin de ressource
"salesReportIndex.tpl". Nous pouvons utiliser ces noeuds
"forward" dans nos classes pour identifier des ressources,
pour gérer une situation particulière. Dans ce cas si
la génération de rapport est couronnée de
succès, nous pouvons utiliser l'objet "salesReportSuccess"
et sa ressource définie "salesReport.tpl" pour
traiter la requête. Si la génération du rapport
échoue pour quelque raison nous pouvons transmettre le
contrôle à l'objet "forward"
"salesReportFailure" et sa ressource définie
"salesReportIndex.tpl" traitera la présentation,
peut-être en redirigeant l'utilisateur à la page
originale.
Le
fichier de configuration "phpmvc-config.xml" peut être
modifié à l'aide d'un éditeur de texte
classique, ou en utilisant un éditeur de ressource XML
spécialisé. Les éditeurs XML sont d'habitude
capables de valider le fichier de configuration à partir du
fichier XML DTD "phpmvc-config_1_1.dtd" associé. Le
fichier DTD définit les éléments XML, leurs
attributs associés et les valeurs qui sont valables pour le
fichier "phpmvc-config.xml". Le fichier DTD est l'arbitre
suprême de la façon dont les éléments, les
attributs et les valeurs peuvent être utilisés dans le
fichier "phpmvc-config.xml".
Un
exemple de fichier "phpmvc-config.xml" est présenté
ci-dessous:
<?xml
version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE
phpmvc-config PUBLIC "-//PHPMVC//DTD PHPMVC Configuration
1.0//EN" "./phpmvc-config_1_1.dtd">
<phpmvc-config>
<form-beans> <form-bean name="salesReportForm"
type="SalesReportForm"/> </form-beans>
<action-mappings> <action path = "salesReport"
type = "SalesReportAction" name =
"salesReportForm" scope = "request"
validate = "true"> <forward
name="salesReportSuccess" path="salesReport.tpl"/>
<forward name="salesReportFailure"
path="salesReportIndex.tpl"/> </action>
</action-mappings>
</phpmvc-config>
Configurations
et liaisons XML : phpmvc-config.xml
VIII)Le
Contrôleur
Le composant contrôleur
du framework php.MVC consiste en classes qui manipulent des requêtes
utilisateurs selon des options de configuration prédéfinies.
Une requête utilisateur typique ressemble à quelque
chose comme :
http://www.myhost.com/mycompany/Main.php?do=salesReport.
Le contrôleur
php.MVC consiste en deux sections distinctes : le "Front
Controller" et le Contrôleur approprié. Le "Front
Controller" est responsable de configurer l'application quand
une requête arrive et le contrôleur traite la requête
selon les propriétés de configuration définies
dans le fichier "phpmvc-config.xml".
La
figure ci-dessous montre les tâches principales exécutées
par le "Front Controller" du php.MVC quand l'application
reçoit une requête web.

Figure
6 : Le Front Controller
La requête utilisateur est reçue par le
fichier d'application "Main.php" dans lequel nous
configurons des options simple d'initialisation. Le "Front
Controller" exécute les tâches suivantes :
$appServerRootDir
= 'C:/WWW/phpmvc-base'; $moduleRootDir = 'C:/WWW/mycompany';
$actionDispatcher
= 'MyActionDispatcher';
Initialiser les
chemins de classe de l'application : le "Front Controller"
charge les chemins globaux prédéfinis et nos chemins
d'application, pour que le chargeur de classe puisse trouver nos
classes et ressources. Nous pouvons définir des chemins de
répertoires complémentaires d'application dans le
fichier "/WEB-INF/ModulePaths.php" :
$appDirs
= array(); ... $appDirs = 'WEB-INF/report_tpl'; $appDirs =
'WEB-INF/report_classes';
include_once
'./WEB-INF/mytools/MyTools.php';
Configurer
l'application : le "Front Controller" définit
certaines informations de configuration pour l'application, comme
l'"ActionDispacher" que nous avons vu précédemment.
Initialiser le
contrôleur : le "Front Controller" crée
maintenant une instance du serveur d'application (ActionServer).
Configurer
l'application : le "Front Controller" charge maintenant
l'information de configuration de l'application. Si le fichier
"phpmvc-config.xml" pour cette application a été
modifié depuis la dernière requête, le fichier
"phpmvc-config.xml" est retraité et caché
dans le répertoire."/WEB-INF/" de l'application en
tant que "phpmvc-config.data".
Initialisez la
requête HTTP : le "Front Controller" configure
maintenant la requête HTTP et ajoute les attributs de la
requête.
Appeler le contrôleur
de l'application : le "Front Controller" a maintenant fini
de préparer le serveur d'application pour traiter la requête
et passe cette responsabilité au contrôleur.
Note :
la section précédente changera à l'avenir, avec
l'implémentation d'un système de chargement et de
configuration de type "web.xml".
Le
contrôleur reçoit la requête du "Front
Controller" et exécute une série d'opérations
sur la requête selon les propriétés de
configuration définies pour ce chemin
(Main.php?do=salesReport).
La
figure 7 dépeint le contrôleur php.MVC :

Figure
7 : Le contrôleur
Process Action Path:
le contrôleur identifie le composant "path" utilisé
pour sélectionner une configuration d'action. Par exemple, si
la requête ressemble à quelque chose comme
"http://www.myhost.com/mycompany/Main.php?do=salesReport",
le chemin ("path") est "salesReport".
Process Locale : on
sélectionne une localisation pour l'utilisateur actuel si
nécessaire (*).
Process Content : on
définit les en-têtes de type "content" si
nécessaire. Le type par défaut est "text/html"
Process NoCache: on
définit les en-têtes de cache si nécessaire. Par
défaut : "Pragma",
"No-cache" "Cache-Control",
"no-cache" "Expires", 1
Process Preprocess :
prétraitement à but général. On peut
réécrire cette méthode dans notre propre
sous-classe "ActionServer", pour exécuter des
prétraitements spécifiques à notre application.
Process Action
Mapping : le contrôleur identifie la configuration d'action
pour cette requête, basée sur le chemin de requête
("salesReport"). Cet objet de configuration d'action a été
généré à partir du noeud correspondant
dans notre fichier "phpmvc-config.xml", avec le chemin
"salesReport" (<action
path = "salesReport" ...).
Process Roles : on
vérifie des rôles éventuels d'identification
nécessaires à l'exécution de cette action (*).
Process Action Form :
le contrôleur récupère le "bean"
ActionForm associé à cette configuration. Par exemple
le bean formulaire que nous définissons avec l'attribut
d'action : <action
... name = "salesReportForm" .../>.
Process Populate :
"peupler" les propriétés de l'instance
"ActionForm" indiqué, avec les paramètres de
requête inclus avec cette requête (*).
Validate Action Form
: appel de la méthode "validate()" de
l'"ActionForm" spécifié. Pour appeler la
méthode "validate()" définir "<action
validate = "true" .../>"
dans le fichier "phpmvc-config.xml" de l'application. Si
"validate()" retourne "False" (la validation a
échoué), le contrôleur utilisera la ressource
(le template) indiquée dans l'attribut "input" de
la configuration d'action. Par exemple : <action
path = "salesReport" ... validate = "true"
input = reportsIndex.tpl> Si
"validate()" retourne "True" (la validation est
passée), le traitement normal continue à la classe
d'action.
Process Forward : le
contrôleur vérifie si une configuration d'uri "forward"
a été défini pour supplanter le traitement
normal. Habituellement retourne "True", donc on continue
le traitement normal.
Process Action Create
: le contrôleur crée ou acquiert l'instance d'action
pour traiter cette requête. Ceci est défini dans le
fichier "phpmvc-config.xml" en utilisant la propriété
"type" : <action
path = "salesReport" type = "SalesReportAction"
...
Process Action
Execute : le contrôleur appelle maintenant la méthode
"execute()" de notre classe "Action". Par
exemple : "SalesReportAction->execute(...)".
De la méthode "execute()" nous pouvons appeler
notre logique métier comme demandé.
Process Action Chain
: le contrôleur vérifie si nous avons une autre action
à traiter. Nous pouvons définir une série
d'actions à exécuter séquentiellement en
définissant une "ActionChain" dans le fichier xml
de configuration de l'application. Pour définir une
"ActionChain", il faut ajouter un élément
forward au noeud d'action avec un attribut "nextActionPath"
: <action
path = "salesReport" type = "SalesReportAction"
<forward name = "salesReportSuccess"
path = "salesReport.tpl" nextActionPath =
"salesReport2"/> ... L'attribut
de chemin est un attribut requis par l'élément
"forward", alors si nous n'avons aucune sortie pour cette
action particulière, il faut définir le chemin = "".
Voir le guide ActionChain pour plus d'information sur les séquences
d'actions.
Process Action
Forward : le contrôleur maintenant transmet ou redirige à
la destination indiquée, par le mécanisme indiqué.
Une requête "forward" est traitée dans le
processeur actuel. Le "RequestProcessor" passe simplement
le contrôle à l'"ActionDispatcher", qui
inclut l' URI indiquée (page/template). Voici le comportement
par défaut : <forward
name="forward_path path="forwardRequest"
redirect="false"/> Une
requête redirigée envoie en réalité au
client (le navigateur) un en-tête réponse redirigeant
le client vers une nouvelle URL. L'exécution du processus
actuel se termine immédiatement à l'envoi des en-têtes
de redirection de requête au client. <!--
This server --> <forward name="redirect_path
path="/MyApp/Main.php?do=newRequest"
redirect="true"/> Ou
peut être sur un serveur distant <!--
This server, or a remote server
--> <forward name="redirect_path path="http://www.myhost.com/MyApp/Main.php?do=newRequest" redirect="true"/> S'il
n'y a plus d'actions à traiter ("ActionChains"), le
processus du contrôleur se termine.
(*)
Toutes ces opérations ne sont pas mises en oeuvre à
présent.
IX)ActionForm
Les
"ActionForm" sont utilisés pour fournir le
traitement initial de formulaire pour des requêtes HTTP de
notre application. Pour profiter de cette fonctionnalité nous
étendons la classe fournie par le framework "ActionForm"
à l'intérieur de notre propre application et écrivons
ou importons des routines de validation de formulaire spécifiques
pour répondre à nos besoins. Dans cet exemple nous
utilisons une classe fille abstraite "ActionForm" appelée
"AbstractBaseForm". Cette classe abstraite peut contenir la
logique commune qui peut être utilisée dans plusieurs
classes de traitement de formulaire. La classe de formulaire
"SalesReportForm" étend "AbstractBaseForm"
pour fournir un exemple concret de traitement de formulaire dans
l'application. Cette conception a été discutée
dans le chapitre "La carte des objets de l'application"
ci-dessus.
Un
"ActionForm" est représenté dans la
configuration XML de l'application comme ceci :
<form-beans>
<form-bean name="salesReportForm"
type="SalesReportForm"/> </form-beans>
L'utilisation
d'un ActionForm pour un chemin de requête particulier est
facultative et peut être activée dans le système
de configuration XML de l'application en utilisant l'attribut
"validate" du noeud de configuration comme cela :
<action
path = "salesReport" ... name = "salesReportForm"
validate = "true" input =
"salesReportIndex.tpl" ...> </action>
Pour
désactiver la validation on utilise :
validate
= "false"
La valeur
de défaut pour l'attribut "validate" est "True"
ainsi il n'y a aucun besoin de déclarer cet attribut
spécifiquement, cependant en déclarant l'attribut
"validate" nous pouvons éviter tout incompréhension.
Si la validation du formulaire échoue, le contrôleur du
framework peut retourner une ressource (template) défini dans
le noeud d'action par l'attribut "input". Par exemple :
input
= "salesReportIndex.tpl"
Dans ce
cas si nous trouvons des erreurs saisies sur le formulaire HTML, nous
pouvons sauver et renvoyer les erreurs dans un objet "ActionErrors"
et le contrôleur enregistrera l'objet "ActionErrors"
avec la requête avant de transmettre le contrôle à
la ressource "salesReportIndex.tpl". Le diagramme
ci-dessous montre ce traitement :

Figure
8 : validation ActionForm
Nous avons
vu dans la section de configuration XML de l'application que
l'attribut "name" de l'élément de mapping
action lie un formulaire à une action. Par exemple le noeud
action et le noeud du form-bean partagent un attribut "name"
commun (name
= "salesReportForm") qui lie le
"form-bean" à l'Action spécifique.
A)Utilisation de classes "ActionForm"
Un examen
de la littérature de Jakarta Struts indique que nous devons
préalablement vérifier les champs de formulaire dans
nos classes "ActionForm", pour vérifier par exemple
des champs non renseignés. Une vérification de champ
plus rigoureuse étant alors faite dans les classes "Action".
Cependant nous sommes libres de concevoir notre schéma
d'authentification/autorisation de formulaire selon nos préférences
de développement.
Dans
l'exemple utilisé dans ce guide nous exécutons notre
authentification d'utilisateur dans la classe "ActionForm"
(dérivée) et faisons une vérification
d'autorisation (simulée) du rôle de l'utilisateur
complémentaire dans la classe "Action" (dérivée).
B)La classe "AbstractBaseForm"
Comme
noté ci-dessus nous utilisons une classe "AbstractBaseForm"
qui étend la classe "ActionForm" du framework, comme
nous l'avons vu décrit dans la section "La carte des
objets de l'application" ci-dessus. Nous pouvons utiliser cette
classe "AbstractBaseForm" pour regrouper quelques attributs
et méthodes qui peuvent être utilisées dans
plusieurs classes concrètes "ActionForm"
rapprochées. La section de code ci-dessous montre une version
abrégée de la classe "AbstractBaseForm"
utilisée dans l'exemple.
class
AbstractBaseForm extends ActionForm {
// ----- Instance
Variables --------------------------------------------- // var
$actionErrors = NULL; var $pmr = NULL; var
$locale = NULL;
// ----- Constructor
---------------------------------------------------- //
function AbstractBaseForm() {
$this->actionErrors =&
new ActionErrors(); $config = 'MyAppResources';
$returnNull = False; $defaultLocale =& new Locale();
$factory = NULL; $pmr =& new
PropertyMessageResources($factory, $config, $returnNull);
$pmr->setDefaultLocale($defaultLocale); $this->pmr =
$pmr; }
// ----- Public Methods
------------------------------------------------- //
function reset(&$mapping, &$request) { ; }
// Check if this is the first call to this form. function
isSubmit(&$request, &$actionErrors) {
if($request->getParameter('submit') == '') {
$this->setUserName('Username=john');
$this->setPassWord('Password=aaa');
$this->setUserRole('accounts');
$request->setAttribute( 'ACTION_FORM', $this );
$actionErrors->add( 'first_form_call', new ActionError('') );
return $actionErrors; } else { return
NULL; } }
// ----- Form Properties
------------------------------------------------ //
var
$username = ''; var $password = ''; var $userrole = '';
function setUserName($username) { $this->username =
$username; } function getUserName() { return
$this->username; } ... }
Le
constructeur : dans la section du constructeur de la classe
"AbstractBaseForm" nous pouvons voir qu'un objet
"ActionErrors" est créé et que sa référence
est sauvegardé par un attribut de classe "$actionErrors".
C'est l'objet d'erreurs que nous utiliserons pour récupérer
n'importe quelles erreurs de formulaire trouvées en traitant
le formulaire.
"Locale"
et "PropertyMessageResources" : sont aussi créés
des instances des classes "Locale" et
"PropertyMessageResources". A noter la variable $config
='MyAppResources' qui est utilisée
comme un argument à l'appel du constructeur
"PropertyMessageResources". La classe
"PropertyMessageResources" fournit un traitement de
messages textes utilisé pour formater les messages d'erreur.
Les messages textes pour cet exemple sont définis dans un
fichier de propriété d'application appelé
"MyAppResources.properties". La classe
"PropertyMessageResources" localise le fichier de
propriétés correct en utilisant la variable $config
='MyAppResources'. Par exemple le
paramètre $config
='MyAppResources' est utilisé par
la classe de message pour localiser un fichier de propriété
appelé "MyAppResources.properties".
La
classe "Locale" peut être utilisé pour
sélectionner des ressources de propriété
spécifiques selon une localisation d'utilisateur (langue, PAYS
et VARIANTE) [Rédacteur : le traitement de message et la
localisation exigent un guide consacré. Veuillez trouver les
jeux de test "MessageFormatTestCase" et
"PropertyMessageResourcesTestCase" dans le répertoires
"/WEB-INF/classes/phpmvc/test/" d'exemples d'utilisation].
Propriétés
de formulaire : la classe "AbstractBaseForm" contient aussi
quelques propriétés de formulaire et une méthode
"isSubmit (...)". Cet exemple utilise des variables de
formulaire créées manuellement et les méthodes
"setter" et "getter" correspondantes, juste pour
obtenir un code aussi simple que possible. Une approche plus
évolutive pour une application réaliste serait
d'utiliser une des bibliothèques de traitement de formulaire
PHP, comme phplib::OOHForms ou PEAR::HTML_QuickForm.
Dans
cet exemple nous utilisons les propriétés de formulaire
("$username", "$password", "$userrole")
pour conserver les variables de formulaire correspondantes
récupérées. Si nous trouvons des erreurs
d'entrée de formulaire, ces propriétés de
formulaire sont renvoyées au formulaire et affichées
dans les champs du formulaire de saisie, avec n'importe quels
messages d'erreur.
La
méthode "isSubmit(...)" : la méthode
"isSubmit(...)"est utilisée pour vérifier si
une requête particulière est la première. Par
exemple le bouton "submit" n'a pas été
cliqué, donc nous n'avons pas de paramètre "submit"
($request->getParameter
('submit') == ''). Dans ce cas nous
définissons quelques valeurs par défaut pour les champs
du formulaire ($this->setUserName('Username=john'),
etc). Nous sauvons alors la classe
"ActionForm" avec l'objet requête
($request->setAttribute('ACTION_FORM',
$this)) pour une récupération
ultérieure dans notre "ActionDispatcher".
Nous
ajoutons aussi un élément erreur factice
($actionErrors->add('first_form_call',
new ActionError(''))) pour forcer le
contrôleur à contourner le traitement de la classe
"Action" et envoyer le contrôle directement à
la ressource "input" (salesReportIndex.tpl), comme indiqué
dans le diagramme de validation d'"ActionForm" ci-dessus.
Finalement l'objet d'erreurs est retourné (via la classe
concrète "ActionForm").
C)La classe "SalesReportForm"
La
classe abrégée "SalesReportForm" montrée
ci-dessous est notre implémentation concrète de la
classe "ActionForm" du framework php.MVC. Comme on peut le
voir, la classe "SalesReportForm" étend le
comportement de notre "AbstractBaseForm", qui étend
à son tour la classe "ActionForm".
class
SalesReportForm extends AbstractBaseForm {
// -----
Constructor ---------------------------------------------------- //
function SalesReportForm() { // Setup the parent object
first parent::AbstractBaseForm(); }
// -----
Public Methods ------------------------------------------------- //
function reset(&$mapping, &$request) {
parent::reset($mapping, $request); }
function
validate(&$mapping, &$request) {
$actionErrors
=& $this->actionErrors; $pmr =& $this->pmr;
$locale =& $this->locale;
if($this->isSubmit($request, $actionErrors)) { return
$actionErrors; }
$username =
$request->getParameter('uname'); $password =
$request->getParameter('pword');
if($username !=
'john') { $args = array($username); $msg =
$pmr->getMessage($locale, 'logon.username.reqd', $args);
$actionErrors->add( 'logon_username_reqd', new ActionError($msg)
); }
if($password != 'aaa') {
$args = array($password, $username); $msg =
$pmr->getMessage($locale, 'logon.password.reqd', $args);
$actionErrors->add( 'logon_password_reqd', new ActionError($msg)
); }
if($actionErrors->isEmpty() == False)
{ $this->setUserName($username);
$this->setPassWord($password);
$this->setUserRole($request->getParameter('urole'));
}
$request->setAttribute( 'ACTION_FORM', $this );
return $actionErrors;
}
// ----- Form
Properties ------------------------------------------------ //
// See the base class }
Le
constructeur : comme on peut le voir dans la section de code
ci-dessus, la première chose qui arrive quand notre classe
"SalesReportForm" est créée, est que le
constructeur de la classe de base "AbstractBaseForm" est
appelée à l'intérieur de la méthode
constructeur de la classe SalesReportForm. Cela nous permet de
définir des comportements communs pour nos traitements de
formulaires, comme nous avons vu dans la section de la classe
"AbstractBaseForm" ci-dessus.
La
méthode "reset()" : nous pouvons utiliser la méthode
"reset()" pour éventuellement initialiser les
variables de formulaire dans certains cas. Nous n'utilisons pas la
méthode "reset()" dans cet exemple.
La
méthode "validate()" : comme noté ci-dessus,
la validation "ActionForm" est contrôlé par le
système de configuration XML de l'application en utilisant
l'attribut "validate" du nœud de l'action :
<action
path = "salesReport" ... name =
"salesReportForm" validate = "true"
input = "salesReportIndex.tpl" ...> </action>
Quand une
requête (par exemple :
http://www.myhost.com/mycompany/Main.php?do=salesReport)
arrive pour un chemin particulier (do=salesReport),
le contrôleur récupère l'objet mapping action
pour le chemin demandé. Dans ce cas, c'est l'objet mapping
action qui est généré par la configuration
d'action (<action
path = "salesReport" ... </action>).
De ce mapping action le contrôleur détermine si nous
demandons la validation de formulaire. Pour ce mapping action
particulier nous avons déclaré (validate
= "true") que nous demandons la
validation ActionForm
ActionErrors,
PropertyMessageResources et Locale : la première chose que
nous faisons dans la méthode "validate" est de
récupérer des références locales aux
ressources d'erreur et de message texte que nous avons configurées
précédemment, dans notre classe de base
"AbstractBaseForm" :
$actionErrors
=& $this->actionErrors; $pmr =& $this->pmr; $locale
=& $this->locale;
La méthode
"isSubmit()" : maintenant nous appelons la méthode
"isSubmit()" de la classe de base pour tester si c'est le
premier appel au formulaire :
if($this->isSubmit($request,
$actionErrors)) { return $actionErrors; }
Si c'est
le premier appel au formulaire, la variable de formulaire "submit"
(<input
type='submit' name='submit' Value='Submit'/>)
ne sera pas présente dans les paramètres de la requête.
Sur le premier appel nous définissons des valeurs par défaut
dans la classe de base et retournons l'objet d'erreurs que devrait
contenir la ressource input = "salesReportIndex.tpl" et
sautez tout traitement supplémentaire dans la méthode
"validate".
Validation
des champs de formulaire : maintenant nous exécutons quelques
essais simples sur l'exemple de formulaire de saisie. Comme noté
ci-dessus, dans une application plus complexe nous utiliserions
probablement une des bibliothèques consacrées au
traitement de formulaire HTML comme phpLIB::OOHForms ou
PEAR::HTML_QuickForm, qui automatiserait beaucoup de tâches de
validation de formulaire. Cependant pour des applications simples il
peut être préférable d'utiliser une approche
simple comme ici.
Les
variables intéressantes ici sont les paramètres de
formulaire "$username" et "$password". Ces champs
sont définis dans le formulaire de "salesReportIndex.tpl"
comme ceci :
<input
type='text' Name='uname' value='<?php print $form->username ?>'
/> ... <input type='text' Name='pword' value='<?php
print $form->password ?>' />
Ces
variables de formulaire ont été automatiquement
sauvegardées à l'objet requête et peuvent être
récupérées comme ceci :
$username
= $request->getParameter('uname'); $password =
$request->getParameter('pword');
Une
note sur la sécurité
Dans une
application en production nous devons toujours supposer que toutes
les données de formulaire sont douteuses. Toutes les saisies
doivent être vérifiées par rapport à
l'exactitude de gammes de caractères/numéros valables.
Par exemple nous pouvons vérifier la variable de formulaire
"username" en utilisant une expression régulière
comme "^[a-z0-9]{8}$" (cette expression spécifie que
le champ username doit seulement contenir un total de huit caractères
imprimables ou numériques). Les bibliothèques de
formulaire comme phpLIB::OOHForms ont les moyens d'exécuter
cette tâche plus facilement.
Nous
pouvons maintenant essayer de valider les variables de formulaire.
Dans une application réelle nous pourrions comparer le mot de
passe d'utilisateur aux informations récupérées
dans une base de données, pour cet utilisateur. Pour faire des
choses simples nous comparerons juste la variable "username"
à une chaîne de caractère, comme ceci :
if
($username != 'john') { $args = array($username); $msg =
$pmr->getMessage($locale, 'logon.username.reqd', $args);
$actionErrors->add( 'logon_username_reqd', new ActionError($msg)
); }
Si
"username" n'est pas égal (! =) à la chaîne
de caractère "John" alors on ajoute un élément
erreur à l'objet d'erreurs. D'abord nous créons un
message d'erreur appropriée à cette condition d'erreur.
En
utilisant la classe "PropertyMessageResources" nous pouvons
récupérer des messages "string" (chaîne
de caractères) d'un fichier de propriété
d'application et utiliser aussi la substitution de variable sur le
message. De cette façon nous pouvons utiliser différents
fichiers de propriété pour des langues, des pays et des
variantes diverses.
Pour
cet exemple nous utilisons un fichier de propriété
appelé "MyAppResources.properties" qui est placé
dans le répertoire d'exemple "/WEB-INF/classes". Les
messages "string" dans le fichier de propriété
sont authentifiés par un identifiant "string" devant
un signe égal. Un message "string" typique de
fichier de propriété ressemble à quelque chose
comme :
logon.username.reqd=Please
enter a valid username [{0}]
Où
{0} est un paramètre de remplacement. Nous pouvons avoir
jusqu'à quatre paramètres de remplacement dans un
message "string" ({0} à {3})
Maintenant
nous pouvons créer le message d'erreur. Dans ce cas nous
utilisons la variable "username" comme notre (premier)
paramètre de remplacement, donc nous créons un tableau
contenant notre paramètre de remplacement, comme cela : $args
= array($username). Ensuite nous appelons
la méthode "getMessage()" de la classe
"PropertyMessageResources" comme cela : $msg
= $pmr->getMessage($locale, 'logon.username.reqd', $args).
La variable "$msg" doit maintenant contenir le message,
quelque chose comme "Entrez s'il vous plaît un nom
d'utilisateur valide [jblogs]".
Et
enfin nous pouvons ajouter ce message à notre objet d'erreurs
comme ceci : $actionErrors->add('logon_username_reqd',
new ActionError($msg)), où
"logon_username_reqd" est la clef du message.
Pour
des détails sur la façon dont la classe
"PropertyMessageResources" choisi le fichier de propriétés
correct, revenir sur la section de la classe "AbstractBaseFrom"
au dessus.
On
manipule le variable de formulaire du mot de passe de la même
façon que la variable "username" ci-dessus, sauf que
nous démontrons l'utilisation de deux paramètres de
remplacement de message.
$args
= array($password, $username)
Et
utilisation de la chaîne 'logon_password_reqd' comme clef de
message.
Persistance
des champs de formulaire : maintenant nous pouvons vérifier si
aucune erreur de formulaire n'a été détectée
en appelant la méthode "isEmpty()" de la classe
"$actionErrors" :
if
($actionErrors->isEmpty() == False) {
$this->setUserName($username);
$this->setPassWord($password);
$this->setUserRole($request->getParameter('urole')); }
Si
"$actionErrors" n'est pas vide nous sauvons les variables
"$username" et "$password" dans l'objet
ActionForm. Nous sauvons aussi la variable "urole" (ou rôle
d'utilisateur) dans le formulaire. Nous nous servirons du rôle
d'utilisateur dans la classe "Action".
Enfin
nous pouvons sauver l'objet ActionForm ("SalesReportForm")
dans l'objet requête pour une référence
ultérieure dans les templates de "Vue" :
$request->setAttribute('ACTION_FORM',
$this)
Et on
retourne n'importe quelles $actionErrors. Comme on peut le remarquer
au dessus, si le contrôleur détecte que n'importe
quelles "$actionErrors" est définie il ignorera la
classe "Action", en acheminant la requête à la
ressource (template) défini dans l'action mapping par
l'attribut input (= "salesReportIndex.tpl").
X)Action
Les
classes "Action" fournissent une occasion d'exécuter
des traitements complémentaires sur les données
saisies, l'accès à une base de données et
l'appel de classes métiers spécifiques à
l'application (le modèle).
Par
exemple nous pouvons vérifier les permissions utilisateurs
pour accéder à certains rapports d'entreprise, appeler
notre logique métier (peut-être une classe de génération
de rapport) et questionner ou mettre à jour notre base de
données à l'intérieur de nos classes "Action".
Pour
utiliser la classe "Action" on étend la classe
"Action", fournie par le framework, dans notre propre
application. Dans cet exemple nous utilisons une classe "Action"
abstraite enfant appelée "AbstractBaseAction", qui
étend "Action". Cette classe "Action"
abstraite peut contenir la logique commune pouvant être
utilisée dans plusieurs de nos classes "Action" de
l'application.
La
classe "Action" "SalesReportAction" étend
"AbstractBaseAction" pour fournir une classe "Action"
concrète dans notre application. On peut voir une vue
d'ensemble de cette conception dans la section "Carte des objets
de l'application" ci-dessus.
Une
classe Action est représentée dans la configuration XML
de l'application comme cela :
<action-mappings>
<action path = "salesReport" type =
"SalesReportAction" name = "salesReportForm"
validate = "true" input = "salesReportIndex.tpl"
scope = "request"> <forward
name="salesReportSuccess" path="salesReport.tpl"
/> <forward name="salesReportFailure"
path="salesReportIndex.tpl"/>
</action> </action-mappings>
Comme on
peut le remarquer dans la section de configuration XML de
l'application ci-dessus, l'attribut "path = salesReport" de
ce noeud agit en tant qu'identifiant clé pour ce mapping
d'action. Le contrôleur identifiera ce mapping d'action, d'une
requête telle que :
http://www.myhost.com/mycompany/Main.php?do=salesReport
A)La classe AbstractBaseAction
Une version abrégée
de la classe "AbstractBaseAction" est présentée
ci-dessous :
class
AbstractBaseAction extends Action {
// ----- Instance
Variables --------------------------------------------- // var
$log = NULL; var $actionErrors = NULL; var $pmr
= NULL; var $locale = NULL; var $dbConn
= NULL;
// ----- Constructor
---------------------------------------------------- //
function AbstractBaseAction() {
$this->log = new
PhpMVC_Log();
$this->actionErrors =& new
ActionErrors();
$config = 'MyAppResources';
$returnNull = False; $defaultLocale =& new Locale();
$factory = NULL; $pmr =& new
PropertyMessageResources($factory, $config, $returnNull);
$pmr->setDefaultLocale($defaultLocale); $this->pmr =
$pmr; }
// ----- Public Methods
------------------------------------------------- // function
execute($mapping, $form, &$request, &$response) { ;
// Implement this method in your concrete Action classes } }
Le
constructeur : la classe "AbstractBaseAction" a fourni des
services communs, tels que la manipulation des chaînes d'erreur
et de message, de même que la classe "AbstractBaseForm"
montrée ci-dessus. Aussi fournie, une classe de journalisation
qui peut être utile au dépistage d'erreurs. Les classes
"Locale" et "PropertyMessageResources" ont été
présentées dans la section "ActionForm"
ci-dessus.
La
méthode "execute()" : la méthode "execute()"
est appelée par le framework quand il reçoit une
requête pour cette action en particulier. Nous fournissons une
implémentation concrète de cette méthode dans
notre classe "SalesReportAction".
B)La classe SalesReportAction
Une
version abrégée du "SalesReportAction" est
montrée ci-dessous. C'est notre implémentation concrète
spécifique d'application de la classe "Action" (par
l'intermédiaire de la classe "AbstractBaseAction").
class
SalesReportAction extends AbstractBaseAction {
// -----
Constructor ---------------------------------------------------- //
function SalesReportAction() {
parent::AbstractBaseAction();
$this->log->setLog('isTraceEnabled' , True);
}
// ----- Public Methods
------------------------------------------------- //
function execute($mapping, $form, &$request, &$response)
{
$trace = $this->log->getLog('isTraceEnabled');
if($trace) { $this->log->trace('Start:
SalesReportAction->execute(...)'.
'['.__LINE__.']'); }
$actionErrors =&
$this->actionErrors; $pmr =& $this->pmr;
$locale =& $this->locale;
$username =
$request->getParameter('uname'); $password =
$request->getParameter('pword'); $group =
$request->getParameter('urole');
// SQL as required
$aclCheck = False; if($group == 'accounts') {
$aclCheck = True; }
$myForward = NULL;
if($aclCheck == True) {
$myForward = $mapping->findForwardConfig('salesReportSuccess');
$sales = NULL;
$salesReport =& new
ReportsBusinessClass(); $sales =
$salesReport->getSales($this->dbConn);
$request->setAttribute('FORM_DATA', $sales); } else {
$myForward =
$mapping->findForwardConfig('salesReportFailure');
$msg = $pmr->getMessage($locale, 'report.auth.failed');
$actionErrors->add( 'report_auth_failed', new ActionError($msg)
); $request->setAttribute(Action::getKey('ERROR_KEY'),
$actionErrors); $form->setUserName($username);
$form->setPassWord($password);
$form->setUserRole($group);
$request->setAttribute( 'ACTION_FORM', $form ); }
return $myForward;
} }
Le
constructeur : le constructeur est appelé automatiquement
quand notre classe est instanciée. Dans le constructeur on
appelle le constructeur de la classe parente
(parent::AbstractBaseAction())
pour définir nos services communs dans la classe de base. Nous
pouvons éventuellement activer la journalisation dans notre
classe : $this->log->setLog('isTraceEnabled',
True).
La
méthode "execute()" : comme indiqué ci-dessus
la méthode "execute()" est appelée quand le
framework reçoit une requête de ce chemin d'action
particulier.
Logging
: Dans la méthode "execute()" il peut être
utile d'utiliser la journalisation pour tracer les chemins
d'exécution à travers notre application. Nous pouvons
utiliser une trace de journalisation comme ceci :
$trace
= $this->log->getLog('isTraceEnabled'); if($trace) {
$this->log->trace('Start: SalesReportAction->execute(...)'.
'['.__LINE__.']'); }
Cela
produira une sortie de type :
Trace:
Start: SalesReportAction->execute(...)[85]
ActionErrors,
PropertyMessageResources et Locale : on retrouve de nouveau des
références aux objets erreurs, ressources de message et
localisation :
$actionErrors
=& $this->actionErrors; $pmr =& $this->pmr;
$locale =& $this->locale;
Référez-vous
à l'ActionForm pour l'utilisation.
Accession
aux champs de formulaire : nous pouvons maintenant récupérer
les champs de formulaire, pour exécuter par exemple une
nouvelle authentification utilisateur. Notez que nous devons avoir
vérifié les champs de formulaire pour un contenu
correct dans la classe ActionForm "SalesReportBaseForm".
Donc nous supposons maintenant que les champs sont valides.
$username
= $request->getParameter('uname'); $password =
$request->getParameter('pword'); $group =
$request->getParameter('urole');
Vérification
permission utilisateur : à cette étape nous pouvons
vérifier si cet utilisateur a la permission d'accéder
aux ressources fournies par notre classe Action. Nous pouvons
interroger notre base de données, ou utiliser un système
d'authentification utilisateur et de gestion de permission comme
phpLIB::auth or PEAR::LiveUser. Dans cet exemple nous esquiverons la
vérification de permission d'utilisateur et évaluerons
simplement si le champ de formulaire "urole" est défini
en tant que chaîne prédéterminée
"accounts", comme indiqué ci-dessous :
$aclCheck
= False; if($group == 'accounts') { $aclCheck = True; }
Si
l'utilisateur a la permission "de rôle" correcte nous
définissons la variable ($aclCheck) d'accès de contrôle
de liste (ACL) à "True", indiquant que cet
utilisateur a la permission d'avoir accès à nos
ressources.
Les
ressources métiers : maintenant nous pouvons appeler notre
classe métier "ReportsBusinessClass", si la variable
ACL ($aclCheck) est définie :
if($aclCheck
== True) {
...
L'admission
de cet utilisateur est bonne pour continuer, nous récupérons
l'objet de configuration "forward" "salesReportSuccess"
:
$myForward
= $mapping->findForwardConfig('salesReportSuccess');
Cela
correspond à l'élément "forward"
d'action dans notre fichier phpmvc-config.xml :
<forward
name="salesReportSuccess" path="salesReport.tpl"
/>
Maintenant
nous créons une nouvelle instance de notre classe métier
de rapport et appelons la méthode $salesReport->getSales(...)
:
$salesReport
=& new ReportsBusinessClass(); $sales =
$salesReport->getSales($this->dbConn);
Cette
classe métier retourne simplement un objet "$sales"
qui contient plusieurs attributs de classe auxquelles nous pouvons
avoir accès dans notre template de rapport :
class
Sales { var $salesNorth; var $salesSouth; ... }
Note :
pour réduire le couplage et assurer la réutilisation de
code, nous devons éviter de passer des objets de bibliothèque
spécifiques comme arguments à nos classes métiers.
Dans l'exemple ci-dessus nous passons simplement une référence
de base de données ($this->dbConn)
à la méthode d'objet métier. Cette conception
peut nous permettre de réutiliser notre classe métier
dans d'autres applications.
Finalement
nous sauvons l'objet "$sales" avec la requête. Nous
aurons accès à cet objet sur notre template de vue :
$request->setAttribute('FORM_DATA',
$sales);
Permission
refusée : si cet utilisateur n'est pas autorisé à
accéder à cette ressource particulière
($aclCheck
= False), nous récupérons
l'objet "forward" de configuration "salesReportFailure"
:
$myForward
= $mapping->findForwardConfig('salesReportFailure');
Cela
correspond à l'élément forward d'action dans
notre fichier phpmvc-config.xml :
<forward
name="salesReportFailure" path="salesReportIndex.tpl"/>
La
tâche suivante est de configurer le message d'erreur approprié
à être affiché dans le formulaire. Regarder la
section "ActionForm" ci-dessus pour une description de
l'utilisation des classes PropertyMessageResources et ActionErrors :
$msg
= $pmr->getMessage($locale,
'report.auth.failed'); $actionErrors->add(
'report_auth_failed', new ActionError($msg) );
Notez
que nous créons un message sans paramètres de
remplacement ($args) dans ce cas.
La
déclaration suivante sauve l'objet d'erreurs à l'objet
requête pour une référence ultérieure dans
notre page template :
$request->setAttribute(Action::getKey('ERROR_KEY'),
$actionErrors);
Nous
pouvons retrouver plus tard les objets d'erreurs comme ceci :
$errors
= $request->getAttribute( Action::getKey('ERROR_KEY') );
Les
champs de saisie appropriés sont maintenant sauvés dans
l'objet "$form" (ActionForm), celui qui a été
passé comme paramètre à la méthode
"SalesReportAction->execute()"
:
$form->setUserName($username); $form->setPassWord($password); $form->setUserRole($group);
Et
l'objet "$form" est sauvé à l'objet requête
pour une référence ultérieure :
$request->setAttribute(
'ACTION_FORM', $form );
L'objet
"$form" peut être récupéré comme
ceci :
$form
= $request->getAttribute('ACTION_FORM');
Prochain
arrêt : l'"ActionDispatcher". Tout ce que nous devons
faire maintenant est de retourner l'objet "$myForward" que
nous avons défini précédemment, dépendant
de la permission utilisateur d'accéder à nos
comptes-rendus économiques. L'objet "$myForward"
contient maintenant le nom de la ressource (template) qui doit être
utilisée.
return
$myForward;
Le
contrôleur appelle maintenant l'"ActionDispatcher"
pour manipuler le traitement et l'acheminement de la réponse
produite. Ou plus précisément, notre classe spécifique
d'application qui étend la classe "ActionDispatcher"
du framework.
XI)La
vue
Avant
que nous ne regardions l'"ActionDispatcher", nous devrions
jeter un regard rapide à la "Vue", ou ressources de
template.
Comme
mentionné ci-dessus dans ce guide nous utiliserons des
templates de page simples comme composants "Vue". Ces
templates contiennent quelques balises de langage PHP qui utilisent
des objets de données de formulaire que nous avons créés
plus tôt. Cette technique peut être plus appropriée
pour les petits projets qui ne garantissent pas la complémentarité
de classes spécialisées dans la manipulation de
formulaires. Pour des plus grands projets les développeurs
peuvent utiliser une librairie comme phplib::OOHForms ou
PEAR::HTML_QuickForm pour une approche plus automatisée de
l'implémentation de la vue dans php.MVC.
N'importe
quelle technique est utilisée, les ressources template de
l'application doivent être construites de telle façon
que les non programmeurs peuvent facilement travailler sur les pages
template sans affecter notre logique métier critique. Par
exemple, aucun code métier ne doit être inclus dans les
templates, seulement des appels aux objets de données
prédéfinis.
Il y a
actuellement beaucoup de discussions sur le pour et contre des
différentes techniques de template. Les avantages et les
inconvénients de ces approches de conception de page sont un
sujet de recherche en soi et sont au-delà de la portée
de ce guide. Veuillez consulter la section des ressources de ce guide
pour des liens à d'autres ressources sur ce sujet.
L'exemple
présenté dans ce guide utilise deux ressources
template. La page "salesReportIndex.tpl" est l'index, ou
page de départ. Si nous trouvons des erreurs d'entrée
en traitant le formulaire, nous retournons l'utilisateur à
cette page et affichons les messages d'erreur appropriés. La
page "salesReport.tpl" agit comme un simple compte-rendu
métier qui affiche nos données de ventes prédéfinies.
La
page index de rapport de ventes. La page index de rapport de ventes
permet simplement à l'utilisateur d'entrer un nom
d'utilisateur, un mot de passe et un rôle d'utilisateur. Nous
avons vu dans la section "Action" comment la variable de
saisie du rôle d'utilisateur a été utilisée
pour vérifier la permission de l'utilisateur d'avoir accès
à notre compte-rendu métier.
Voici
une version légèrement condensée du template de
page d'index de rapport de ventes (salesReportIndex.tpl) ci-dessous
<!DOCTYPE
HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN"> <html> <head>
<title>Sales Report Index Page</title> <link
rel='stylesheet' type='text/css'
href="./style/man.css"> </head>
<body
leftmargin='2' topmargin='2' marginwidth='2'
marginheight='2'>
<table class='header'> <tr>
<td align="center"> <font
class="pageHeader">Sales Report Index Page</font>
</td> </tr> </table>
<h3>Welcome
to Our Sales Reporting Page</h3><br>
...
<font
color='red'> <?php print ($er =
$errors->getItemString('report_auth_failed')) ? $er.'<br>':
''; print ($er = $errors->getItemString('logon_username_reqd'))
? $er.'<br>': ''; print ($er =
$errors->getItemString('logon_password_reqd')) ? $er.'<br>':
''; ?> </font>
<form
action='Main.php?do=salesReport' Method='POST'/> <table
class='' border=1> <tr>
<td bgcolor='#EFEFEF'> Username: </td>
<td> <input type='text' Name='uname'
value='<?php print $form->username ?>' /> </td>
</tr> <tr> <td bgcolor='#EFEFEF'>
Password: </td> <td>
<input type='text' Name='pword' value='<?php print
$form->password ?>' /> </td> </tr>
<tr> <td bgcolor='#EFEFEF'> User
Role: </td> <td> <input
type='text' Name='urole' value='<?php print $form->userrole ?>'
/> </td> </tr> </table> <input
type='submit' name='submit' Value='Submit' />
</body> </html>
Comme
on peut le voir il s'agit simplement d'une page web standard, avec
l'utilisation complémentaire de balises en langage PHP.
Le premier
élément intéressant est la section de traitement
d'erreur :
<?php print
($er = $errors->getItemString('report_auth_failed')) ? $er.'<br>':
''; print ($er = $errors->getItemString('logon_username_reqd'))
? $er.'<br>': ''; print ($er =
$errors->getItemString('logon_password_reqd')) ? $er.'<br>':
''; ?>
Ici
nous accédons aux éléments d'erreurs (si il y en
a) que nous avons définis précédemment en
utilisant les identificateurs textes d'erreur comme
"report_auth_failed". Autrement une chaîne nulle est
insérée dans la page ("). Les objets mentionnés
dans le template sont rendus disponibles via notre
"ReportActionDispatcher", comme nous le verrons dans la
section suivante.
L'élément
intéressant suivant est la balise de formulaire montrée
ci-dessous :
<form
action='Main.php?do=salesReport' Method='POST'/>
L'action
dans la balise du formulaire spécifie le chemin à la
classe "Action" que nous avons développée
précédemment. Ce chemin (do=salesReport)
est utilisé par le contrôleur pour récupérer
le mapping d'action correspondant.
<action
path = "salesReport" type = "SalesReportAction"
... /> </action>
Ensuite
viennent les balises de saisie de formulaire : "Nom
d'utilisateur"; "Mot de passe" et "Rôle
d'utilisateur". Ils sont presque tous les mêmes, donc nous
regarderons juste le champ "Nom d'utilisateur", comme
indiqué ci-dessous :
<input
type='text' Name='uname' value='<?php print $form->username
?>'/>
Comme
nous pouvons le voir c'est un élément standard HTML de
saisie, à l'exception de l'attribut de valeur. Nous utilisons
une simple déclaration en langage PHP dans l'attribut de
valeur pour récupérer la propriété
"username" de l'objet "$form", qui est en réalité
une instance de notre classe ActionForm "SalesReportForm".
Et
l'élément "submit" classique complète
l'élément formulaire de cette page :
<input
type='submit' name='submit' Value='Submit'/>
Quand
l'utilisateur soumet le formulaire avec les entrées correctes
la page de rapport de ventes est affichée.
La
page de rapport des ventes : la page de rapport des ventes affiche
une table contenant nos données de ventes à
l'utilisateur après qu'il ai rentré ses lettres de
créance correctes au formulaire précédent.
Voici
une version condensée du template de page du rapport de ventes
(salesReport.tpl) :
<!DOCTYPE
HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN"> ... <h4>Sales Reports
(Millions of Dollars AU)</h4> <table class='idxTable'
bgcolor='#C0C0C0'> <tr class='idxTableHeader'>
<td>Report Description</td>
<td>Revenues</td> </tr> <tr
class='idxTableRow'> <td class='idxTableCell' nowrap>
Northern Sector </td> <td
class='idxTableCellData' nowrap> $ <?php print
$data->salesNorth ?>
</td> </tr> ... </table> ... </body> </html>
C'est une
page HTML très simple contenant une table simple.
A
l'intérieur de la balise "<td ... />" on
utilise une balise PHP pour accéder à la propriété
"salesNorth" de l'objet $data.
<?php
print $data->salesNorth ?>
Cet objet
"$data" est en réalité le formulaire de
données que nous avons créées dans la classe
"SalesReportAction" au dessus. Dans la section
"ActionDispatcher" ci-dessous nous verrons que l'objet
"$data" est rendu disponible au template, comme ceci :
$data
= $request->getAttribute('FORM_DATA');
Les lignes
de table sont très semblables et récupèrent
simplement le propriétés de $data : "salesSouth",
"salesEast" et "salesTerrit".
La page de
rapport des ventes ressemble à quelque chose comme :

Figure
9 : la page de rapport de vente
XII)L'ActionDispatcher
L'ActionDispatcher
est responsable de sélectionner la ressource Vue correcte et
de composer la réponse à l'utilisateur. Le diagramme
ci-dessous montre une vue d'ensemble du processus de
l'ActionDispatcher :

Figure
10 : l'ActionDispatcher
Extension
de l'ActionDispatcher. Dans la plupart des cas nous devrons étendre
la classe ActionDispatcher fourni par le framework php.MVC avec notre
propre classe dispatcher spécifique d'application. Dans cet
exemple nous créons une classe dispatcher appelée
"ReportActionDispatcher". Dans notre classe dispatcher nous
devons réécrire la méthode "serviceResponse()"
comme indiqué ci-dessous :
class
ReportActionDispatcher extends ActionDispatcher {
function
ReportActionDispatcher($uri='', $wrapper='', $servletPath='',
$pathInfo='', $queryString='', $name='')
{
parent::ActionDispatcher($uri='', $wrapper='',
$servletPath='', $pathInfo='',
$queryString='', $name='');
$this->log->setLog('isDebugEnabled' , False);
$this->log->setLog('isTraceEnabled' , False); }
function serviceResponse(&$request, &$response) {
$trace = $this->log->getLog('isTraceEnabled');
if($trace) $this->log->trace('Start:
TestActionDispatcher->serviceResponse(..)['.__LINE__.']');
$requestURI = $this->uri;
$form =
$request->getAttribute('ACTION_FORM'); $data =
$request->getAttribute('FORM_DATA'); $errors =
$request->getAttribute( Action::getKey('ERROR_KEY') );
$pageBuff = ''; ob_start(); include
$requestURI; $pageBuff = ob_get_contents();
ob_end_clean();
$response->setResponseBuffer($pageBuff); } }
La
méthode "serviceResponse()". Dans la méthode
"serviceResponse()" on peut activer la journalisation en
appelant la classe "logging" (après avoir défini
les flags de logging appropriés dans le constructeur au
dessus).
Maintenant
nous récupérons la ressource (URI) à utiliser
comme objet de Vue pour cette requête.
$requestURI
= $this->uri;
Dans
cet exemple l'URI sera la page de template "salesReportIndex.tpl"
ou "salesReport.tpl".
Maintenant
nous récupérons l'ActionForm, les données de
formulaire et les objets ActionErrors.
$form
= $request->getAttribute('ACTION_FORM'); $data =
$request->getAttribute('FORM_DATA'); $errors =
$request->getAttribute(Action::getKey('ERROR_KEY'));
Ce
sont les objets que nous avons créés dans nos classes
ActionForm et Action.
Note : ces
objets sont maintenant disponibles dans le cadre de cette méthode
et seront si visibles au template (URI) que nous chargerons ensuite.
Maintenant
nous pouvons inclure notre ressource template ($requestURI) entre les
déclarations de buffer de sortie PHP ob_start() et
ob_end_clean() :
ob_start();
include $requestURI; $pageBuff =
ob_get_contents(); ob_end_clean();
Comme
le template est inclus, n'importe quelle déclaration PHP à
l'intérieur du template sera exécutée comme si
le template était un script PHP normal. Les objets "$form",
"$data" et "$errors" sont maintenant visibles
pour n'importe quelle instruction dans le template.
Les
buffers de sortie PHP nous permettent de capturer la ressource
incluse ($requestURI) et de sauver la sortie à une variable
tampon: "$pageBuff". La variable "$pageBuff"
contient maintenant le contenu complet de la réponse HTTP, que
notre utilisateur verra comme une page web dans son navigateur.
Et
enfin nous retournons le contenu "$pageBuff" au Dispatcher
$response->setResponseBuffer($pageBuff);
Le
Dispatcher envoi maintenant le contenu "$pageBuff" comme
réponse HTTP au client (habituellement le navigateur de
l'utilisateur).
Document version: 1.0 – 02-April-2004
Copyright © 2004 John C. Wildenauer. All rights reserved.
|