4. Un'applicazione illustrativa
Proponiamo di illustrare il metodo precedente con un esempio di calcolo delle imposte.
4.1. Il problema
Il nostro obiettivo è scrivere un programma per calcolare l'imposta di un contribuente. Consideriamo il caso semplificato di un contribuente che deve dichiarare solo il proprio stipendio:
- Calcoliamo il numero di scaglioni fiscali per il dipendente: nbParts = nbEnfants / 2 + 1 se non sposato, nbEnfants / 2 + 2 se sposato, dove nbEnfants è il numero di figli. Il numero di scaglioni viene aumentato di 0,5 se ci sono tre o più figli.
- Calcoliamo il suo reddito imponibile R = 0,72 * S, dove S è il suo stipendio annuale
- Calcoliamo il loro coefficiente familiare Q = R/N
- Calcoliamo la sua imposta I sulla base dei seguenti dati
| Ogni riga ha 3 campi: limit, coeffR e coeffN. Per calcolare l'imposta I, trova la prima riga in cui QF <= limit. Ad esempio, se QF = 30000, la riga trovata è: 31810 0,2 3309,5. L'imposta I è quindi pari a 0,2*R - 3309,5*nbParts. Se QF è tale che la condizione QF <= limite non è mai soddisfatta, vengono utilizzati i coefficienti dell'ultima riga: 0 0,65 49062, il che dà l'imposta I = 0,65*R - 49062*nbParts. |
4.2. Il database
I dati precedenti sono memorizzati in un database MySQL denominato dbimpots. L'utente seldbimpots con password mdpseldbimpots dispone di accesso in sola lettura ai contenuti del database. Il database contiene una singola tabella denominata impots con la seguente struttura:

Il suo contenuto è il seguente:

4.3. L'architettura MVC dell'applicazione
L'applicazione avrà la seguente architettura MVC:
![]() |
- Il controller main.php sarà il controller generico descritto sopra
- La richiesta del client viene inviata al controller sotto forma di query del tipo main.php?action=xx. Il valore del parametro action determina quale script del blocco ACTIONS eseguire. Lo script dell'azione eseguita restituisce al controller una variabile che indica lo stato in cui deve essere posta l'applicazione web. Grazie a questo stato, il controller attiverà uno dei generatori di vista per inviare la risposta al client.
- impots-data.php è la classe responsabile di fornire al controller i dati di cui ha bisogno
- impots-calcul.php è la classe di logica di business che calcola l'imposta
4.4. La classe di accesso ai dati
La classe di accesso ai dati è progettata per nascondere la fonte dei dati all'applicazione web. La sua interfaccia include un metodo getData che restituisce i tre array di dati necessari per calcolare l'imposta. Nel nostro esempio, i dati vengono recuperati da un database MySQL. Per rendere la classe indipendente dal tipo effettivo di DBMS, useremo la libreria pear::DB descritta nell'appendice. Il codice della classe è il seguente:
<?php
// libraries
require_once 'DB.php';
class impots_data{
// data source access class DBIMPOTS
// attributes
var $sDSN; // the connection chain
var $sDatabase; // base name
var $oDB; // base connection
var $aErreurs; // error list
var $oRésultats; // query result
var $connecté; // boolean indicating whether or not you are connected to the database
var $sQuery ; // the last query executed
// manufacturer
function impots_data($dDSN){
// $dDSN: dictionary defining the link to be established
// $dDSN['sgbd']: type of SGBD to be connected to
// $dDSN['host']: name of the host machine hosting it
// $dDSN['database']: name of the database to be connected to
// $dDSN['user']: a bse user
// $dDSN['mdp']: its password
// creates in $oDB a connection to the database defined by $dDSN as $dDSN['user']
// if the connection is successful
// sets $sDSN to the database connection string
// sets $sDataBase to the name of the database to which you are connecting
// sets $connecté to true
// if the connection fails
// puts the appropriate error msg in the $aErreurs list
// closes the connection if necessary
// sets $connecté to false
// raz error list
$this->aErreurs=array();
// create a connection to the $sDSN database
$this->sDSN=$dDSN["sgbd"]."://".$dDSN["user"].":".$dDSN["mdp"]."@".$dDSN["host"]."/".$dDSN["database"];
$this->sDatabase=$dDSN["database"];
$this->connect();
// connected?
if( ! $this->connecté) return;
// the connection was successful
$this->connecté=TRUE;
}//manufacturer
// ------------------------------------------------------------------
function connect(){
// (re)connecting to the base
// raz error list
$this->aErreurs=array();
// create a connection to the $sDSN database
$this->oDB=DB::connect($this->sDSN,true);
// mistake?
if(DB::iserror($this->oDB)){
// on note l'erreur
$this->aErreurs[]="Echec de la connexion à la base [".$this->sDatabase."] : [".$this->oDB->getMessage()."]";
// connection failed
$this->connecté=FALSE;
// end
return;
}
// we're connected
$this->connecté=TRUE;
}//connect
// ------------------------------------------------------------------
function disconnect(){
// if connected, closes the connection to the $sDSN database
if($this->connecté){
$this->oDB->disconnect();
// we are disconnected
$this->connecté=FALSE;
}//if
}//disconnect
// -------------------------------------------------------------------
function execute($sQuery){
// $sQuery: query to be executed
// memorize the request
$this->sQuery=$sQuery;
// are we connected?
if(! $this->connecté){
// on note l'erreur
$this->aErreurs[]="Pas de connexion existante à la base [$this->sDatabase]";
// end
return;
}//if
// query execution
$this->oRésultats=$this->oDB->query($sQuery);
// mistake?
if(DB::iserror($this->oRésultats)){
// on note l'erreur
$this->aErreurs[]="Echec de la requête [$sQuery] : [".$this->oRésultats->getMessage()."]";
// return
return;
}//if
}//execute
// ------------------------------------------------------------------
function getData(){
// we retrieve the 3 limit data series, coeffr, coeffn
$this->execute('select limites, coeffR, coeffN from impots');
// mistakes?
if(count($this->aErreurs)!=0) return array();
// browse the result of the select
while ($ligne = $this->oRésultats->fetchRow(DB_FETCHMODE_ASSOC)) {
$limites[]=$ligne['limites'];
$coeffr[]=$ligne['coeffR'];
$coeffn[]=$ligne['coeffN'];
}//while
return array($limites,$coeffr,$coeffn);
}//getDataImpots
}//class
?>
Un programma di test potrebbe essere simile a questo:
<?php
// library
require_once "c-impots-data.php";
require_once "DB.php";
// testing the impots-data class
ini_set('track_errors','on');
ini_set('display_errors','on');
// dbimpots base configuration
$dDSN=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
// opening of the session
$oImpots=new impots_data($dDSN);
// mistakes?
if(checkErreurs($oImpots)){
exit(0);
}
// follow-up
echo "Connecté à la base...\n";
// recovery of limit data, coeffr, coeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// mistakes?
if( ! checkErreurs($oImpots)){
// content
echo "données : \n";
for($i=0;$i<count($limites);$i++){
echo "[$limites[$i],$coeffr[$i],$coeffn[$i]]\n";
}//for
}//if
// disconnect
$oImpots->disconnect();
// follow-up
echo "Déconnecté de la base...\n";
// end
exit(0);
// ----------------------------------
function checkErreurs(&$oImpots){
// mistakes?
if(count($oImpots->aErreurs)!=0){
// display
for($i=0;$i<count($oImpots->aErreurs);$i++){
echo $oImpots->aErreurs[$i]."\n";
}//for
// errors
return true;
}//if
// no errors
return false;
}//checkErreurs
?>
L'esecuzione di questo programma di test produce i seguenti risultati:
Connecté à la base...
données :
[12620,0,0]
[13190,0.05,631]
[15640,0.1,1290.5]
[24740,0.15,2072.5]
[31810,0.2,3309.5]
[39970,0.25,4900]
[48360,0.3,6898]
[55790,0.35,9316.5]
[92970,0.4,12106]
[127860,0.45,16754]
[151250,0.5,23147.5]
[172040,0.55,30710]
[195000,0.6,39312]
[0,0.65,49062]
Déconnecté de la base...
4.5. La classe di calcolo delle imposte
Questa classe viene utilizzata per calcolare l'imposta di un contribuente. I dati necessari per questo calcolo vengono forniti al suo costruttore. Successivamente, calcola l'imposta corrispondente. Il codice della classe è il seguente:
<?php
class impots_calcul{
// tax calculation class
// manufacturer
function impots_calcul(&$perso,&$data){
// $perso: dictionary with the following keys
// children : number of children
// salary: annual salary
// married: Boolean indicating whether the taxpayer is married or not
// impot(s): tax payable calculated by this manufacturer
// $data: dictionary with the following keys
// limits: tranche limits table
// coeffr: income coefficients table
// coefficients tablaeu of coefficients of number of shares
// the 3 arrays have the same number of elements
// calculating the number of shares
if($perso['marié'])
$nbParts=$perso['enfants']/2+2;
else $nbParts=$perso['enfants']/2+1;
if ($perso['enfants']>=3) $nbParts+=0.5;
// taxable income
$revenu=0.72*$perso['salaire'];
// family quotient
$QF=$revenu/$nbParts;
// search for tax bracket corresponding to QF
$nbTranches=count($data['limites']);
$i=0;
while($i<$nbTranches-2 && $QF>$data['limites'][$i]) $i++;
// tax
$perso['impot']=floor($data['coeffr'][$i]*$revenu-$data['coeffn'][$i]*$nbParts);
}//manufacturer
}//class
?>
Un programma di test potrebbe essere simile a questo:
<?php
// library
require_once "c-impots-data.php";
require_once "c-impots-calcul.php";
// dbimpots base configuration
$dDSN=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
// opening of the session
$oImpots=new impots_data($dDSN);
// mistakes?
if(checkErreurs($oImpots)){
exit(0);
}
// follow-up
echo "Connecté à la base...\n";
// recovery of limit data, coeffr, coeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// mistakes?
if(checkErreurs($oImpots)){
exit(0);
}
// we disconnect
$oImpots->disconnect();
// follow-up
echo "Déconnecté de la base...\n";
// tax calculation
$dData=array('limites'=>&$limites,'coeffr'=>&$coeffr,'coeffn'=>&$coeffn);
$dPerso=array('enfants'=>2,'salaire'=>200000,'marié'=>true,'impot'=>0);
new impots_calcul($dPerso,$dData);
dump($dPerso);
$dPerso=array('enfants'=>3,'salaire'=>200000,'marié'=>false,'impot'=>0);
new impots_calcul($dPerso,$dData);
dump($dPerso);
$dPerso=array('enfants'=>3,'salaire'=>20000,'marié'=>true,'impot'=>0);
new impots_calcul($dPerso,$dData);
dump($dPerso);
$dPerso=array('enfants'=>3,'salaire'=>2000000,'marié'=>true,'impot'=>0);
new impots_calcul($dPerso,$dData);
dump($dPerso);
// end
exit(0);
// ----------------------------------
function checkErreurs(&$oImpots){
// mistakes?
if(count($oImpots->aErreurs)!=0){
// display
for($i=0;$i<count($oImpots->aErreurs);$i++){
echo $oImpots->aErreurs[$i]."\n";
}//for
// errors
return true;
}//if
// no errors
return false;
}//checkErreurs
?>
L'esecuzione di questo programma di test produce i seguenti risultati:
Connecté à la base...
Déconnecté de la base...
[enfants,2] [salaire,200000] [marié,1] [impot,22506]
[enfants,3] [salaire,200000] [marié,] [impot,22506]
[enfants,3] [salaire,20000] [marié,1] [impot,0]
[enfants,3] [salaire,2000000] [marié,1] [impot,706752]
4.6. Come funziona l'applicazione
Quando si avvia il calcolatore fiscale online, appare la seguente vista [v-form]:
![]() |
L'utente compila i campi e richiede il calcolo delle imposte:
![]() |
Si noti che il modulo viene rigenerato nello stato in cui l'utente lo ha inviato e mostra anche l'importo dell'imposta dovuta. L'utente potrebbe commettere errori nell'inserimento dei dati. Questi vengono segnalati da una pagina di errore, che chiameremo vista [v-errors].
![]() |
![]() |
Il link [Torna al modulo di inserimento dati] consente all'utente di tornare al modulo così come lo ha inviato.
![]() |
Infine, il pulsante [Cancella modulo] riporta il modulo allo stato iniziale, ovvero a come l'utente lo ha ricevuto durante la richiesta iniziale.
4.7. Torniamo all'architettura MVC dell'applicazione
L'applicazione presenta la seguente architettura MVC:
![]() |
Abbiamo appena descritto le due classi impots-data.php e impots-calcul.php. Descriveremo ora gli altri elementi dell'architettura.
4.8. Il controller dell'applicazione
Il controller main.php dell'applicazione è quello descritto nella prima parte di questo capitolo. Si tratta di un controller generico indipendente dall'applicazione.
<?php
// generic controller
// configurable reading
include 'config.php';
// including libraries
for($i=0;$i<count($dConfig['includes']);$i++){
include($dConfig['includes'][$i]);
}//for
// start or resume session
session_start();
$dSession=$_SESSION["session"];
if($dSession) $dSession=unserialize($dSession);
// retrieve the action to be taken
$sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
$sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";
// is the sequence of actions normal?
if( ! enchainementOK($dConfig,$dSession,$sAction)){
// abnormal sequence
$sAction='enchainementinvalide';
}//if
// share processing
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// send response(view) to customer
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
// end of script - we shouldn't get there unless there's a bug
trace ("Erreur de configuration.");
trace("Action=[$sAction]");
trace("scriptAction=[$scriptAction]");
trace("Etat=[$sEtat]");
trace("scriptVue=[$scriptVue]");
trace ("Vérifiez que les script existent et que le script [$scriptVue] se termine par l'appel à finSession.");
exit(0);
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: configuration dictionary
// $dSession: dictionary containing session info
// $dReponse: the dictionary of arguments for the response page
// session registration
if(isset($dSession)){
// put the query parameters in the session
$dSession['requete']=strtolower($_SERVER['REQUEST_METHOD'])=='get' ? $_GET :
strtolower($_SERVER['REQUEST_METHOD'])=='post' ? $_POST : array();
$_SESSION['session']=serialize($dSession);
session_write_close();
}else{
// no session
session_destroy();
}
// we present the answer
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// end of script
exit(0);
}//endsession
//--------------------------------------------------------------------
function enchainementOK(&$dConfig,&$dSession,$sAction){
// checks whether the current action is authorized with respect to the previous state
$etat=$dSession['etat']['principal'];
if(! isset($etat)) $etat='sansetat';
// check action
$actionsautorisees=$dConfig['etats'][$etat]['actionsautorisees'];
$autorise= ! isset($actionsautorisees) || in_array($sAction,$actionsautorisees);
return $autorise;
}
//--------------------------------------------------------------------
function dump($dInfos){
// displays an information dictionary
while(list($clé,$valeur)=each($dInfos)){
echo "[$clé,$valeur]<br>\n";
}//while
}//follow-up
//--------------------------------------------------------------------
function trace($msg){
echo $msg."<br>\n";
}//follow-up
?>
4.9. Azioni dell'applicazione web
Esistono quattro azioni:
- get:init: questa è l'azione attivata durante la richiesta iniziale al controller senza parametri. Visualizza la vista 'form' vuota.
- post:clearform: azione attivata dal pulsante [Cancella modulo]. Visualizza la vista [v-form] vuota.
- post:calculateTax: azione attivata dal pulsante [Calcola imposta]. Genera la vista [v-form] con l'importo dell'imposta dovuta oppure la vista [v-errors].
- get:returnform: azione attivata dal link [Torna al modulo di inserimento]. Visualizza la vista [v-form] precompilata con i dati errati.
Queste azioni sono configurate come segue nel file di configurazione:
<?php
…
// configuration of application actions
$dConfig['actions']['get:init']=array('url'=>'a-init.php');
$dConfig['actions']['post:calculerimpot']=array('url'=>'a-calculimpot.php');
$dConfig['actions']['get:retourformulaire']=array('url'=>'a-retourformulaire.php');
$dConfig['actions']['post:effacerformulaire']=array('url'=>'a-init.php');
$dConfig['actions']['enchainementinvalide']=array('url'=>'a-enchainementinvalide.php');
$dConfig['actions']['actionInvalide']=array('url'=>'a-actioninvalide.php');
Ogni azione è associata allo script responsabile della sua elaborazione. Ogni azione porterà l'applicazione web in uno stato definito dall'elemento $dSession['state']['main']. Questo stato è destinato ad essere salvato nella sessione. Inoltre, l'azione memorizza nel dizionario $dResponse le informazioni necessarie per visualizzare la vista associata al nuovo stato in cui si troverà l'applicazione.
4.10. Stati dell'applicazione web
Ce ne sono due:
[e-form]: state in which the different variants of the [v-form] view are displayed.
[e-errors]: state in which the [v-errors] view is displayed.
Le azioni consentite in questi stati sono le seguenti:
<?php
…
// application status configuration
$dConfig['etats']['formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
$dConfig['etats']['erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
$dConfig['etats']['sansetat']=array('actionsautorisees'=>array('get:init'));
In uno stato, le azioni consentite corrispondono agli URL di destinazione dei link o dei pulsanti [submit] nella vista associata a quello stato. Inoltre, l'azione 'get:init' è sempre consentita. Ciò permette all'utente di recuperare l'URL main.php dalla barra degli indirizzi del proprio browser e ricaricarlo indipendentemente dallo stato dell'applicazione. Si tratta di una sorta di reset 'manuale'. Lo stato 'sansetat' esiste solo all'avvio dell'applicazione.
Ogni stato dell'applicazione è associato a uno script responsabile della generazione della vista associata a quello stato:
- stato [e-form]: script e-formulaire.php
- stato [e-errors]: script e-errors.php
Lo stato [e-form] visualizzerà la vista [v-form] con alcune variazioni. Infatti, la vista [v-form] può essere visualizzata vuota, precompilata o con l'importo delle imposte. L'azione che porta l'applicazione nello stato [e-form] specifica lo stato principale dell'applicazione nella variabile $dSession['state']['main']. Il controller utilizza solo questa informazione. Nella nostra applicazione, l'azione che porta allo stato [e-form] aggiungerà ulteriori informazioni a $dSession['state']['secondary'], consentendo al generatore di risposta di sapere se generare un modulo vuoto, un modulo precompilato o un modulo con o senza l'importo dell'imposta. Avremmo potuto adottare un approccio diverso ipotizzando che ci fossero tre stati diversi e quindi tre generatori di vista da scrivere.
4.11. Il file di configurazione config.php dell'applicazione web
<?php
// php configuration
ini_set("register_globals","off");
ini_set("display_errors","off");
ini_set("expose_php","off");
// list of modules to be included
$dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');
// application controller
$dConfig['webapp']=array('titre'=>"Calculez votre impôt");
// aplication view configuration
$dConfig['vuesReponse']['modele1']=array('url'=>'m-reponse.php');
$dConfig['vuesReponse']['modele2']=array('url'=>'m-reponse2.php');
$dConfig['vues']['formulaire']=array('url'=>'v-formulaire.php');
$dConfig['vues']['erreurs']=array('url'=>'v-erreurs.php');
$dConfig['vues']['formulaire2']=array('url'=>'v-formulaire2.php');
$dConfig['vues']['erreurs2']=array('url'=>'v-erreurs2.php');
$dConfig['vues']['bandeau']=array('url'=>'v-bandeau.php');
$dConfig['vues']['menu']=array('url'=>'v-menu.php');
$dConfig['style']['url']='style1.css';
// configuration of application actions
$dConfig['actions']['get:init']=array('url'=>'a-init.php');
$dConfig['actions']['post:calculerimpot']=array('url'=>'a-calculimpot.php');
$dConfig['actions']['get:retourformulaire']=array('url'=>'a-retourformulaire.php');
$dConfig['actions']['post:effacerformulaire']=array('url'=>'a-init.php');
$dConfig['actions']['enchainementinvalide']=array('url'=>'a-enchainementinvalide.php');
$dConfig['actions']['actionInvalide']=array('url'=>'a-actioninvalide.php');
// application status configuration
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
$dConfig['etats']['sansetat']=array('actionsautorisees'=>array('get:init'));
// model application configuration
$dConfig["DSN"]=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
?>
4.12. Azioni delle applicazioni web
4.12.1. Funzionamento generale degli script di azione
- Uno script di azione viene chiamato dal controller in base al parametro action ricevuto dal client.
- Dopo l'esecuzione, lo script di azione deve comunicare al controller lo stato in cui collocare l'applicazione. Questo stato deve essere specificato in $dSession['etat']['principal'].
- Uno script di azione potrebbe voler memorizzare informazioni nella sessione. Lo fa inserendo queste informazioni nel dizionario $dSession, che viene automaticamente salvato nella sessione dal controller al termine del ciclo richiesta-risposta.
- Uno script di azione può contenere informazioni da trasmettere alle viste. Questo aspetto è indipendente dal controller. Si tratta dell'interfaccia tra azioni e viste, un'interfaccia specifica per ogni applicazione. Nell'esempio qui discusso, le azioni forniranno informazioni ai generatori di viste tramite un dizionario denominato $dResponse.
4.12.2. L'azione get:init
Questa è l'azione che genera il modulo vuoto. Il file di configurazione mostra che sarà gestita dallo script a-init.php:
Il codice dello script a-init.php è il seguente:
<?php
// the input form is displayed
$dSession['etat']=array('principal'=>'e-formulaire', 'secondaire'=>'init');
?>
Questo script imposta semplicemente lo stato in cui dovrebbe trovarsi l'applicazione — lo stato [e-form] — in $dSession['etat']['principal'], e fornisce una descrizione di questo stato in $dSession['etat']['secondaire']. Il file di configurazione ci mostra che il controller eseguirà lo script e-formulaire.php per generare la risposta al client.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Lo script e-formulaire.php genererà la vista [v-formulaire] nella sua variante [init], ovvero il modulo vuoto.
4.12.3. L'azione post:calculateTax
Questa è l'azione che calcola l'imposta in base ai dati inseriti nel modulo. Il file di configurazione specifica che lo script a-calculimpot.php gestirà questa azione:
Il codice dello script a-calculimpot.php è il seguente:
<?php
// tax calculation request
// we first check the validity of the parameters
$sOptMarie=$_POST['optmarie'];
if($sOptMarie!='oui' && $sOptMarie!='non'){
$erreurs[]="L'état marital [$sOptMarie] est erroné";
}
$sEnfants=trim($_POST['txtenfants']);
if(! preg_match('/^\d{1,3}$/',$sEnfants)){
$erreurs[]="Le nombre d'enfants [$sEnfants] est erroné";
}
$sSalaire=trim($_POST['txtsalaire']);
if(! preg_match('/^\d+$/',$sSalaire)){
$erreurs[]="Le salaire annuel [$sSalaire] est erroné";
}
// if there are mistakes, it's over
if(count($erreurs)!=0){
// preparing the error page
$dReponse['erreurs']=&$erreurs;
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'saisie');
return;
}//if
// the data entered is correct
// retrieve the data needed to calculate taxes
if(! $dSession['limites']){
// the data is not in the session
// we retrieve them from the data source
list($erreurs,$limites,$coeffr,$coeffn)=getData($dConfig['DSN']);
// if there are errors, the error page is displayed
if(count($erreurs)!=0){
// preparing the error page
$dReponse['erreurs']=&$erreurs;
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'database');
return;
}//if
// no errors - data put into session
$dSession['limites']=&$limites;
$dSession['coeffr']=&$coeffr;
$dSession['coeffn']=&$coeffn;
}//if
// here you have the data you need to calculate your taxes
// on calcule celui-ci
$dData=array('limites'=>&$dSession['limites'],
'coeffr'=>&$dSession['coeffr'],
'coeffn'=>&$dSession['coeffn']);
$dPerso=array('enfants'=>$sEnfants,'salaire'=>$sSalaire,'marié'=>($sOptMarie=='oui'),'impot'=>0);
new impots_calcul($dPerso,$dData);
// preparing the answer page
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'calculimpot');
$dReponse['impot']=$dPerso['impot'];
return;
//-----------------------------------------------------------------------
function getData($dDSN){
// connection to the data source defined by the $dDSN dictionary
$oImpots=new impots_data($dDSN);
if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
// recovery of limit data, coeffr, coeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// we disconnect
$oImpots->disconnect();
// we return the result
if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
else return array(array(),$limites,$coeffr,$coeffn);
}//getData
Lo script fa ciò che deve fare: calcolare l'imposta. Lasciamo al lettore il compito di decifrare il codice di elaborazione. Ci interessano gli stati che possono verificarsi a seguito di questa azione:
- i dati inseriti non sono corretti o c'è un problema nell'accedere ai dati: l'applicazione viene impostata nello stato [e-errors]. Il file di configurazione mostra che lo script e-errors.php sarà responsabile della generazione della vista di risposta:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
- In tutti gli altri casi, l'applicazione viene impostata sullo stato [e-form] con la variante di calcolo delle imposte specificata in $dSession['state']['secondary']. Il file di configurazione indica che lo script e-formulaire.php genererà la vista di risposta. Utilizzerà il valore di $dSession['state']['secondary'] per generare un modulo precompilato con i valori inseriti dall'utente e l'importo dell'imposta.
4.12.4. L'azione post:effacerformulaire
È associata tramite configurazione allo script a-init.php già descritto.
4.12.5. L'azione get:return-form
Consente di tornare allo stato [e-form] dallo stato [e-errors]. Lo script a-retourformulaire.php gestisce questa azione:
Lo script a-retourformulaire.php è il seguente:
<?php
// the input form is displayed
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'retourformulaire');
?>
Chiediamo semplicemente che l'applicazione sia impostata sullo stato [e-form] nella sua variante [form-return]. Il file di configurazione ci mostra che il controller eseguirà lo script e-form.php per generare la risposta al client.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Lo script e-formulaire.php genererà la vista [v-formulaire] nella sua variante [retourformulaire], ovvero il modulo precompilato con i valori inseriti dall'utente ma senza l'importo dell'imposta.
4.13. Sequenza di azioni non valida
Le azioni valide da un dato stato dell'applicazione sono definite dalla configurazione:
<?php
…
// application status configuration
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
$dConfig['etats']['sansetat']=array('actionsautorisees'=>array('get:init'));
Abbiamo già spiegato questa configurazione. Se viene rilevata una sequenza di azioni non valida, viene eseguito lo script a-invalid-sequence.php:
Il codice di questo script è il seguente:
<?php
// invalid sequence of actions
$dReponse['erreurs']=array("Enchaînement d'actions invalide");
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'enchainementinvalide');
?>
Questo imposta l'applicazione allo stato [e-errors]. Forniamo informazioni in $dSession['state']['secondary'] che saranno utilizzate dal generatore della pagina di errore. Come abbiamo già visto, questo generatore è e-errors.php:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
Esamineremo il codice di questo generatore più avanti. La vista inviata al client è la seguente:

4.14. Le viste dell'applicazione
4.14.1. Visualizzazione della vista finale
Vediamo come il controller invia la risposta al client una volta eseguita l'azione richiesta dal client:
<?php
…
....
// start or resume session
session_start();
$dSession=$_SESSION["session"];
if($dSession) $dSession=unserialize($dSession);
// retrieve the action to be taken
$sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
$sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";
// is the sequence of actions normal?
if( ! enchainementOK($dConfig,$dSession,$sAction)){
// abnormal sequence
$sAction='enchainementinvalide';
}//if
// share processing
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// send response(view) to customer
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
.....
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: configuration dictionary
// $dSession: dictionary containing session information
// $dReponse: the dictionary of arguments for the response page
// session registration
...
// reply sent to customer
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// end of script
exit(0);
}//endsession
Al ritorno da uno script di azione, il controller recupera lo stato in cui deve impostare l'applicazione da $dSession['etat']['principal']. Questo stato è stato impostato dall'azione appena eseguita. Il controller esegue quindi il generatore di vista associato a tale stato. Trova il nome del generatore di vista nel file di configurazione. Il ruolo del generatore di vista è il seguente:
- Imposta il nome del modello di risposta da utilizzare in $dResponse['responseView']. Questa informazione verrà passata al controller. Un modello è una composizione di viste di base che, una volta combinate, formano la vista finale.
- Prepara le informazioni dinamiche da visualizzare nella vista finale. Questo passaggio è indipendente dal controller. Funge da interfaccia tra il generatore di viste e la vista finale. È specifico per ogni applicazione.
- deve terminare con una chiamata alla funzione finSession del controller. Questa funzione
- salverà la sessione
- invierà la risposta
Il codice per la funzione finSession è il seguente:
<?php
…
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: configuration dictionary
// $dSession: dictionary containing session information
// $dReponse: the dictionary of arguments for the response page
// session registration
...
// reply sent to customer
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// end of script
exit(0);
}//endsession
La vista inviata all'utente è definita dall'entità $dResponse['responseView'], che definisce il template da utilizzare per la risposta finale.
4.14.2. Modello di risposta
L'applicazione genererà le sue varie risposte sulla base del seguente modello unico:
![]() |
Questo modello è associato alla chiave 'modele1' nel dizionario $dConfig['vuesreponse']:
Lo script m-reponse.php è responsabile della generazione di questo modello:
<html>
<head>
<title>Application impots</title>
<link type="text/css" href="<?php echo $dReponse['urlstyle'] ?>" rel="stylesheet" />
</head>
<body>
<?php
include $dReponse['vue1'];
?>
<hr>
<?php
include $dReponse['vue2'];
?>
</body>
</html>
Questo script contiene tre elementi dinamici memorizzati in un dizionario $dResponse e associati alle seguenti chiavi:
- urlstyle: URL del foglio di stile del modello
- view1: nome dello script responsabile della generazione della vista view1
- vue2: nome dello script responsabile della generazione della vista vue2
Un generatore di viste che desideri utilizzare il modello modèle1 deve definire questi tre elementi dinamici. Definiamo ora le viste di base che possono sostituire gli elementi [vue1] e [vue2] nel modello.
4.14.3. La vista di base v-bandeau.php
Lo script v-bandeau.php genera una vista che verrà inserita nell'area [vue1]:
<table>
<tr>
<td><img src="univ01.gif"></td>
<td>
<table>
<tr>
<td><div class='titre'><?php echo $dReponse['titre'] ?></div></td>
</tr>
<tr>
<td><div class='resultat'><?php echo $dReponse['resultat']?></div></td>
</tr>
</table>
</td>
</tr>
</table>
Il generatore di viste deve definire due elementi dinamici inseriti in un dizionario $dResponse e associati alle seguenti chiavi:
title: title to display
result: amount of tax due
4.14.4. La vista di base v-form.php
La sezione [vue2] corrisponde alla vista [v-form] o alla vista [v-errors]. La vista [v-form] è generata dallo script v-formulaire.php:
<form method="post" action="main.php?action=calculerimpot">
<table>
<tr>
<td class="libelle">Etes-vous marié(e)</td>
<td class="valeur">
<input type="radio" name="optmarie" <?php echo $dReponse['optoui'] ?> value="oui">oui
<input type="radio" name="optmarie" <?php echo $dReponse['optnon'] ?> value="non">non
<td>
<tr>
<td class="libelle">Nombre d'enfants</td>
<td class="valeur">
<input type="text" class="text" name="txtenfants" size="3" value="<?php echo $dReponse['enfants'] ?>"
</td>
</tr>
<tr>
<td class="libelle">Salaire annuel</td>
<td class="valeur">
<input type="text" class="text" name="txtsalaire" size="10" value="<?php echo $dReponse['salaire'] ?>"
</td>
</tr>
</table>
<hr>
<input type="submit" class="submit" value="Calculer l'impôt">
</form>
<form method="post" action="main.php?action=effacerformulaire">
<input type="submit" class="submit" value="Effacer le formulaire">
</form>
Le parti dinamiche di questa vista che devono essere definite dal generatore di viste sono associate alle seguenti chiavi nel dizionario $dReponse:
- optoui: stato del pulsante di opzione denominato optoui
- optnon: stato del pulsante di opzione denominato optnon
- children: numero di figli da inserire nel campo txtenfants
- salary: stipendio annuale da inserire nel campo txtsalary
4.14.5. La vista di base v-erreurs.php
La vista [v-errors] è generata dallo script v-errors.php:
Les erreurs suivantes se sont produites :
<ul>
<?php
for($i=0;$i<count($dReponse["erreurs"]);$i++){
echo "<li class='erreur'>".$dReponse["erreurs"][$i]."</li>\n";
}//for
?>
</ul>
<div class="info"><?php echo $dReponse["info"] ?></div>
<br>
<a href="<?php echo $dReponse["href"] ?>"><?php echo $dReponse["lien"] ?></a>
Le parti dinamiche di questa vista che devono essere definite dal generatore di viste sono associate alle seguenti chiavi nel dizionario $dReponse:
- errors: array di messaggi di errore
- info: messaggio informativo
- link: testo di un link
- href: URL di destinazione del link sopra indicato
4.14.6. Il foglio di stile
Tutte le viste sono definite da un foglio di stile. Per modificare l'aspetto visivo dell'applicazione, è necessario modificare il foglio di stile. Il seguente foglio di stile style1.css:
div.menu {
background-color: #FFD700;
color: #F08080;
font-weight: bolder;
text-align: center;
}
td.separateur {
background: #FFDAB9;
width: 20px;
}
table.modele2 {
width: 600px;
}
BODY {
background-image : url(standard.jpg);
margin-left : 0px;
margin-top : 6px;
color : #4A1919;
font-size: 10pt;
font-family: Arial, Helvetica, sans-serif;
scrollbar-face-color:#F2BE7A;
scrollbar-arrow-color:#4A1919;
scrollbar-track-color:#FFF1CC;
scrollbar-3dlight-color:#CBB673;
scrollbar-darkshadow-color:#CBB673;
}
div.titre {
font: 30pt Garamond;
color: #FF8C00;
background-color: Yellow;
}
table.menu {
background-color: #ADD8E6;
}
A:HOVER {
text-decoration: underline;
color: #FF0000;
background-color : transparent;
}
A:ACTIVE {
text-decoration: underline;
color : #BF4141;
background-color : transparent;
}
A:VISITED {
color : #BF4141;
background-color : transparent;
}
.error {
color : red;
font-weight : bold;
}
INPUT.text {
margin-left : 3px;
font-size:8pt;
font-weight:bold;
color:#4A1919;
background-color:#FFF6E0;
border-right:1px solid;
border-left:1px solid;
border-top:1px solid;
border-bottom:1px solid;
}
td.libelle {
background-color: #F0FFFF;
color: #0000CD;
}
td.valeur {
background-color: #DDA0DD;
}
DIV.resultat {
background-color : #FFA07A;
font : bold 12pt;
}
div.info {
color: #FA8072;
}
li.erreur {
color: #DC143C;
}
INPUT.submit {
margin-left : 6px;
font-size:8pt;
font-weight:bold;
color:#4A1919;
background-color:#FFF1CC;
border-right:1px solid;
border-left:1px solid;
border-top:1px solid;
border-bottom:1px solid;
}
4.15. Visualizza generatori
4.15.1. Il ruolo di un generatore di viste
Rivediamo il frammento di codice del controller che esegue un generatore di viste:
<?php
…
// share processing
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// send response(view) to customer
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
Un generatore di vista è associato allo stato in cui si troverà l'applicazione. Il collegamento tra lo stato e il generatore di vista viene definito tramite la configurazione:
<?php
…
// application status configuration
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
$dConfig['etats']['sansetat']=array('actionsautorisees'=>array('get:init'));
Abbiamo già spiegato il ruolo di un generatore di viste. Rivediamolo qui. Un generatore di viste:
- imposta il nome del modello di risposta da utilizzare in $dResponse['responseView']. Questa informazione verrà passata al controller. Un modello è una composizione di viste di base che, una volta combinate, formano la vista finale.
- prepara le informazioni dinamiche da visualizzare nella vista finale. Questo passaggio è indipendente dal controller. Funge da interfaccia tra il generatore di viste e la vista finale. È specifico per ogni applicazione.
- deve terminare con una chiamata alla funzione finSession del controller. Questa funzione
- salverà la sessione
- invierà la risposta
4.15.2. Il generatore di vista associato allo stato [e-form]
Lo script responsabile della generazione della vista associata allo stato [e-form] si chiama e-form.php:
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Il codice è il seguente:
<?php
// we prepare the answer form
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['vuereponse']='modele1';
$dReponse['vue1']=$dConfig['vues']['bandeau']['url'];
$dReponse['vue2']=$dConfig['vues']['formulaire']['url'];
$dReponse['urlstyle']=$dConfig['style']['url'];
$dReponse['titre']=$dConfig['webapp']['titre'];
// configuration according to the type of form to be generated
$type=$dSession['etat']['secondaire'];
if($type=='init'){
// empty form
$dReponse['optnon']='checked';
}//if
if($type=='calculimpot'){
// we need to redisplay the input parameters stored in the query
$dReponse['optoui']=$_POST['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui'] ? '' : 'checked';
$dReponse['enfants']=$_POST['txtenfants'];
$dReponse['salaire']=$_POST['txtsalaire'];
$dReponse['resultat']='Impôt à payer : '.$dReponse['impot'].' F';
}//if
if($type=='retourformulaire'){
// we need to redisplay the input parameters stored in the session
$dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';
$dReponse['enfants']=$dSession['requete']['txtenfants'];
$dReponse['salaire']=$dSession['requete']['txtsalaire'];
}//if
// we send the answer
finSession($dConfig,$dReponse,$dSession);
?>
Si noti che il generatore di viste soddisfa i requisiti previsti per un generatore di viste:
- imposta il modello di risposta da utilizzare in $dReponse['vuereponse']
- passare le informazioni a questo modello. In questo caso, vengono passate tramite il dizionario $dResponse.
- terminare chiamando la funzione finSession del controller
Qui, il modello utilizzato è 'template1'. Pertanto, il generatore di viste definisce le due informazioni richieste da questo modello: $dResponse['view1'] e $dResponse['view2'].
Nel caso specifico della nostra applicazione, la vista associata allo stato [e-form] dipende dalle informazioni memorizzate nella variabile $dSession['etat']['secondaire']. Si tratta di una scelta di progettazione. Un'altra applicazione potrebbe scegliere di passare informazioni aggiuntive in modo diverso. Inoltre, qui tutte le informazioni necessarie per visualizzare la vista finale sono collocate nel dizionario $dResponse. Anche in questo caso, si tratta di una scelta lasciata allo sviluppatore. Lo stato [e-form] può verificarsi dopo quattro diverse azioni: init, calculateTax, returnForm, clearForm. La vista da visualizzare non è esattamente la stessa in tutti i casi. Pertanto, abbiamo distinto tre casi qui in $dSession['state']['secondary']:
- init: il modulo viene visualizzato vuoto
- calculateTax: il modulo viene visualizzato con l'importo dell'imposta e i dati utilizzati per calcolarlo
- returnform: il modulo viene visualizzato con i dati inseriti inizialmente
Sopra, lo script e-formulaire.php utilizza queste informazioni per presentare la risposta in base a queste tre varianti.
4.15.3. La vista associata allo stato [e-errors]
Lo script responsabile della generazione della vista associata allo stato [e-errors] si chiama e-errors.php ed è il seguente:
<?php
// we prepare the answer errors
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['vuereponse']='modele1';
$dReponse['vue1']=$dConfig['vues']['bandeau']['url'];
$dReponse['vue2']=$dConfig['vues']['erreurs']['url'];
$dReponse['urlstyle']=$dConfig['style']['url'];
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['lien']='Retour au formulaire de saisie';
$dReponse['href']='main.php?action=retourformulaire';
// additional information
$type=$dSession['etat']['secondaire'];
if($type=='database'){
$dReponse['info']="Veuillez avertir l'administrateur de l'application";
}
// we send the answer
finSession($dConfig,$dReponse,$dSession);
?>
4.15.4. Visualizzazione della vista finale
Entrambi gli script che generano le due viste finali terminano con una chiamata alla funzione finSession del controller:
<?php
…
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: configuration dictionary
// $dSession: dictionary containing session information
// $dReponse: the dictionary of arguments for the response page
....
// we present the answer
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// end of script
exit(0);
}//endsession
La vista inviata all'utente è definita dall'entità $dResponse['responseView'], che specifica il modello da utilizzare per la risposta finale. Per gli stati [e-form] ed [e-errors], questo modello è stato impostato su template1:
Questo modello corrisponde allo script m-reponse.php:
4.16. Modifica del modello di risposta
In questo caso, supponiamo di voler modificare l'aspetto visivo della risposta inviata al client e desideriamo comprendere le implicazioni che ciò comporta sul codice.
4.16.1. Il nuovo modello
La struttura della risposta sarà ora la seguente:
![]() |
Questo modello si chiamerà template2, mentre lo script responsabile della sua generazione si chiamerà m-response2.php:
Lo script corrispondente a questo modello è il seguente:
<html>
<head>
<title>Application impots</title>
<link type="text/css" href="<?php echo $dReponse['urlstyle'] ?>" rel="stylesheet" />
</head>
<body>
<table class='modele2'>
<!-- start banner -->
<tr>
<td colspan="2"><?php include $dReponse['vue1']; ?></td>
</tr>
<!-- slim band -->
<tr>
<!-- start menu -->
<td><?php include $dReponse['vue2']; ?></td>
<!-- end menu -->
<!-- start zone 3 -->
<td><?php include $dReponse['vue3']; ?></td>
<!-- end of zone 3 -->
</tr>
</table>
</body>
</html>
Gli elementi dinamici del modello sono i seguenti:
- $dReponse['urlstyle']: il foglio di stile da utilizzare
- $dReponse['vue1']: lo script da utilizzare per generare [vue1]
- $dReponse['vue2']: lo script da utilizzare per generare [vue2]
- $dReponse['vue3']: lo script da utilizzare per generare [vue3]
Questi elementi devono essere impostati dai generatori di vista.
4.16.2. Le diverse pagine di risposta
L'applicazione presenterà ora le seguenti risposte all'utente. Alla chiamata iniziale, la pagina di risposta sarà la seguente:
![]() |
Se l'utente fornisce dati validi, l'imposta viene calcolata:
![]() |
Se commette errori di inserimento, viene visualizzata la pagina di errore:
![]() |
Se utilizzano il link [Torna al modulo di inserimento dati], vedranno il modulo così come è stato inviato l'ultima volta:
![]() |
Se, nello scenario sopra descritto, utilizzano il link [Reimposta modulo], vedranno un modulo vuoto:
![]() |
Si noti che l'applicazione utilizza le stesse azioni di prima. È cambiato solo l'aspetto delle risposte.
4.16.3. Viste di base
La vista di base [view1] sarà associata allo script v-bandeau.php, come nell'esempio precedente:
<table>
<tr>
<td><img src="univ01.gif"></td>
<td>
<table>
<tr>
<td><div class='titre'><?php echo $dReponse['titre'] ?></div></td>
</tr>
<tr>
<td><div class='resultat'><?php echo $dReponse['resultat']?></div></td>
</tr>
</table>
</td>
</tr>
</table>
Questa vista presenta due elementi dinamici:
- $dResponse['title']: titolo da visualizzare
- $dResponse['resultat']: importo dell'imposta dovuta
La vista di base [vue2] sarà associata al seguente script v-menu.php:
<table class="menu">
<tr>
<td><div class="menu">Options</div></td>
</tr>
<?php
for($i=0;$i<count($dReponse['liens']);$i++){
echo '<tr><td><div class="option"><a href="'.
$dReponse['liens'][$i]['url'].
'">'.$dReponse['liens'][$i]['texte']."</a></div></td></tr>\n";
}//$i
?>
</table>
Questa vista presenta i seguenti elementi dinamici:
- $dResponse['links']: array di link da visualizzare in [view2]. Ogni elemento dell'array è un dizionario con due chiavi:
- 'url': l'URL di destinazione del link
- 'text': testo del link
La vista di base [view3] sarà associata allo script v-form2.php se si desidera visualizzare il modulo di input, oppure allo script v-errors2.php se si desidera visualizzare la pagina di errore. Il codice per lo script v-form2.php è il seguente:
<form method="post" action="main.php?action=calculerimpot">
<table>
<tr>
<td class="libelle">Etes-vous marié(e)</td>
<td class="valeur">
<input type="radio" name="optmarie" <?php echo $dReponse['optoui'] ?> value="oui">oui
<input type="radio" name="optmarie" <?php echo $dReponse['optnon'] ?> value="non">non
</td>
</tr>
<tr>
<td class="libelle">Nombre d'enfants</td>
<td class="valeur">
<input type="text" class="text" name="txtenfants" size="3" value="<?php echo $dReponse['enfants'] ?>"
</td>
</tr>
<tr>
<td class="libelle">Salaire annuel</td>
<td class="valeur">
<input type="text" class="text" name="txtsalaire" size="10" value="<?php echo $dReponse['salaire'] ?>"
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" class="submit" value="Calculer l'impôt"></td>
</tr>
</table>
</form>
Le parti dinamiche di questa vista che devono essere definite dal generatore di viste sono associate alle seguenti chiavi nel dizionario $dResponse:
- optoui: stato del pulsante di opzione denominato optoui
- optnon: stato del pulsante di opzione denominato optnon
- children: numero di figli da inserire nel campo txtenfants
- salaire: stipendio annuale da inserire nel campo txtsalaire
Lo script che genera la pagina di errore si chiama v-erreurs2.php. Il suo codice è il seguente:
Les erreurs suivantes se sont produites :
<ul>
<?php
for($i=0;$i<count($dReponse["erreurs"]);$i++){
echo "<li class='erreur'>".$dReponse["erreurs"][$i]."</li>\n";
}//for
?>
</ul>
<div class="info"><?php echo $dReponse["info"] ?></div>
Le parti dinamiche di questa vista che devono essere definite dal generatore di viste sono associate alle seguenti chiavi nel dizionario $dReponse:
errors: array of error messages
info: information message
4.16.4. Il foglio di stile
Non è cambiato. È ancora style1.css.
4.16.5. Il nuovo file di configurazione
Per implementare queste nuove viste, dobbiamo modificare alcune righe nel file di configurazione.
<?php
// php configuration
ini_set("register_globals","off");
ini_set("display_errors","off");
ini_set("expose_php","off");
// list of modules to be included
$dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');
// application controller
$dConfig['webapp']=array('titre'=>"Calculez votre impôt");
// aplication view configuration
$dConfig['vuesReponse']['modele1']=array('url'=>'m-reponse.php');
$dConfig['vuesReponse']['modele2']=array('url'=>'m-reponse2.php');
$dConfig['vues']['formulaire']=array('url'=>'v-formulaire.php');
$dConfig['vues']['erreurs']=array('url'=>'v-erreurs.php');
$dConfig['vues']['formulaire2']=array('url'=>'v-formulaire2.php');
$dConfig['vues']['erreurs2']=array('url'=>'v-erreurs2.php');
$dConfig['vues']['bandeau']=array('url'=>'v-bandeau.php');
$dConfig['vues']['menu']=array('url'=>'v-menu.php');
$dConfig['style']['url']='style1.css';
// configuration of application actions
$dConfig['actions']['get:init']=array('url'=>'a-init.php');
$dConfig['actions']['post:calculerimpot']=array('url'=>'a-calculimpot.php');
$dConfig['actions']['get:retourformulaire']=array('url'=>'a-retourformulaire.php');
$dConfig['actions']['post:effacerformulaire']=array('url'=>'a-init.php');
$dConfig['actions']['enchainementinvalide']=array('url'=>'a-enchainementinvalide.php');
$dConfig['actions']['actionInvalide']=array('url'=>'a-actioninvalide.php');
// application status configuration
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire2.php');
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs2.php');
$dConfig['etats']['sansetat']=array('actionsautorisees'=>array('get:init'));
// model application configuration
$dConfig["DSN"]=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
?>
La modifica principale consiste nell'aggiornamento dei generatori di vista associati ai report [e-form] e [e-errors]. Una volta fatto ciò, i nuovi generatori di vista si occuperanno di generare le nuove pagine di risposta.
4.16.6. Il generatore di viste associato al report [e-form]
Nel file di configurazione, lo stato [e-form] è ora associato al generatore di viste e-form2.php. Il codice di questo script è il seguente:
<?php
// we prepare the answer form
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['vuereponse']='modele2';
$dReponse['vue1']=$dConfig['vues']['bandeau']['url'];
$dReponse['vue2']=$dConfig['vues']['menu']['url'];
$dReponse['vue3']=$dConfig['vues']['formulaire2']['url'];
$dReponse['urlstyle']=$dConfig['style']['url'];
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['liens']=array(
array('texte'=>'Réinitialiser le formulaire', 'url'=>'main.php?action=init')
);
// configuration according to the type of form to be generated
$type=$dSession['etat']['secondaire'];
if($type=='init'){
// empty form
$dReponse['optnon']='checked';
}//if
if($type=='calculimpot'){
// we need to redisplay the input parameters stored in the query
$dReponse['optoui']=$_POST['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui'] ? '' : 'checked';
$dReponse['enfants']=$_POST['txtenfants'];
$dReponse['salaire']=$_POST['txtsalaire'];
$dReponse['resultat']='Impôt à payer : '.$dReponse['impot'].' F';
}//if
if($type=='retourformulaire'){
// we need to redisplay the input parameters stored in the session
$dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';
$dReponse['enfants']=$dSession['requete']['txtenfants'];
$dReponse['salaire']=$dSession['requete']['txtsalaire'];
}//if
// we send the answer
finSession($dConfig,$dReponse,$dSession);
?>
Le modifiche principali sono le seguenti:
- Il generatore di viste indica che vuole utilizzare il modello di risposta modele2
- per questo motivo, popola gli elementi dinamici $dReponse['vue1'], $dReponse['vue2'], $dReponse['vue3'], tutti e tre richiesti dal modello di risposta modele2.
- Il generatore di viste popola anche l'elemento dinamico $dResponse['links'], che imposta i link da visualizzare nell'area [view2] della risposta.
4.16.7. Il generatore di vista associato allo stato [e-errors]
Nel file di configurazione, lo stato [e-errors] è ora associato al generatore di vista e-errors2.php. Il codice per questo script è il seguente:
<?php
// we prepare the answer errors
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['vuereponse']='modele2';
$dReponse['vue1']=$dConfig['vues']['bandeau']['url'];
$dReponse['vue2']=$dConfig['vues']['menu']['url'];
$dReponse['vue3']=$dConfig['vues']['erreurs2']['url'];
$dReponse['urlstyle']=$dConfig['style']['url'];
$dReponse['titre']=$dConfig['webapp']['titre'];
$dReponse['liens']=array(
array('texte'=>'Retour au formulaire de saisie', 'url'=>'main.php?action=retourformulaire')
);
// additional information
$type=$dSession['etat']['secondaire'];
if($type=='database'){
$dReponse['info']="Veuillez avertir l'administrateur de l'application";
}
// we send the answer
finSession($dConfig,$dReponse,$dSession);
?>
Le modifiche apportate sono identiche a quelle apportate al generatore di viste e-formulaire2.php.
4.17. Conclusione
Siamo riusciti a dimostrare, utilizzando un esempio, i vantaggi del nostro controller generico. Non abbiamo dovuto scriverlo noi stessi. Abbiamo semplicemente scritto gli script di azione, i generatori di vista e le viste per l'applicazione. Abbiamo anche dimostrato i vantaggi della separazione delle azioni dalle viste. Questo ci ha permesso di modificare l'aspetto delle risposte senza modificare una sola riga di codice negli script di azione. Sono stati modificati solo gli script coinvolti nella generazione della vista. Affinché ciò sia possibile, lo script di azione non deve fare alcuna ipotesi sulla vista che visualizzerà le informazioni che ha calcolato. Deve semplicemente restituire queste informazioni al controller, che le passa al generatore di viste per formattarle. Questa è una regola assoluta: un'azione deve essere completamente disaccoppiata dalle viste.
In questo capitolo abbiamo esplorato la filosofia di Struts, ben nota agli sviluppatori Java. Un progetto open-source chiamato php.mvc consente lo sviluppo web/PHP utilizzando la filosofia di Struts. Visita http://www.phpmvc.net/ per ulteriori informazioni.













