Sleek Action Edit | SourceForge - PHP - Freshmeat - Gibson Research - Ubuntu Linux - Clusty Search - Babel Fish Translation - WordReference Dictionaries - Wiktionary - ASP
php.MVC, The Model View Controller Framework for PHP Web Applications
  Free OpenSource Downloads
The Model View Controller Framework for PHP Web Applications
 
spacer Features •  Demos •  Docs •  Design •  Download •  CVS •  Support •  Developers

spacer

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/


Modification

Auteur

Date

Description

Version

John C. Wildenauer

02-Apr-2004

Création du document

1

Olivier HENRY

19-May-2005

Traduction française

1.00


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 :

  • Définir les chemins de l'application : on définit le chemin d'installation des librairies php.MVC et le chemin à notre application web. Par exemple :

$appServerRootDir = 'C:/WWW/phpmvc-base';
$moduleRootDir = 'C:/WWW/mycompany';

  • Définir l'"ActionDispatcher" de l'application : on utilise habituellement notre propre classe "Dispatcher" personnalisée qui étend l'"ActionDispatcher" du framework

$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';

  • Inclure les classes d'application : maintenant le "Front Controller" charge les fichiers de classe qu'il doit utiliser. Nous pouvons charger optionnellement des fichiers de classe d'application spécifiques en utilisant le fichier "/WEB-INF/prepend.php" :

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.



Printable Page
spacer

SleeK Action Edit - Code Editor for Windows PHP Logo php.MVC Logo SourceForge
Copyright © 2006 John C. Wildenauer. All rights reserved.