Noas PHP nest pas une extension PHP, ni un module Apache, ou autres composants « exécutables ». Il sagit purement et simplement densemble de classes et dun fichier de configuration. Procurer vous larchive en prenant soin de choisir celle qui correspond à lextension des scripts PHP5 reconnue par votre serveur (.php ou .php5 ou utiliser un logiciel pour renommer tous les fichiers à votre convenance ). Décompresser le contenu de larchive dans un répertoire neutre, que nous appellerons « NOAS_INSTALL ». Il ne vous reste plus quà définir correctement les constantes du fichier de configuration « noas-server-conf.inc ».
Définissez la constante « NOAS_SEPARATOR » à « \\ » si vous développez sous Windows ou à « / » pour Linux.
Définissez « NOAS_HOME » à « NOAS_INSTALL ».
Définissez « NOAS_WORK_DIR » en spécifiant le répertoire dans lequel vous souhaitez que le framework génère ses fichiers temporaires. Veuillez à ce que PHP ai le droit dy créer des dossiers et des fichiers.
Définissez « NOAS_LOG_DIR » en spécifiant le répertoire dans lequel vous souhaitez que le framework génère les fichiers de logs. Veuillez à ce que PHP ai le droit dy créer des dossiers et des fichiers.
Définissez « NOAS_PHP_EXTENSION » en spécifiant lextension PHP5 reconnue par votre serveur (.php , .php5 ou autres ).
La configuration étant terminée, nous pouvons débuter la découverte du framework au travers dun petit projet que nous appellerons EMC (Entreprise Message Center), une application de dépôt et de consultation de messages centralisés.
En PHP5 vous pouvez placer vos définitions de classes à peu prés nimporte où. Par contre, vous devez faire vous-même leffort de les retrouver avec le risque de produire une application non portable. Noas PHP a donc ajouter les notions de chemin de classes et packages qui permettent dimporter une définition de classe aisément en faisant abstraction de sa location physique. Un chemin de classes est une liste de répertoires, séparée par des « ; », qui va servir de base pour la recherche des définitions. Le répertoire « NOAS_HOME »/classes et « MA_WEB_APP »/NOAS-INF/classes sont toujours inclus par défaut, vous navez pas besoin de les spécifier. Comme nous le verrons plus loin, cette valeur est définissable pour chaque application.
Un package représente une arborescence de dossier que lon exprime par la liste des dossiers séparés par un « . ». En utilisant les packages pour organier vos classes, vous obtiendrez des projets plus limpides, donc plus facile à maintenir. La base dun package valide est toujours un répertoire du chemin de classes.
Le fichier dimplémentation dune classe doit suivre une nomenclature particulière afin dêtre retrouvée : « MA_CLASSE ».class« EXTENSION_PHP »
Une fois implémenter dans le bon fichier, accessoirement le bon package, il vous suffit dimporter sa définition en utilisant son nom complet comme ci-dessous.
Noas::import("noas.core.NoasUserRequest");
Dans ce cas la classe NoasUserRequest se trouve dans le fichier
« NOAS_HOME »/classes/noas/core/NoasUserRequest.class.php Nous vous rappelons que les classes du package « noas.type » nont pas besoin dêtre importées. Elles sont chargées en même temps que le framework.
Exceptionnellement, le temps que vous vous familiarisiez avec le framework, nous vous proposons dutiliser le squelette type, « noasphp-blank.zip », disponible uniquement sur votre CD. Il contient des dossiers « standards » comme « images », « css », etc. et le dossier obligatoire « NOAS-INF » pré-structuré selon les spécifications en vigueurs pour imposées par le framework. Décompressez le contenu de larchive dans le répertoire « emc » sur votre serveur.
Intéressons-nous au de configuration de lapplication « noas-blank-conf.inc ». Renommez le en « noas-emc-conf.inc ». Bien que son nom et son emplacement soient arbitraires, vous avez tout intérêt à définir votre propre nomenclature afin de pouvoir le distinguer et le retrouver facilement.
Définissez la constante « NOAS_APPLICATION_HOME » qui correspond au répertoire de votre application.
Définissez la constante « NOAS_APPLICATION_HTTP » qui correspond à ladresse de votre application.
Définissez la constante « NOAS_APPLICATION_GROUP », qui correspond au groupe de votre application, à « EMC_GROUP ». Nous rappelons que les applications Noas PHP peuvent se grouper et disposer de données communes (langue, format, préférence utilisateur, etc.).
Définissez la constante « NOAS_APPLICATION_NAME », qui correspond au nom de votre application, à « EMC ».
Définissez la constante « NOAS_APPLICATION_CLASS », qui correspond au nom complet de la classe de votre application, à « emc.env.EmcApplicationContext ».
Vous devez nécessairement inclure le fichier de configuration du framework comme den lexemple ci-dessous.
<?php
//////////////////////////////////////////////////////////////////////
// File : noas-emc-conf.inc
/////////////////////////////////////////////////////////////////////
include_once("/dev/noasphp1.0.0/noas-server-conf.inc");
define('NOAS_APPLICATION_HOME', '/dev/www/emc');
define('NOAS_APPLICATION_HTTP', 'http://localhost/emc/');
define('NOAS_CLASS_PATH','');
define('NOAS_APPLICATION_NAME', 'EMC');
define('NOAS_APPLICATION_GROUP', 'EMC_GROUP');
define('NOAS_APPLICATION_CLASS', 'emc.env.EmcApplicationContext');
define('NOAS_APPLICATION_LOCAL', 'fr');
define('NOAS_APPLICATION_DATE_FORMAT', 'd/m/Y H:i:s');
define('NOAS_APPLICATION_TEMP', '/dev/www/emc/tmp');
define('NOAS_APPLICATION_TIMEOUT', 60 * 60);
define('NOAS_TRACE_LEVEL', 100);
define('NOAS_LOG_FILE_PATTERN', '&host/&name/&ip_&d-&m-&y.txt');
?>
Lenvironnement dexécution est lensemble des classes définissant votre application. Il est constitué de classes nécessaires et suffisantes pour que votre application se charge sans erreur. De manière générale, comme dans notre cas, il sagit des classes de session, dinterface et dapplication.
Nous allons toutes les placer dans le package « emc.env » de notre application.
La classe « emc.env.EmcSession » va modéliser notre session utilisateur.
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcSession.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.core.NoasUserSession");
class EmcSession extends NoasUserSession {
function __construct() {
parent::__construct();
}
public function initialize() {
parent::initialize();
}
}
?>
La classe « emc.env.EmcInterface » vas modéliser notre interface utilisateur. Choisissez le mode « debug » pour le temps du développement. Vous passerez en mode « release » une fois le projet achevé.
//////////////////////////////////////////////////////////////////////
// File : EmcInterface.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.core.NoasUserInterface");
class EmcInterface extends NoasUserInterface {
function __construct() {
parent::__construct(self::debug);
}
}
Il ne vous reste plus quà implémenter la classe « emc.env.EmcApplicationContext » pour modéliser lapplication.
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcApplicationContext.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.core.NoasUserRequest");
Noas::import("noas.core.NoasApplicationContext");
Noas::import("emc.env.EmcSession");
Noas::import("emc.env.EmcInterface");
class EmcApplicationContext extends NoasApplicationContext {
function __construct() {
parent::__construct("php/error".NOAS_PHP_EXTENSION);
}
protected function createSession(){
return new EmcSession();
}
protected function createInterface(){
return new EmcInterface();
}
protected function createRequest(){
return new NoasUserRequest();
}
public function initialize(){
parent::initialize();
}
}
?>
Vous devez impérativement définir une page derreur. Elle sera affichée chaque fois quune exception na pas été capturée. Libre à vous de renvoyer une erreur HTTP standard, comme ci-dessous ou de ladapter à votre guise.
<?php
//////////////////////////////////////////////////////////////////////
// File : error.php
/////////////////////////////////////////////////////////////////////
header("HTTP/1.0 500 Internal Server Error");
?>
Notez que nous utilisons toujours la constante « NOAS_PHP_EXTENSION » à la place de lextension reconnue par linterpréteur PHP. Cela nous permet de déployer les applications quelle que soit la stratégie du serveur cible.
Le concept de page en Noas PHP suit le très célèbre design pattern « MCV ». Pour notre part, la template représente une vue et le contexte un modèle (enrichi dun état et dun comportement). Le contrôle étant assuré par un élément interne du framework..
Une template est un fichier HTML quelconque, placé dans le répertoire « MA_WEB_APP »/NOAS-INF/template (vous pouvez créer des arborescences), composée de tagues spécifiques au framework. Lors du chargement de la page, le framework va la « compiler » en code PHP selon le mode de linterface (release, design, debug). Une compilé le code PHP produit sera exécuté sur le contexte. Le mode « debug » spécifie que la template sera toujours recompilée à chaque nouvelle requête. Le mode « design » spécifie que la template ne sera compilée que si elle a été modifiée depuis la dernière compilation. Le mode « release » spécifie que la template ne sera compilée quune seule fois.
Pour placer des commentaires, non visibles après compilation, placez les entre « <%--
--%> ».
Créons notre première template, « home.tpl ».
<%--
//////////////////////////////////////////////////////////////////////
// File : home.tpl
/////////////////////////////////////////////////////////////////////
--%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>Démo - Noas PHP</title>
</head>
<body>
<h1>Noas PHP, extrême framework</h1>
<hr style="width: 100%; height: 2px;">
<div style="text-align: center;">
programmez!
</div>
</body>
</html>
Tous les contextes de page dérivent de la classe « noas.web.context.NoasPageDeviceContext». Il faut ensuite définir la template à utiliser, la page de retour valide et la page de retour invalide. La page de retour valide correspond au script PHP responsable du chargement du contexte. La page de retour invalide correspond au script PHP à exécuter lorsque le contexte nest pas valide, généralement des points dentré (page daccueil, formulaire de connexion, etc.). Les chemins sont données en relatif.
Créons le contexte « emc.context.EmcHomePage ».
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcHomePage.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.web.context.NoasPageDeviceContext");
class EmcHomePage extends NoasPageDeviceContext {
function __construct() {
parent::__construct("home.tpl"
,"php/home".NOAS_PHP_EXTENSION);
$this->setInvalidPage("php/home".NOAS_PHP_EXTENSION);
}
}
?>
Vous remarquerez que la page de retour valide et invalide sont identiques car il sagit dun point dentré sur lapplication.
Intéressons-nous à la page qui doit charger le contexte, « php/home.php ». Vous navez que deux lignes de code à y ajouter. Premièrement insérez le fichier de configuration de lapplication, deuxièmement chargez le contexte en spécifiant la classe du contexte et si le contrôle de la navigation doit être activé. Le contrôle de la navigation est une technique qui permet au développeur dinterdire laffichage asynchrone dune page. Imaginez si un utilisateur entre directement dans le navigateur ladresse dune page sensée afficher le détail dune commande ! Comme cette commande nexiste pas, il est fort à parier que cette manipulation va déstabiliser votre application.
Dans notre cas, et de manière générale pour les points dentré, désactivez se contrôle ( au risque de voir apparaître des boucles infinies !).
<?php
//////////////////////////////////////////////////////////////////////
// File : home.php
/////////////////////////////////////////////////////////////////////
include_once("../noas-emc-conf.inc");
Noas::loadPageContext("emc.context.EmcHomePage", false);
?>
Saisissez ladresse de la page dans votre navigateur et observez le résultat.
Le framework dispose dun mécanise vous permettant de réaliser des applications en plusieurs langues tout en conservant le même code source. Vous avez la possibilité de placer des ressources dans un répertoire qui varie en fonction de langue de linterface. Le changement se fait de manière transparente pour le développeur. Il existe trois types de ressource standard, les messages derreurs, les messages dinformations et les libellés dinterface (GUI). Vous être libre de laisser court à votre imagination pour en définir dautres. Ces ressources standards se présent sous la forme de fichier au format « clef / valeur » (INI). Chargez les, ainsi que toutes vos ressources personnalisées, un surchargeant la méthode « loadResource() » de linterface.
protected function loadResource($resourceBase, $local){
$this->loadGuiResource( $resourceBase."emc-gui.resource");
$this->loadErrorResource( $resourceBase."emc-error.resource");
$this->loadMessageResource( $resourceBase."emc-message.resource");
}
Les ressources doivent être présentes dans tous les répertoires correspondant aux langues supportées. Nous nous contenterons du local « fr » qui a dailleurs été spécifié par défaut dans la configuration. Créez les fichiers de ressource dans le répertoire « MA_WEB_APP »/NOAS-INF/resource/fr. Internationalisons notre template. Notez que cela se fait généralement dans lautre sens.
Définissez les deux seuls libellés dont nous avons besoin pour le moment dans le fichier GUI. Prenez soins de choisir des clefs significatives car pour un projet complet le nombre peut être conséquent.
EMC_TITLE="Noas PHP, extrême framework"
EMC_BOOK="programmez!"
Pour utiliser ces libellés dans la tempate, vous devez importer la librairie de tagues «noas.web.tag ». Elle contient des tagues classiques dont « resource » qui vous permet daccéder aux valeurs des ressources standards. Lorsque vous importé une librairie vous devez spécifier lespace de nomage à utiliser.
<%--
//////////////////////////////////////////////////////////////////////
// File : home.tpl
/////////////////////////////////////////////////////////////////////
--%>
<%@taglib uri="noas.web.tag" prefix="noas"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>Démo - Noas PHP</title>
</head>
<body>
<h1><noas:resource gui="EMC_TITLE"/></h1>
<hr style="width: 100%; height: 2px;">
<div style="text-align: center;">
<noas:resource gui="EMC_BOOK"/>
</div>
</body>
</html>
Il peut arriver que certaine partie des templates dune application soient similaire. Par exemple le bloque contenue dans la balise « header » a de très forte chance de ne pas changer. Si vous souhaitez le modifier, le titre par exemple, vous seriez contraint de le propager sur lensemble des pages. Une astuce consiste à placer les bloques identiques dans des fichiers puis les inclure dans les templates. Ce mode dinclusion est appelé « inclusion statique » car elle intervient avant la compilation de la template utilisatrice.
<%--
//////////////////////////////////////////////////////////////////////
// File : header.tpl
/////////////////////////////////////////////////////////////////////
--%>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<script src="<noas:base/>js/noas.js" type="text/javascript"></script>
<title>Démo - Noas PHP</title>
La tague « < :base/> » nous sert à obtenir ladresse HTTP de lapplication et le fichier « noas.js » sert à importer les scripts nécessaires à linteractivé de linterface.
<head><%@include file="header.tpl"%></head>
Nous avons précisez que les contextes étaient capables de « réagire » face à un événement. Un événement peut être généré par linterface ou directement par programmation. Pour le capturer, un contexte doit implémenter une méthode de type « XXXEvent() » où XXX est le nom de lévénement. Les tagues capables den générer sont très facilement reconnaissable. Elles possèdent toutes lattribut « event » à définir au nom de lévénement. La librairie de tague « noas.web.tag.html » en contient quelques-unes comme « href », « action », « form », « submit », etc.
Capturons lévénement « goToMessageEdit » en implémentant la méthode, vide pour le moment, « goToMessageEditEvent() ». Il sera généré par lutilisateur en cliquant sur le lien « programmez ! ».
Importez la librairie « noas.web.tag.html »
<%@taglib uri="noas.web.tag.html" prefix="html"%>
Placez lévénement dans la template à laide de la balise « < :href/> ».
<html:href event="goToMessageEdit">
<noas:resource gui="EMC_BOOK"/>
</html:href>
Le framework met à votre disposition un moyen de communiquer avec lutilisateur en lui affichant des messages qui ne seront valide que pour une seule requête. Ces messages peuvent provenir de la validation dun formulaire ou de votre propre volonté. Ils utilisent les ressources standards, donc supportent linternationalisation. Envoyons un message derreur lorsque lévénement « goToMessageEdit » est générer.
Ajoutez une entré dans fichier de ressources derreur « emc-error.resource »
NO_IMPLEMENT_ERROR="Cette fonctionnalité est provisoirement indisponible !"
Composez le message dans la méthode évènementielle.
public function goToMessageEditEvent(){
$message = new NoasMessage();
$message->addErrorMessage("NO_IMPLEMENT_ERROR", array());
self::getRequest()->getMessage()->addMessage($message);
}
Vous êtes libre de placer les messages utilisateur où vous le souhaitez dans la template. Vous pouvez ainsi personnaliser le rendu, par exemple les afficher en rouge.
<div style="color: red;">
<html:errorMessage/>
</div>
Si vous ne voulez quafficher le message derreur « NO_IMPLEMENT_ERROR » placez plutôt le code suivant dans votre template.
<div style="color: red;">
<html:errorMessage key= "NO_IMPLEMENT_ERROR"/>
</div>
Chaque champ dun formulaire est toujours relié à une propriété dun objet (modèle). Par défaut, il sagit du contexte sur lequel sexécute le script. Il est très souvent judicieux de spécifier directement un objet métier comme modèle. Vous bénéficiez au moins dune mise à jour automatique ( sans passer par dinterminable « setXXX/getXXX » ) et dune réutilisation des données recueillies. Optons pour cette solution. Mappons le formulaire sur lobjet métier « emc.business.EmcMessageEntity ». Rien noblige à ce quil dérive de « NoasObject ».
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcMessageEntity.class.php
/////////////////////////////////////////////////////////////////////
class EmcMessageEntity extends NoasObject {
private $entryId;
private $surname;
private $firstname;
private $email;
private $subject;
private $message;
private $response;
private $service;
private $dateRegister;
private $dateSender;
private $editable = false;
public function getSurname() {
return $this->surname;
}
public function setSurname($_surname) {
$this->surname = $_surname;
}
public function getFirstname() {
return $this->firstname;
}
public function setFirstname($_firstname) {
$this->firstname = $_firstname;
}
public function getEntryId() {
return $this->entryId;
}
public function setEntryId($_entryId) {
$this->entryId = $_entryId;
}
public function hasResponse() {
return isset($this->response);
}
public function isEditable() {
return $this->editable;
}
public function setEditable($_editable) {
$this->editable = $_editable;
}
}
?>
Implémentez le contexte de page dédition du message dans la classe « emc.context.EmcEditPage ». Nous pouvons déjà prévoir les évènements « save » et « cancel ».
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcEditPage.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.web.context.NoasPageDeviceContext");
Noas::import("emc.business.EmcMessageEntity");
class EmcEditPage extends NoasPageDeviceContext {
private $businessObject;
function __construct() {
parent::__construct("edit.tpl"
,"php/edit".NOAS_PHP_EXTENSION);
$this->setInvalidPage("php/home".NOAS_PHP_EXTENSION);
}
public function getBusinessObject(){
if(!isset($this->businessObject)){
$this->businessObject = $this->createBusinessObject();
}
return $this->businessObject;
}
public function setBusinessObject($_businessObject){
$this->businessObject = $_businessObject;
}
public function saveEvent(){
// @TODO
}
public function cancelEvent(){
$this->setBusinessObject(null);
}
protected function createBusinessObject(){
return new EmcMessageEntity();
}
}
?>
<?php
//////////////////////////////////////////////////////////////////////
// File : edit.php
/////////////////////////////////////////////////////////////////////
include_once("../noas-emc-conf.inc");
Noas::loadPageContext("emc.context.EmcEditPage", false);
?>
Vous pouvez dés maintenant ajouter les libellés associés à cette template dans le fichier de ressource « emc-gui.resource ».
EMC_SAVE_BUTTON="Envoyer"
EMC_CANCEL_BUTTON="Annuler"
EMC_MESSAGE_ENTRYID="N°"
EMC_MESSAGE_SURNAME="Nom"
EMC_MESSAGE_FIRSTNAME="Prénom"
EMC_MESSAGE_EMAIL="Email"
EMC_MESSAGE_SUBJECT="Sujet"
EMC_MESSAGE_MESSAGE="Message"
EMC_MESSAGE_RESPONSE="Réponse"
EMC_MESSAGE_SERVICE="Service"
EMC_MESSAGE_DATE_REGISTER="Enregistré le"
EMC_MESSAGE_DATE_SENDER="Envoyé le"
La rédaction de la template nest ni plus ni moins quun ensemble de tagues de type « input ». Leurs attributs sont quasiment identiques à leur homologue HTML, consultez la documentation pour plus de détails.
<%--
//////////////////////////////////////////////////////////////////////
// File : edit.tpl
/////////////////////////////////////////////////////////////////////
--%>
<%@taglib uri="noas.web.tag" prefix="noas"%>
<%@taglib uri="noas.web.tag.html" prefix="html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><%@include file="header.tpl"%></head>
<body>
<h1><noas:resource gui="EMC_TITLE"/></h1>
<hr style="width: 100%; height: 2px;">
<html:form name="message">
<table cellspacing="1" cellpadding="0" class="list">
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_MESSAGE_SURNAME"/> :
</td>
<td>
<html:textfield model="businessObject" property="surname"
size="20" maxlength="200" />
</td>
</tr>
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_MESSAGE_FIRSTNAME"/> :
</td>
<td>
<html:textfield model="businessObject" property="firstname"
size="20" maxlength="200"/>
</td>
</tr>
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_MESSAGE_EMAIL"/> :
</td>
<td>
<html:textfield model="businessObject" property="email"
size="20" maxlength="200" />
</td>
</tr>
<tr>
<td style="vertical-align:middle;" colspan="2">
<noas:resource gui="EMC_MESSAGE_SUBJECT"/> : <br/>
<html:textfield model="businessObject" property="subject"
size="46" maxlength="300" />
</td>
</tr>
<tr>
<td style="vertical-align:middle;" colspan="2">
<noas:resource gui="EMC_MESSAGE_MESSAGE"/> : <br/>
<html:textarea model="businessObject" property="message"
rows="5" cols="35"/>
</td>
</tr>
<tr>
<td style="text-align: center; vertical-align:bottom;" colspan="2">
<html:submit gui="EMC_SAVE_BUTTON" event="save"/>
<html:button gui="EMC_CANCEL_BUTTON" event="cancel"/>
</td>
</tr>
</table>
</html:form>
</body>
</html>
Si vous testez lexemple à ce niveau, vous constaterez que lévénement « save » est exécuté sans entrave même si les champs sont vides. Ceci nest pas souhaitable car il est inadmissible de sauvegarder un message sans aucune information. Deux solutions se posent à nous. Soit nous effectuons manuellement les contrôles des valeurs dans la méthode « saveEvent() », soit nous utilisons les mécanismes du framework. Sachez que toutes les anomalies de valeurs détectables à laide dune expression régulière sont interceptables.
Une règle expression régulière) est associé à une clef unique. Vous devez ajouter une entré de même clef dans le fichier de ressource derreur correspondant au message à renvoyer à lutilisateur lors de son occurrence, et une entré de même clef dans un fichier de propriétés, correspondant à lexpression régulière associée.
Pour faire simple, énonçons que seul les messages non vide avec un sujet non vide et un mail valide seront acceptés. Ce qui nous conduit à définir deux règles, « NOTNULL_RULES » et « MAIL_RULES ». Ajouter les messages derreur correspondant.
NOTNULL_RULES="ce champ ne peut pas être nul !"
MAIL_RULES="ce champ doit être un e-mail valide !"
Un fichier de propriétés na besoin que dêtre dans le chemin de classes. Créez le directement dans le répertoire « classes » de votre projet. Vous devez explicitement charger le fichier des règles lors de linitialisation de lapplication.
;//////// emc-rules.properties ///////////////////
NOTNULL_RULES="[^\s]+"
MAIL_RULES="/^[^@]+@(([\w\-]+\.){1,4}[a-zA-Z]{2,4}|(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5]))$/"
public function initialize(){
parent::initialize();
$this->loadRules("emc-rules.properties", true);
}
Vous pouvez à présent activer la validation automatique des règles, mais avant vous allez importer la librairie de tagues « noas.web.tag.logic » qui vous permettra dutiliser des structures logiques dans vos temples ( if, else, while, etc.).
<%@taglib uri="noas.web.tag.logic" prefix="logic"%>
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_MESSAGE_EMAIL"/> :
<logic:ifError key="EMC_MESSAGE_EMAIL">
<span title="<html:errorMessage key="EMC_MESSAGE_EMAIL"/>"
style="color: red; cursor: hand;" >*</span>
</logic:ifError>
</td>
<td>
<html:textfield model="businessObject" property="email"
size="20" maxlength="200"
rules="NOTNULL_RULES" errorKey="EMC_MESSAGE_EMAIL"/>
</td>
</tr>
<tr>
<td style="vertical-align:middle;" colspan="2">
<noas:resource gui="EMC_MESSAGE_SUBJECT"/> :
<logic:ifError key="EMC_MESSAGE_SUBJECT">
<span title="<html:errorMessage key="EMC_MESSAGE_SUBJECT"/>"
style="color: red; cursor: hand;" >*</span>
</logic:ifError>
<br/>
<html:textfield model="businessObject" property="subject"
size="46" maxlength="300"
rules="NOTNULL_RULES" errorKey="EMC_MESSAGE_SUBJECT"/>
</td>
</tr>
<tr>
<td style="vertical-align:middle;" colspan="2">
<noas:resource gui="EMC_MESSAGE_MESSAGE"/> :
<logic:ifError key="EMC_MESSAGE_MESSAGE">
<span title="<html:errorMessage key="EMC_MESSAGE_MESSAGE"/>"
style="color: red; cursor: hand;" >*</span>
</logic:ifError>
<br/>
<html:textarea model="businessObject" property="message"
rows="5" cols="35"
rules="NOTNULL_RULES" errorKey="EMC_MESSAGE_MESSAGE"/>
</td>
</tr>
Vous avez constatez que la règle « MAIL_RULES » na pas été utilisé. En réalité elle est trop complexe pour être utilisé en automatique (la fonction PHP ereg() est utilisée en interne ). Faite le manuellement de la manière suivante :
public static function checkEmail(NoasMessage $_report, $_key, $_value){
if(!preg_match (self::getApplication()->getRule("MAIL_RULES")
, $_value)){
$error = new NoasMessage();
$error->addErrorMessage($_key
, array("NOAS_INPUT_ERROR"=>"MAIL_RULES"));
$_report->addMessage($error);
}
}
public function saveEvent(){
$report = new NoasMessage();
self::checkEmail($report, "EMC_MESSAGE_EMAIL"
, $this->getBusinessObject()->getEmail());
if($report->hasErrorMessage()){
self::getRequest()->getMessage()->addMessage($report);
} else {
// @TODO
}
}
Tester lapplication. Vous constaterez quapparaissent des étoiles rouges à côté des champs erronés. Passez le curseur au-dessus pour lire le message derreur associé.
Sur le précédant formulaire, il maque la liste des services destinataires du message. Nous allons lajouter en utilisant un concept des « Enumérations ».
Les énumérations sont des associations clef/valeur où les clefs sont des codes et les valeurs des chaînes de caractères. Elles sont essentiellement utilisées pour représenter des ensembles finis de libellés, par exemple la liste des civilités (M., Mme, Mlle ). Le framework fournie une interface et des implémentations standards pour les modéliser.
Les énumérations supportent linternationalisation. Lorsque vous les utilisez dans une template, sur une combo box par exemple, elles sont en premier lieu cherchées sur linterface utilisateur, puis sur le modèle de la tague. Donc à moins dune contrainte particulière, elles seront gérées par linterface de votre application.
Pour notre exemple utilisons une énumération basée sur les fichiers (format INI). Comme nous vous lavons précisez, les énumérations supportent linternationalisation, vous placerez donc le fichier « emc-service.enum » dans le répertoire des ressources.
10="Direction Ressources Humaines"
20="Contentieux & Recouvrement"
30="Support Technique"
40="Commercial"
50="Marketing"
60="Autre"
Limplémentation à utiliser est « noas.util.enum.NoasFileEnum ». Son constructeur prend en argument le chemin complet du fichier à utiliser. Pour rendre cette énumération disponible pour les tagues de type « liste de choix » vous allez définir une propriété correspondante dans linterface (sans oublier de limporter).
Vous devez charger les données en même temps que le changement de langue.
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcInterface.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.core.NoasUserInterface");
Noas::import("noas.util.enum.NoasFileEnum");
class EmcInterface extends NoasUserInterface {
private $serviceEnum;
function __construct() {
parent::__construct(self::debug);
}
public function getServiceEnum(){
if(!$this->serviceEnum->isLoad()){
$this->serviceEnum->load();
}
return $this->serviceEnum;
}
protected function loadResource($resourceBase, $local){
$this->loadGuiResource( $resourceBase."emc-gui.resource");
$this->loadErrorResource( $resourceBase."emc-error.resource");
$this->loadMessageResource( $resourceBase."emc-message.resource");
$this->serviceEnum = new NoasFileEnum($resourceBase."emc-service.enum");
$this->serviceEnum->setNullLabel(null);
}
}
?>
Il ne vous reste plus quà ajouter la combo box dans le formulaire en spécifiant lénumération utilisée.
<tr>
<td style="vertical-align:middle;" colspan="2">
<noas:resource gui="EMC_MESSAGE_SERVICE"/> :
<html:combobox model="businessObject" property="service"
enum="serviceEnum" />
</td>
</tr>
Pour stocker nos informations nous navons besoin que dune base de données et dune table. Nous avons opté pour SQLite livré avec la distribution standard de PHP5. Créez la base de donnée « SQLDEMO ». Le fichier associer est placé dans le répertoire du projet sous le nom de « sqldemo.db ».
Chargez la définition de classe du moteur SQLite dans fichier dimplémentation de votre application.
Noas::import("sqlite.exchange.SQLiteDriver");
Définissez « demo » comme nom de référence à cette source de données en inscrivant les lignes suivantes dans la méthode dinitialisation de lapplication.
public function initialize(){
parent::initialize();
$this->loadRules("emc-rules.properties", true);
NoasExchangeManager::setReference("demo"
,"sqlite://[0666]"
.NOAS_APPLICATION_HOME
.NOAS_SEPARATOR."sqldemo.db");
}
Il faut à présent préparer la source de données. Créez la table nécessaire en exécutant linstruction SQL suivante :
CREATE TABLE emc_entry (
entry_id BIGINT NOT NULL PRIMARY KEY ,
surname VARCHAR ( 150 ),
firstname VARCHAR ( 100 ) ,
email VARCHAR ( 60 ) NOT NULL ,
subject VARCHAR ( 200 ) NOT NULL ,
message TEXT NOT NULL ,
response TEXT ,
service INT NOT NULL ,
date_register TIMESTAMP NOT NULL ,
date_sender TIMESTAMP ) ;
Nous avons également besoin dune séquence pour contrôler les numéros des enregistrements. Nous créons donc également la séquence « emc_entry_seq ».
CREATE TABLE noas_exchange_sequence (
name VARCHAR(100),
value BIGINT ) ;
INSERT INTO noas_exchange_sequence (name, value)
VALUES
('emc_entry_seq', 1 ) ;
Nous vous rappelons que le processus de création de séquence dépend du SGBDR utilisée. Consultez la documentation pour plus dinformation.
Pour effectuer les flux utilisons les mécanismes de persistances du framework. Pour mettre en relation la classe métier « EmcMessageEntity » et la table « emc_entry », utilisons un « proxy ». Ce « proxy », qui vous permettra de contrôler le transfert des objets. Il doit dériver de la classe « noas.exchange.NoasExchangeProxy ». Le framework fournir une variante, « noas.exchange.NoasExchangeProxyWizard », basé sur un fichier de description XML.Utilisons ce dernier pour plus daisance.
Vous devez rédiger un fichier de description pour chaque objet métier. La syntaxe est intuitive hors mis quelques éléments que nous allons préciser.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE exchange-description PUBLIC "-//Noas PHP, The Framework.//DTD Exchange Description 1.0//FR" "http://noas.sourceforge.net/dtds/noas-exchange_1_0.dtd">
<exchange-description>
<entity>EmcMessageEntity</entity>
<exchange>emc_entry</exchange>
<code>EMC_ENTRY</code>
<lazy>true</lazy>
<desc>false</desc>
<field>
<type>INTEGER</type>
<code>EMC_MESSAGE_ENTRYID</code>
<property>entryId</property>
<exchange>entry_id</exchange>
<size>10</size>
<notnull>true</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
<primary>true</primary>
<sequence>emc_entry_seq</sequence>
</field>
<field>
<type>STRING</type>
<code>EMC_MESSAGE_SURNAME</code>
<property>surname</property>
<exchange>surname</exchange>
<size>150</size>
<notnull>false</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>STRING</type>
<code>EMC_MESSAGE_FIRSTNAME</code>
<property>firstname</property>
<exchange>firstname</exchange>
<size>120</size>
<notnull>false</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>STRING</type>
<code>EMC_MESSAGE_EMAIL</code>
<property>email</property>
<exchange>email</exchange>
<size>60</size>
<notnull>true</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>STRING</type>
<code>EMC_MESSAGE_SUBJECT</code>
<property>subject</property>
<exchange>subject</exchange>
<size>200</size>
<notnull>true</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>TEXT</type>
<code>EMC_MESSAGE_MESSAGE</code>
<property>message</property>
<exchange>message</exchange>
<size>1024</size>
<notnull>true</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>TEXT</type>
<code>EMC_MESSAGE_RESPONSE</code>
<property>response</property>
<exchange>response</exchange>
<size>1024</size>
<notnull>false</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>INTEGER</type>
<code>EMC_MESSAGE_SERVICE</code>
<property>service</property>
<exchange>service</exchange>
<size>10</size>
<notnull>true</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>TIMESTAMP</type>
<code>EMC_MESSAGE_DATE_REGISTER</code>
<property>dateRegister</property>
<exchange>date_register</exchange>
<notnull>true</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
<field>
<type>TIMESTAMP</type>
<code>EMC_MESSAGE_DATE_REGISTER</code>
<property>dateSender</property>
<exchange>date_sender</exchange>
<notnull>false</notnull>
<readonly>true</readonly>
<writeonly>true</writeonly>
</field>
</exchange-description>
Lélément « <type/> » correspond au type du champ dont les valeurs possibles sont "VERSION", "INTEGER", "NUMERIC", "STRING", "TEXT", "BLOB", "BOOLEAN", "TIMESTAMP".
Lélément « <code/> » sert à mieux distinguer les champs et peut être utilisé comme identifiant de libellé GUI.
Lélément « <property/> » correspond à la propriété de classe associée.
Lélément « < exchange /> » correspond à la colonne de table associée.
Les éléments« < readonly /> » et « < writeonly /> » correspondent aux sens décriture autorisés.
Lélément « < sequence /> » correspond à la séquence numérique à utiliser pour incrémenter automatiquement la valeur du champ.
Les fichiers de description ne se limite pas quaux simples champs. Vous pouvez également déclarer des agrégats ou des références qui seront gérées automatiquement ( mise à jour et suppression en cascades) en utilisant les éléments « <aggregate/> » et « <reference/>».
Notre proxy ne fera pas grand chose, si ce nest que ce référencer au prés du manageur et définir la date de création.
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcMessageEntityProxy.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.exchange.NoasExchangeProxyWizard");
Noas::import("emc.business.EmcMessageEntity");
class EmcMessageEntityProxy extends NoasExchangeProxyWizard {
function __construct() {
parent::__construct(dirname(__FILE__)
.NOAS_SEPARATOR."EmcMessageEntity.xml");
}
public function onCreate(NoasExchangeContext $_context, $_businessObject) {
parent::onCreate($_context, $_businessObject);
$_businessObject->setDateRegister(NoasTimestamp::getTimestamp()) ;
}
}
NoasExchangeManager::setProxy("EmcMessageEntity"
,"EmcMessageEntityProxy");
?>
Utilisons une transaction sur la référence « demo » pour effectuer lenregistrement en base de données dans lévénement « save ».
Importer la définition de la transaction et du proxy dans la classe « EmcEditPage ».
Noas::import("noas.exchange.NoasExchangeTransaction");
Noas::import("emc.business.EmcMessageEntityProxy");
Vous devez modifier un temps soit peu la méthode « createBusinessObject() ». pour être en accord avec notre nouvelle logique.
protected function createBusinessObject(){
$newBusinessObject = new EmcMessageEntity();
$transaction = new NoasExchangeTransaction("demo");
$transaction->open();
$transaction->beginTransaction(NOAS_SERIALIZABLE);
$transaction->create($newBusinessObject);
$transaction->commit();
$transaction->close();
return $newBusinessObject;
}
La modification apportée va nous permettre dinitialiser correctement lobjet et de ne pas tenter dinsérer des instances avec des identifiant nulles.
public function saveEvent(){
$report = new NoasMessage();
self::checkEmail($report, "EMC_MESSAGE_EMAIL"
, $this->getBusinessObject()->getEmail());
if($report->hasErrorMessage()){
self::getRequest()->getMessage()->addMessage($report);
} else {
$transaction = new NoasExchangeTransaction("demo");
$transaction->open();
$transaction->beginTransaction();
try{
if($transaction->exist($this->getBusinessObject())){
$transaction->update($this->getBusinessObject());
} else {
$transaction->save($this->getBusinessObject());
}
$transaction->commit();
} catch(Exception $ex){
try { $transaction->rollback(); }catch (Exception $ex){ }
Noas::log($ex);
}
$transaction->close();
}
}
Pour une réelle application soyer plus rigoureux sur la gestion des exceptions. Les exceptions renvoyées par la couche de persistance sont assez riches pour réagire finement selon les cas. Penser également à renvoyer un message de confirmation pour les actions significatives réussies. Vous pouvez gagner en précision, au niveau de lharmonisation des contraintes, en utilisant les tagues de la librairie « noas.web.tag.exchange ». Ses champs de formulaire vont directement utiliser les contraintes définis par les proxys. Vous naurez donc plus besoin de préciser la taille maximale des champs par exemple ou encore sil ne doit pas être nul.
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_MESSAGE_SURNAME"/> :
</td>
<td>
<exchange:textfield model="businessObject" property="surname" size="20"/>
</td>
</tr>
Il existe différent moyen de naviguer sur les pages de votre application. Le moyen le plus simple, mais complètement hors gamme et qui ne doit servir quen cas dextrême nécessité, est de placer directement les URL dans les templates. Une autre façon de procéder est de définir un événement qui va effectuer un « forward » sur un contexte. Sachez que dans ce cas, lobjet requête nest pas réinitialiser. Le nombre de forward nest pas limité. Utilisions cette dernière méthode pour accéder au formulaire de message depuis le contexte « EmcHomePage »
public function goToMessageEditEvent(){
self::getRequest()->forward("emc.context.EmcEditPage");
}
Vous pouvez transmettre plusieurs informations à un contexte en procédant ainsi ( un objet à modifier, un événement, etc.). Si cela nest pas le cas, utilisez plutôt la tague « <:forward/> » depuis la template, elle effectue exactement le même travail.
<html:forward page="emc.context.EmcEditPage">
<noas:resource gui="EMC_BOOK"/>
</html:forward>
Si vous souhaitez utiliser les URL plus évoluées, ce qui peut arriver si vous devez en créer dynamiquement, vous devez utiliser un mapping. Cela vous permet de changer le contenu dune URL sans avoir à retoucher toutes templates. Voici le même exemple en utilisant les URL.
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcHomePage.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.web.context.NoasPageDeviceContext");
class EmcHomePage extends NoasPageDeviceContext {
function __construct() {
parent::__construct("home.tpl"
,"php/home".NOAS_PHP_EXTENSION);
$this->setInvalidPage("php/home".NOAS_PHP_EXTENSION);
$this->URL("emc.context.EmcEditPage"
, NoasURL::create("php/edit".NOAS_PHP_EXTENSION));
}
}
?>
<html:redirect page="emc.context.EmcEditPage">
<noas:resource gui="EMC_BOOK"/>
</html:redirect>
Noas PHP se veut « intégral », par conséquent il se devait dimplémenter un mécanisme dauthentification. Le principe est simple et pas très nouveau, chaque session dispose dun utilisateur qui lui-même possède un nom didentification et des droits. Son initialisation et leurs définitions sont libres, ce qui permet dimaginez une gestion des droits les plus complexe. Le framework dispose dune implémentation rudimentaire, par rapport à ce qui être réalisé en la matière, basé sur XML. Pour un site avec plusieurs utilisateurs, il est préférable dutiliser des données stockées en base.
Notre exemple est simple et la classe « noas.xml.user.NoasXmlRemoteUser » suffit amplement. Nous allons considérer quun utilisateur peut consulter les messages dun service sil possède le droit égale au code du service. Les autres actions seront soumises aux droit « UPDATE », « DELETE ». Pour la démo créez un « administrateur » et des « clients ».
Prenez soins de le protéger le répertoire « NOAS-INF » pour un usage une production. Créez le fichier de nom arbitraire « users.security.xml ».
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE user-description PUBLIC "-//Noas PHP, The Framework.//DTD User Description 1.0//FR" "http://noas.sourceforge.net/dtds/noas-user_1_0.dtd">
<user-description>
<user>
<name>admin</name>
<login>admin</login>
<password>adminpwd</password>
<email>admin@admin.net</email>
<profile>
<right>10</right>
<right>20</right>
<right>30</right>
<right>40</right>
<right>50</right>
<right>60</right>
<right>UPDATE</right>
<right>DELETE</right>
</profile>
</user>
<user>
<name>client1</name>
<login>client1</login>
<password>client1pwd</password>
<email>client1@client.com</email>
<profile>
<right>10</right>
<right>20</right>
<right>30</right>
</profile>
</user>
<user>
<name>client2</name>
<login>client2</login>
<password>client2pwd</password>
<email>client2@client.com</email>
<profile>
<right>40</right>
<right>50</right>
<right>60</right>
</profile>
</user>
</user-description>
A présent, nous nous intéressons à la page de connexion à la partie « back office » de lapplication.
<?php
//////////////////////////////////////////////////////////////////////
// File : login.php
/////////////////////////////////////////////////////////////////////
include_once("../noas-emc-conf.inc");
Noas::loadPageContext("emc.context.EmcLoginPage", false);
?>
<%--
//////////////////////////////////////////////////////////////////////
// File : login.tpl
/////////////////////////////////////////////////////////////////////
--%>
<%@taglib uri="noas.web.tag" prefix="noas"%>
<%@taglib uri="noas.web.tag.html" prefix="html"%>
<%@taglib uri="noas.web.tag.logic" prefix="logic"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><%@include file="header.tpl"%></head>
<body>
<h1><noas:resource gui="EMC_TITLE"/></h1>
<hr style="width: 100%; height: 2px;">
<logic:ifError key="EMC_LOGIN_ERROR">
<table cellspacing="1" cellpadding="0" class="list">
<tr>
<td style="color: red;">
<html:errorMessage key="EMC_LOGIN_ERROR"/>
</td>
</tr>
</table>
</logic:ifError>
<html:form name="login">
<table cellspacing="1" cellpadding="0" class="list">
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_USER_LOGIN"/> :
<logic:ifError key="EMC_USER_LOGIN">
<span title="<html:errorMessage key="EMC_USER_LOGIN"/>"
style="color: red; cursor: hand;" >*</span>
</logic:ifError>
</td>
<td>
<html:textfield model="userCriterion" property="login"
size="20" maxlength="200"
rules="NOTNULL_RULES" errorKey="EMC_USER_LOGIN"/>
</td>
</tr>
<tr>
<td style="vertical-align:middle;" width="50%">
<noas:resource gui="EMC_USER_PWD"/> :
<logic:ifError key="EMC_USER_PWD">
<span title="<html:errorMessage key="EMC_USER_PWD"/>"
style="color: red; cursor: hand;" >*</span>
</logic:ifError>
</td>
<td>
<html:password model="userCriterion" property="password"
size="20"
rules="NOTNULL_RULES" errorKey="EMC_USER_PWD"/>
</td>
</tr>
<tr>
<td style="vertical-align:middle;" colspan="2">
<noas:resource gui="EMC_MESSAGE_SERVICE"/> :
<html:combobox property="userService" enum="serviceEnum" />
</td>
</tr>
<tr>
<td style="text-align: center; vertical-align:bottom;" colspan="2">
<html:submit gui="EMC_CONNECT_BUTTON" event="connect"/>
</td>
</tr>
</table>
</html:form>
</body>
</html>
Vous devez toujours importer la définition de la classe « user » dans votre session.
Noas::import("noas.xml.user.NoasXmlRemoteUser");
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcLoginPage.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.web.context.NoasPageDeviceContext");
class EmcLoginPage extends NoasPageDeviceContext {
private $userCriterion;
private $userService;
function __construct() {
parent::__construct("login.tpl"
,"php/login".NOAS_PHP_EXTENSION);
$this->setInvalidPage("php/login".NOAS_PHP_EXTENSION);
$this->userCriterion = new NoasXmlRemoteUser();
}
public function getUserCriterion(){
return $this->userCriterion;
}
public function setUserCriterion($_userCriterion){
$this->userCriterion = $_userCriterion;
}
public function getUserService(){
return $this->userService;
}
public function setUserService($_userService){
$this->userService = $_userService;
}
public function connectEvent(){
$filename = NOAS_APPLICATION_HOME.NOAS_SEPARATOR."NOAS-INF"
.NOAS_SEPARATOR."users.security.xml";
$userFound = NoasXmlRemoteUser::find($filename, $this->getUserCriterion());
if(!empty($userFound)){
$userFound->check();
if($userFound->hasRight($this->getUserService())){
self::getSession()->setRemoteUser($userFound);
self::getSession()->setParameter("SERVICE", $this->getUserService());
} else {
$userFound->uncheck();
$error = new NoasMessage();
$error->addErrorMessage("EMC_LOGIN_ERROR"
, array("NOAS_INPUT_ERROR"=>"UNKOWN_SERVICE"));
self::getRequest()->getMessage()->addMessage($error);
}
} else {
$error = new NoasMessage();
$this->getUserCriterion()->setPassword(null);
$userFound = NoasXmlRemoteUser::find($filename, $this->getUserCriterion());
if(empty($userFound)){
$error->addErrorMessage("EMC_LOGIN_ERROR"
, array("NOAS_INPUT_ERROR"=>"UNKOWN_USER"));
}else{
$error->addErrorMessage("EMC_LOGIN_ERROR"
, array("NOAS_INPUT_ERROR"=>"INVALID_PWD_ERROR"));
}
self::getRequest()->getMessage()->addMessage($error);
}
}
}
?>
Lévenement « connect » effectue les contrôles nécessaire à lauthentification et sauvegarde le service selectionné. Nous rappelons que par défaut, les contexts sont avec état. Cest pour cette raison que nous navons pas eu à intervenir pour conserver les données saissies par lutilisateur même àprés une erreur.
Nous avons vu ultérieurement que nous pouvions factoriser le contenu des template en utilisant linclusion statique. Le framework vous permet daller plus loin en utilisant le principe des contextes composants. Supposons quau-delà de posséder des éléments graphiques commun, certaines portions de vos templates décrive un comportement spécifique qui nécessite un contexte particulier. Deus solutions se pose à vous. Vous pouvez faire dériver tous vos contextes de page dun contexte unique implémentant toutes les fonctionnalités souhaitées. Dans ce cas précis les inclusions statiques suffisent. Cependant vous restreignez considérablement la réutilisation de votre production. De plus vous risquerez dalourdir un contexte de page qui nutilisera peut être jamais ces fonctionnalités. Réservez donc son usage à de petites fonctionnalités propres à un seul projet.
Une autre alternative est de développer un composant utilisable par nimporte quel contexte, donc réutilisable, qui sera chargé dimplémenter ces fonctionnalités. Dans le cas où ce composant dispose dune template, nous parlons d« inclusion dynamique ». Ce type de procédé à permis de fournir avec le framework un composant capable de prendre en charge les listes déléments que nous utiliserons pour créer le contexte de page qui affichera la liste des messages.
<?php
//////////////////////////////////////////////////////////////////////
// File : list.php
/////////////////////////////////////////////////////////////////////
include_once("../noas-emc-conf.inc");
Noas::loadPageContext("emc.context.EmcListPage", true);
?>
Cette fois ci nous avons activé le contrôle de la navigation pour protéger la consultation de la liste des messages. Nous prenons donc soins de définir la page de connexion comme retour dinvalidité avec un teste adapté dans la méthode « isValid() ».
Un composant ne se créé pas comme un simple objet. Pour gérer la sérialisation (état des contextes) ou encore le contrôle de la propagation des événements, le framework à besoin davoir la main sur le cycle vie complet des contextes. Vous vous devez donc de détruire toutes les références sur dautres contextes ou composants au risque den conserver des copies corrompues. Le choix de le créer en session, donc avec état, ou en requête, sans état, se fait au travers de factory utilisée.
<?php
//////////////////////////////////////////////////////////////////////
// File : EmcListPage.class.php
/////////////////////////////////////////////////////////////////////
Noas::import("noas.web.context.NoasPageDeviceContext");
Noas::import("noas.web.context.NoasListDeviceContext");
Noas::import("noas.exchange.NoasExchangeTransaction");
Noas::import("emc.business.EmcMessageEntityProxy");
class EmcListPage extends NoasPageDeviceContext {
private $resultComponent;
function __construct() {
parent::__construct("list.tpl"
,"php/list".NOAS_PHP_EXTENSION);
$this->setInvalidPage("php/login".NOAS_PHP_EXTENSION);
}
public function isValidate() {
$user = self::getSession()->getRemoteUser();
return isset($user)
&& $user->isAuthenticated()
&& self::getSession()->hasParameter("service");
}
public function serialize() {
parent::serialize();
$this->resultComponent = null;
}
public function getResultComponent( ) {
if(empty($this->resultComponent)){
$this->resultComponent = self::getSession()->getDC($this,
"resultComponent",
"noas.web.context.NoasListDeviceContext");
$this->resultComponent->setTemplate("result.tpl");
$this->resultComponent->setRange(10);
}
return $this->resultComponent;
}
}
<%--
//////////////////////////////////////////////////////////////////////
// File : list.tpl
/////////////////////////////////////////////////////////////////////
--%>
<%@taglib uri="noas.web.tag" prefix="noas"%>
<%@taglib uri="noas.web.tag.html" prefix="html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><%@include file="header.tpl"%></head>
<body>
<h1><noas:resource gui="EMC_TITLE"/></h1>
<hr style="width: 100%; height: 2px;">
<html:component name="resultComponent"/>
</body>
</html>
Pour rediriger lutilisateur, après lauthentification, vers la liste des messages nous devons modifier la méthode « connectEvent() ».
self::getSession()->setRemoteUser($userFound);
self::getSession()->setParameter("service"
, $this->getUserService());
self::getRequest()->forward("emc.context.EmcListPage"
,"showMessageList");
La méthode « showMessageListEvent() » va initialiser la lise des messages. Rajouter là dans le contexte « EmcListePage ».
public function showMessageListEvent(){
$messageList = null;
$criterion = new EmcMessageEntity();
$transaction = new NoasExchangeTransaction("demo");
$transaction->open( );
try{
$criterion->setService(self::getSession()->getParameter("service"));
$messageList = $transaction->find($criterion);
} catch(Exception $ex){
Noas::log($ex);
$messageList = new NoasVector();
}
$transaction->close();
$this->getResultComponent()->setElements($messageList);
}
Nous prévoyons également lévénement « selectMessage » qui va transmettre lobjet métier sélectionné à la page « EmcEditPage » pour le modifier.
public function selectMessageEvent(){
self::getRequest()->forward("emc.context.EmcEditPage"
, "editMessage"
, $this->getResultComponent()->getSelected());
}
Enfin nous récupérons la valeur transmise dans lévénement « editMessage » de la page « EmcEditPage ».
public function editMessageEvent(){
$businessObject = self::getRequest()->getForwardData();
if(isset($businessObject)){
$businessObject->setEditable(true);
}
$this->setBusinessObject($businessObject);
}
Il existe plusieurs tagues pour la gestion des listes. Elles sont essentiellement contenues dans la librairie « noas.web.tag.list ». Pour notre exemple nous allons juste utiliser litération sur lensemble des éléments, le trie automatique et la sélection.
<%--
//////////////////////////////////////////////////////////////////////
// File : result.tpl
/////////////////////////////////////////////////////////////////////
--%>
<%@taglib uri="noas.web.tag" prefix="noas"%>
<%@taglib uri="noas.web.tag.html" prefix="html"%>
<%@taglib uri="noas.web.tag.logic" prefix="logic"%>
<%@taglib uri="noas.web.tag.list" prefix="list"%>
<table cellspacing="2" cellpadding="4" border="1" class="list">
<tr>
<td width="240">
<list:iteratorHeader property="subject">
<noas:resource gui="EMC_MESSAGE_SUBJECT"/>
</list:iteratorHeader>
</td>
<td>
<list:iteratorHeader property="email">
<noas:resource gui="EMC_MESSAGE_EMAIL"/>
</list:iteratorHeader>
</td>
<td>
<list:iteratorHeader property="dateRegister">
<noas:resource gui="EMC_MESSAGE_DATE_REGISTER"/>
</list:iteratorHeader>
</td>
</tr>
<list:iterator>
<tr <logic:else model="currentElement" condition="hasResponse">
style="color: red;"
</logic:else>
>
<td>
<list:iteratorHref event="selectMessage">
<html:value model="currentElement" property="subject"/>
</list:iteratorHref>
</td>
<td>
<html:value model="currentElement" property="email"/>
</td>
<td>
<html:value model="currentElement" property="dateRegister"/>
</td>
</tr>
</list:iterator>
</table>
Voilà nous avons finit ce petit tour dhorizon du framework qui nous à permis de réaliser une application simple mais très instructive. Mais vous êtes encore loin du compte de létendu de ces fonctionnalités. Nous aurons, je lespère, certainement loccasion dapprofondir certains aspect prochainement. En attendant, traquez sur la toile les extensions/composants qui verront le jour dans un premier temps dans les catégories intégration, collaboration, client riche, CMS, outils RAD.
http://noas.sourceforge.net