4. Uma aplicação ilustrativa
Propomos ilustrar o método anterior com um exemplo de cálculo de impostos.
4.1. O problema
O nosso objetivo é escrever um programa para calcular o imposto de um contribuinte. Consideramos o caso simplificado de um contribuinte que tem apenas o seu salário para declarar:
- Calculamos o número de escalões de imposto para o empregado: nbParts = nbEnfants / 2 + 1 se solteiro, nbEnfants / 2 + 2 se casado, onde nbEnfants é o número de filhos. O número de escalões é aumentado em 0,5 se houver três ou mais filhos.
- Calculamos o seu rendimento tributável R = 0,72 * S, em que S é o seu salário anual
- Calculamos o seu coeficiente familiar Q = R/N
- Calculamos o seu imposto I com base nos seguintes dados
| Cada linha tem 3 campos: limite, coeffR e coeffN. Para calcular o imposto I, encontre a primeira linha em que QF <= limite. Por exemplo, se QF = 30000, a linha encontrada é: 31810 0,2 3309,5. O imposto I é então igual a 0,2*R - 3309,5*nbParts. Se QF for tal que a condição QF <= limite nunca seja satisfeita, então são utilizados os coeficientes da última linha: 0 0,65 49062, o que dá o imposto I = 0,65*R - 49062*nbParts. |
4.2. A base de dados
Os dados anteriores estão armazenados numa base de dados MySQL denominada dbimpots. O utilizador seldbimpots, com a palavra-passe mdpseldbimpots, tem acesso de leitura ao conteúdo da base de dados. A base de dados contém uma única tabela denominada impots com a seguinte estrutura:

O seu conteúdo é o seguinte:

4.3. A arquitetura MVC da aplicação
A aplicação terá a seguinte arquitetura MVC:
![]() |
- O controlador main.php será o controlador genérico descrito acima
- O pedido do cliente é enviado ao controlador sob a forma de uma consulta do tipo main.php?action=xx. O valor do parâmetro action determina qual o script do bloco ACTIONS a executar. O script de ação executado devolve uma variável ao controlador indicando o estado em que a aplicação web deve ser colocada. Com este estado, o controlador ativará um dos geradores de visualização para enviar a resposta ao cliente.
- impots-data.php é a classe responsável por fornecer ao controlador os dados de que necessita
- impots-calcul.php é a classe de lógica de negócio que calcula o imposto
4.4. A classe de acesso aos dados
A classe de acesso aos dados foi concebida para ocultar a fonte de dados da aplicação web. A sua interface inclui um método getData que retorna os três vetores de dados necessários para calcular o imposto. No nosso exemplo, os dados são recuperados de uma base de dados MySQL. Para tornar a classe independente do tipo de SGBD real, utilizaremos a biblioteca pear::DB descrita no apêndice. O código da classe é o seguinte:
<?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
?>
Um programa de teste poderia ter o seguinte aspeto:
<?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
?>
A execução deste programa de teste produz os seguintes resultados:
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. A classe de cálculo de impostos
Esta classe é utilizada para calcular o imposto de um contribuinte. Os dados necessários para este cálculo são fornecidos ao seu construtor. Em seguida, calcula o imposto correspondente. O código da classe é o seguinte:
<?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
?>
Um programa de teste poderia ter o seguinte aspeto:
<?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
?>
A execução deste programa de teste produz os seguintes resultados:
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. Como funciona a aplicação
Quando a calculadora de impostos baseada na web é iniciada, aparece a seguinte vista [v-form]:
![]() |
O utilizador preenche os campos e solicita o cálculo do imposto:
![]() |
Note que o formulário é regenerado no estado em que o utilizador o enviou e também apresenta o montante do imposto devido. O utilizador pode cometer erros na introdução de dados. Estes são assinalados por uma página de erro, à qual chamaremos de vista [v-errors].
![]() |
![]() |
O link [Voltar ao formulário de entrada] permite ao utilizador regressar ao formulário tal como o enviou.
![]() |
Por fim, o botão [Limpar formulário] repõe o formulário no seu estado inicial, ou seja, tal como o utilizador o recebeu durante o pedido inicial.
4.7. Voltar à arquitetura MVC da aplicação
A aplicação tem a seguinte arquitetura MVC:
![]() |
Acabámos de descrever as duas classes impots-data.php e impots-calcul.php. Vamos agora descrever os outros elementos da arquitetura.
4.8. O controlador da aplicação
O controlador main.php da aplicação é aquele descrito na primeira parte deste capítulo. Trata-se de um controlador genérico, independente da aplicação.
<?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. Ações da aplicação web
Existem quatro ações:
- get:init: Esta é a ação acionada durante a solicitação inicial ao controlador sem parâmetros. Ela renderiza a visualização 'form' vazia.
- post:clearform: ação acionada pelo botão [Limpar Formulário]. Ela renderiza a vista [v-form] vazia.
- post:calculateTax: ação acionada pelo botão [Calcular imposto]. Gera a vista [v-form] com o valor do imposto a pagar ou a vista [v-errors].
- get:returnform: ação acionada pelo link [Voltar ao formulário de entrada]. Apresenta a vista [v-form] pré-preenchida com os dados incorretos.
Estas ações são configuradas da seguinte forma no ficheiro de configuração:
<?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');
Cada ação está associada ao script responsável pelo seu processamento. Cada ação levará a aplicação web para um estado definido pelo elemento $dSession['state']['main']. Este estado destina-se a ser guardado na sessão. Além disso, a ação armazena no dicionário $dResponse as informações necessárias para apresentar a vista associada ao novo estado em que a aplicação ficará.
4.10. Estados da Aplicação Web
Existem dois:
[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.
As ações permitidas nestes estados são as seguintes:
<?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'));
Num estado, as ações permitidas correspondem aos URLs de destino dos links ou botões [submit] na vista associada a esse estado. Além disso, a ação 'get:init' é sempre permitida. Isto permite ao utilizador recuperar o URL main.php da barra de URL do seu navegador e recarregá-lo independentemente do estado da aplicação. Trata-se de uma espécie de reinicialização «manual». O estado 'sansetat' existe apenas quando a aplicação é iniciada.
Cada estado da aplicação está associado a um script responsável por gerar a vista associada a esse estado:
- estado [e-form]: script e-formulaire.php
- estado [e-errors]: script e-errors.php
O estado [e-form] exibirá a vista [v-form] com variações. Na verdade, a vista [v-form] pode ser exibida vazia, pré-preenchida ou com o valor do imposto. A ação que coloca a aplicação no estado [e-form] especifica o estado principal da aplicação na variável $dSession['state']['main']. O controlador utiliza apenas esta informação. Na nossa aplicação, a ação que conduz ao estado [e-form] irá adicionar informações adicionais a $dSession['state']['secondary'], permitindo que o gerador de respostas saiba se deve gerar um formulário vazio, um formulário pré-preenchido ou um formulário com ou sem o valor do imposto. Poderíamos ter adotado uma abordagem diferente, assumindo que existiam três estados diferentes e, portanto, três geradores de visualização para escrever.
4.11. O ficheiro de configuração config.php da aplicação 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. Ações da aplicação web
4.12.1. Funcionamento geral dos scripts de ação
- Um script de ação é chamado pelo controlador com base no parâmetro de ação que recebeu do cliente.
- Após a execução, o script de ação deve indicar ao controlador o estado em que a aplicação deve ser colocada. Este estado deve ser especificado em $dSession['etat']['principal'].
- Um script de ação pode querer armazenar informações na sessão. Para tal, coloca essas informações no dicionário $dSession, que é automaticamente guardado na sessão pelo controlador no final do ciclo de pedido-resposta.
- Um script de ação pode conter informações a transmitir às visualizações. Este aspeto é independente do controlador. Trata-se da interface entre as ações e as visualizações, uma interface específica de cada aplicação. No exemplo aqui abordado, as ações fornecerão informações aos geradores de visualizações através de um dicionário denominado $dResponse.
4.12.2. A ação get:init
Esta é a ação que gera o formulário vazio. O ficheiro de configuração mostra que será tratada pelo script a-init.php:
O código do script a-init.php é o seguinte:
<?php
// the input form is displayed
$dSession['etat']=array('principal'=>'e-formulaire', 'secondaire'=>'init');
?>
Este script define simplesmente o estado em que a aplicação deve estar — o estado [e-form] — em $dSession['etat']['principal'], e fornece uma descrição deste estado em $dSession['etat']['secondaire']. O ficheiro de configuração mostra-nos que o controlador irá executar o script e-formulaire.php para gerar a resposta para o cliente.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
O script e-formulaire.php irá gerar a vista [v-formulaire] na sua variante [init], ou seja, o formulário vazio.
4.12.3. A ação post:calculateTax
Esta é a ação que calcula o imposto com base nos dados introduzidos no formulário. O ficheiro de configuração especifica que o script a-calculimpot.php irá tratar desta ação:
O código do script a-calculimpot.php é o seguinte:
<?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
O script faz o que é suposto fazer: calcular o imposto. Deixamos ao leitor a tarefa de decifrar o código de processamento. Estamos interessados nos estados que podem surgir como resultado desta ação:
- os dados introduzidos estão incorretos ou existe um problema ao aceder aos dados: a aplicação é colocada no estado [e-errors]. O ficheiro de configuração mostra que o script e-errors.php será responsável por gerar a vista de resposta:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
- Em todos os outros casos, a aplicação é definida para o estado [e-form] com a variante de cálculo de impostos especificada em $dSession['state']['secondary']. O ficheiro de configuração indica que o script e-formulaire.php irá gerar a vista de resposta. Este irá utilizar o valor de $dSession['state']['secondary'] para gerar um formulário pré-preenchido com os valores introduzidos pelo utilizador e o montante do imposto.
4.12.4. A ação post:effacerformulaire
Está associada, por configuração, ao script a-init.php já descrito.
4.12.5. A ação get:return-form
Permite-lhe regressar ao estado [e-form] a partir do estado [e-errors]. O script a-retourformulaire.php trata desta ação:
O script a-retourformulaire.php é o seguinte:
<?php
// the input form is displayed
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'retourformulaire');
?>
Pedimos simplesmente que a aplicação seja definida para o estado [e-form] na sua variante [form-return]. O ficheiro de configuração mostra-nos que o controlador irá executar o script e-form.php para gerar a resposta para o cliente.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
O script e-formulaire.php irá gerar a vista [v-formulaire] na sua variante [retourformulaire], ou seja, o formulário pré-preenchido com os valores introduzidos pelo utilizador, mas sem o montante do imposto.
4.13. Sequência de ações inválida
As ações válidas a partir de um determinado estado da aplicação são definidas pela configuração:
<?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'));
Já explicámos esta configuração. Se for detetada uma sequência inválida de ações, o script a-invalid-sequence.php é executado:
O código deste script é o seguinte:
<?php
// invalid sequence of actions
$dReponse['erreurs']=array("Enchaînement d'actions invalide");
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'enchainementinvalide');
?>
Isto define a aplicação para o estado [e-errors]. Fornecemos informações em $dSession['state']['secondary'] que serão utilizadas pelo gerador da página de erro. Como já vimos, este gerador é o e-errors.php:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
Analisaremos o código deste gerador mais tarde. A visualização enviada ao cliente é a seguinte:

4.14. As visualizações da aplicação
4.14.1. Exibição da vista final
Vamos ver como o controlador envia a resposta ao cliente assim que a ação solicitada pelo cliente tiver sido executada:
<?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
Ao regressar de um script de ação, o controlador recupera o estado em que deve colocar a aplicação a partir de $dSession['etat']['principal']. Este estado foi definido pela ação que acabou de ser executada. O controlador executa então o gerador de visualização associado a esse estado. Encontra o nome do gerador de visualização no ficheiro de configuração. A função do gerador de visualização é a seguinte:
- Define o nome do modelo de resposta a ser utilizado em $dResponse['responseView']. Esta informação será passada para o controlador. Um modelo é uma composição de vistas básicas que, quando combinadas, formam a vista final.
- Prepara as informações dinâmicas a serem exibidas na vista final. Esta etapa é independente do controlador. Funciona como a interface entre o gerador de vistas e a vista final. É específica para cada aplicação.
- deve terminar com uma chamada à função finSession do controlador. Esta função irá
- guardará a sessão
- enviar a resposta
O código para a função finSession é o seguinte:
<?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
A visualização enviada ao utilizador é definida pela entidade $dResponse['responseView'], que define o modelo a utilizar para a resposta final.
4.14.2. Modelo de resposta
A aplicação irá gerar as suas várias respostas com base no seguinte modelo único:
![]() |
Este modelo está associado à chave «modele1» no dicionário $dConfig['vuesreponse']:
O script m-reponse.php é responsável por gerar este modelo:
<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>
Este script tem três elementos dinâmicos armazenados num dicionário $dReponse e associados às seguintes chaves:
- urlstyle: URL da folha de estilos do modelo
- view1: nome do script responsável por gerar a vista view1
- vue2: nome do script responsável pela geração da vista vue2
Um gerador de vistas que pretenda utilizar o modelo modèle1 deve definir estes três elementos dinâmicos. Definimos agora as vistas básicas que podem substituir os elementos [vue1] e [vue2] no modelo.
4.14.3. A vista básica v-bandeau.php
O script v-bandeau.php gera uma vista que será colocada na área [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>
O gerador de visualização deve definir dois elementos dinâmicos colocados num dicionário $dResponse e associados às seguintes chaves:
title: title to display
result: amount of tax due
4.14.4. A vista básica v-form.php
A secção [vue2] corresponde à vista [v-form] ou à vista [v-errors]. A vista [v-form] é gerada pelo 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>
As partes dinâmicas desta vista que devem ser definidas pelo gerador de vistas estão associadas às seguintes chaves no dicionário $dReponse:
- optoui: estado do botão de opção denominado optoui
- optnon: estado do botão de opção denominado optnon
- children: número de filhos a colocar no campo txtenfants
- salary: salário anual a ser colocado no campo txtsalary
4.14.5. A vista básica v-erreurs.php
A vista [v-errors] é gerada pelo 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>
As partes dinâmicas desta vista a serem definidas pelo gerador de vistas estão associadas às seguintes chaves no dicionário $dReponse:
- errors: matriz de mensagens de erro
- info: mensagem informativa
- link: texto de um link
- href: URL de destino do link acima
4.14.6. A folha de estilo
Todas as visualizações são formatadas por uma folha de estilo. Para alterar a aparência visual da aplicação, modifique a sua folha de estilo. A seguinte folha de estilo 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. Geradores de visualização
4.15.1. Função de um gerador de vistas
Vamos rever o trecho de código do controlador que executa um gerador de visualizações:
<?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;
Um gerador de visualização está associado ao estado em que a aplicação será colocada. A ligação entre o estado e o gerador de visualização é definida através da configuração:
<?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'));
Já explicámos o papel de um gerador de visualizações. Vamos revê-lo aqui. Um gerador de visualizações:
- define o nome do modelo de resposta a ser utilizado em $dResponse['responseView']. Esta informação será passada para o controlador. Um modelo é uma composição de vistas básicas que, quando combinadas, formam a vista final.
- prepara as informações dinâmicas a serem exibidas na vista final. Esta etapa é independente do controlador. Funciona como a interface entre o gerador de vistas e a vista final. É específica para cada aplicação.
- deve terminar com uma chamada à função finSession do controlador. Esta função irá
- guardará a sessão
- enviar a resposta
4.15.2. O gerador de visualizações associado ao estado [e-form]
O script responsável por gerar a vista associada ao estado [e-form] chama-se e-form.php:
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
O seu código é o seguinte:
<?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);
?>
Note que o gerador de visualizações cumpre os requisitos para um gerador de visualizações:
- definir o modelo de resposta a utilizar em $dResponse['vuereponse']
- passe informações para este modelo. Aqui, elas são passadas através do dicionário $dResponse.
- termine chamando a função finSession do controlador
Aqui, o modelo utilizado é «template1». Por conseguinte, o gerador de visualizações define as duas informações exigidas por este modelo: $dResponse['view1'] e $dResponse['view2'].
No caso específico da nossa aplicação, a vista associada ao estado [e-form] depende da informação armazenada na variável $dSession['etat']['secondaire']. Esta é uma escolha de design. Outra aplicação poderá optar por passar informação adicional de uma forma diferente. Além disso, aqui toda a informação necessária para apresentar a vista final é colocada no dicionário $dResponse. Mais uma vez, esta é uma escolha deixada ao critério do programador. O estado [e-form] pode ocorrer após quatro ações diferentes: init, calculateTax, returnForm, clearForm. A vista a ser apresentada não é exatamente a mesma em todos os casos. Por isso, distinguimos aqui três casos em $dSession['state']['secondary']:
- init: o formulário é apresentado vazio
- calculateTax: o formulário é apresentado com o montante do imposto e os dados utilizados para o calcular
- returnform: o formulário é apresentado com os dados inicialmente introduzidos
Acima, o script e-formulaire.php utiliza esta informação para apresentar a resposta de acordo com estas três variantes.
4.15.3. A vista associada ao estado [e-errors]
O script responsável por gerar a vista associada ao estado [e-errors] chama-se e-errors.php e é o seguinte:
<?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. Exibição da vista final
Ambos os scripts que geram as duas visualizações finais terminam com uma chamada à função finSession do controlador:
<?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
A vista enviada ao utilizador é definida pela entidade $dResponse['responseView'], que especifica o modelo a utilizar para a resposta final. Para os estados [e-form] e [e-errors], este modelo foi definido como template1:
Este modelo corresponde ao script m-reponse.php:
4.16. Modificar o modelo de resposta
Aqui, partimos do princípio de que decidimos alterar a aparência visual da resposta enviada ao cliente e estamos interessados em compreender as implicações que isso tem no código.
4.16.1. O novo modelo
A estrutura da resposta será agora a seguinte:
![]() |
Este modelo será denominado template2, e o script responsável pela sua geração será denominado m-response2.php:
O script correspondente a este modelo é o seguinte:
<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>
Os elementos dinâmicos do modelo são os seguintes:
- $dReponse['urlstyle']: a folha de estilo a utilizar
- $dReponse['vue1']: o script a utilizar para gerar [vue1]
- $dReponse['vue2']: o script a utilizar para gerar [vue2]
- $dReponse['vue3']: o script a utilizar para gerar [vue3]
Estes elementos devem ser definidos pelos geradores de visualização.
4.16.2. As diferentes páginas de resposta
A aplicação irá agora apresentar as seguintes respostas ao utilizador. Na chamada inicial, a página de resposta será a seguinte:
![]() |
Se o utilizador fornecer dados válidos, o imposto é calculado:
![]() |
Se cometer erros na introdução de dados, é apresentada a página de erro:
![]() |
Se utilizarem o link [Voltar ao formulário de introdução de dados], verão o formulário tal como o enviaram pela última vez:
![]() |
Se, no cenário acima, utilizarem o link [Redefinir formulário], verão um formulário vazio:
![]() |
Note que a aplicação utiliza as mesmas ações que anteriormente. Apenas a apresentação das respostas mudou.
4.16.3. Visualizações básicas
A vista básica [view1] será associada ao script v-bandeau.php, tal como no exemplo anterior:
<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>
Esta visualização tem dois elementos dinâmicos:
- $dResponse['title']: título a apresentar
- $dResponse['resultat']: montante do imposto devido
A vista básica [vue2] será associada ao seguinte 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>
Esta vista tem os seguintes elementos dinâmicos:
- $dResponse['links']: matriz de links a apresentar em [view2]. Cada elemento da matriz é um dicionário com duas chaves:
- 'url': o URL de destino do link
- 'text': texto do link
A vista básica [view3] será associada ao script v-form2.php se pretender apresentar o formulário de entrada, ou ao script v-errors2.php se pretender apresentar a página de erro. O código para o script v-form2.php é o seguinte:
<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>
As partes dinâmicas desta vista que devem ser definidas pelo gerador de vistas estão associadas às seguintes chaves no dicionário $dResponse:
- optoui: estado do botão de opção denominado optoui
- optnon: estado do botão de opção denominado optnon
- children: número de filhos a colocar no campo txtenfants
- salaire: salário anual a ser colocado no campo txtsalaire
O script que gera a página de erro chama-se v-erreurs2.php. O seu código é o seguinte:
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>
As partes dinâmicas desta vista a serem definidas pelo gerador de vistas estão associadas às seguintes chaves no dicionário $dReponse:
errors: array of error messages
info: information message
4.16.4. A folha de estilo
Não sofreu alterações. Continua a ser style1.css.
4.16.5. O novo ficheiro de configuração
Para implementar estas novas visualizações, precisamos de modificar certas linhas no ficheiro de configuração.
<?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"
);
?>
A alteração principal envolve a atualização dos geradores de visualização associados aos relatórios [e-form] e [e-errors]. Depois de concluída esta tarefa, os novos geradores de visualização ficam responsáveis pela geração das novas páginas de resposta.
4.16.6. O gerador de visualização associado ao relatório [e-form]
No ficheiro de configuração, o estado [e-form] está agora associado ao gerador de visualizações e-form2.php. O código para este script é o seguinte:
<?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);
?>
As principais alterações são as seguintes:
- O gerador de visualização indica que pretende utilizar o modelo de resposta modele2
- por esse motivo, preenche os elementos dinâmicos $dResponse['vue1'], $dResponse['vue2'], $dResponse['vue3'], sendo que todos os três são exigidos pelo modelo de resposta modele2.
- O gerador de visualizações também preenche o elemento dinâmico $dResponse['links'], que define os links a serem exibidos na área [view2] da resposta.
4.16.7. O gerador de visualização associado ao estado [e-errors]
No ficheiro de configuração, o estado [e-errors] está agora associado ao gerador de visualização e-errors2.php. O código para este script é o seguinte:
<?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);
?>
As alterações efetuadas são idênticas às realizadas no gerador de visualização e-formulaire2.php.
4.17. Conclusão
Conseguimos demonstrar, através de um exemplo, as vantagens do nosso controlador genérico. Não tivemos de o escrever nós próprios. Simplesmente escrevemos os scripts de ação, os geradores de visualização e as visualizações para a aplicação. Também demonstrámos as vantagens de separar as ações das visualizações. Isto permitiu-nos alterar a aparência das respostas sem modificar uma única linha de código nos scripts de ação. Apenas os scripts envolvidos na geração de visualizações foram modificados. Para que isto seja possível, o script de ação não deve fazer suposições sobre a vista que irá apresentar a informação que calculou. Deve simplesmente devolver esta informação ao controlador, que a passa ao gerador de vistas para a formatar. Esta é uma regra absoluta: uma ação deve estar completamente dissociada das vistas.
Neste capítulo, explorámos a filosofia Struts, bem conhecida dos programadores Java. Um projeto de código aberto chamado php.mvc permite o desenvolvimento web/PHP utilizando a filosofia Struts. Visite http://www.phpmvc.net/ para mais informações.













