4. Eine anschauliche Anwendung
Wir schlagen vor, die vorstehende Methode anhand eines Beispiels zur Steuerberechnung zu veranschaulichen.
4.1. Das Problem
Wir wollen ein Programm schreiben, das die Steuer eines Steuerpflichtigen berechnet. Wir betrachten den vereinfachten Fall eines Steuerpflichtigen, der nur sein Gehalt anzugeben hat:
- Wir berechnen die Anzahl der Steuerklassen für den Arbeitnehmer: nbParts = nbEnfants / 2 + 1, wenn unverheiratet, nbEnfants / 2 + 2, wenn verheiratet, wobei nbEnfants die Anzahl der Kinder ist. Die Anzahl der Steuerklassen erhöht sich um 0,5, wenn drei oder mehr Kinder vorhanden sind.
- Wir berechnen das zu versteuernde Einkommen R = 0,72 * S, wobei S das Jahresgehalt ist
- Wir berechnen ihren Familienkoeffizienten Q = R/N
- Wir berechnen seine Steuer I auf der Grundlage der folgenden Daten
| Jede Zeile enthält 3 Felder: limit, coeffR und coeffN. Um die Steuer I zu berechnen, suchen Sie die erste Zeile, in der QF <= limit ist. Wenn beispielsweise QF = 30000 ist, lautet die gefundene Zeile: 31810 0,2 3309,5. Die Steuer I ist dann gleich 0,2*R – 3309,5*nbParts. Wenn QF so ist, dass die Bedingung QF <= limit nie erfüllt ist, werden die Koeffizienten aus der letzten Zeile verwendet: 0 0,65 49062, was die Steuer I = 0,65*R – 49062*nbParts ergibt. |
4.2. Die Datenbank
Die vorstehenden Daten sind in einer MySQL-Datenbank namens dbimpots gespeichert. Der Benutzer seldbimpots mit dem Passwort mdpseldbimpots hat Lesezugriff auf den Inhalt der Datenbank. Die Datenbank enthält eine einzige Tabelle namens impots mit folgender Struktur:

Ihr Inhalt lautet wie folgt:

4.3. Die MVC-Architektur der Anwendung
Die Anwendung wird die folgende MVC-Architektur aufweisen:
![]() |
- Der Controller „main.php“ ist der oben beschriebene generische Controller
- Die Anfrage des Clients wird in Form einer Abfrage im Format main.php?action=xx an den Controller gesendet. Der Wert des Parameters „action“ bestimmt, welches Skript im Block „ACTIONS“ ausgeführt werden soll. Das ausgeführte Aktionsskript gibt eine Variable an den Controller zurück, die den Zustand angibt, in den die Webanwendung versetzt werden soll. Mit diesem Zustand aktiviert der Controller einen der View-Generatoren, um die Antwort an den Client zu senden.
- „impots-data.php“ ist die Klasse, die dafür zuständig ist, dem Controller die benötigten Daten zur Verfügung zu stellen
- impots-calcul.php ist die Business-Logik-Klasse, die die Steuer berechnet
4.4. Die Datenzugriffsklasse
Die Datenzugriffsklasse dient dazu, die Datenquelle vor der Webanwendung zu verbergen. Ihre Schnittstelle enthält eine getData-Methode, die die drei zur Berechnung der Steuer benötigten Daten-Arrays zurückgibt. In unserem Beispiel werden die Daten aus einer MySQL-Datenbank abgerufen. Um die Klasse vom tatsächlichen DBMS-Typ unabhängig zu machen, verwenden wir die im Anhang beschriebene pear::DB-Bibliothek. Der Klassencode lautet wie folgt:
<?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
?>
Ein Testprogramm könnte wie folgt aussehen:
<?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
?>
Die Ausführung dieses Testprogramms liefert folgende Ergebnisse:
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. Die Steuerberechnungsklasse
Diese Klasse dient zur Berechnung der Steuer eines Steuerpflichtigen. Die für diese Berechnung erforderlichen Daten werden an ihren Konstruktor übergeben. Anschließend berechnet sie die entsprechende Steuer. Der Klassencode lautet wie folgt:
<?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
?>
Ein Testprogramm könnte wie folgt aussehen:
<?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
?>
Die Ausführung dieses Testprogramms liefert folgende Ergebnisse:
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. So funktioniert die Anwendung
Beim Starten des webbasierten Steuerrechners erscheint die folgende [v-form]-Ansicht:
![]() |
Der Benutzer füllt die Felder aus und fordert die Steuerberechnung an:
![]() |
Beachten Sie, dass das Formular in dem Zustand neu generiert wird, in dem der Benutzer es übermittelt hat, und auch den fälligen Steuerbetrag anzeigt. Der Benutzer kann Fehler bei der Dateneingabe machen. Diese werden durch eine Fehlerseite markiert, die wir als [v-errors]-Ansicht bezeichnen.
![]() |
![]() |
Über den Link [Zurück zum Eingabeformular] kann der Benutzer zu dem Formular zurückkehren, das er gerade übermittelt hat.
![]() |
Schließlich setzt die Schaltfläche [Formular löschen] das Formular in seinen Ausgangszustand zurück, d. h. in den Zustand, in dem der Benutzer es bei der ersten Anfrage erhalten hat.
4.7. Zurück zur MVC-Architektur der Anwendung
Die Anwendung verfügt über die folgende MVC-Architektur:
![]() |
Wir haben soeben die beiden Klassen impots-data.php und impots-calcul.php beschrieben. Nun werden wir die anderen Elemente der Architektur beschreiben.
4.8. Der Anwendungscontroller
Der Controller main.php der Anwendung ist derjenige, der im ersten Teil dieses Kapitels beschrieben wurde. Es handelt sich um einen generischen Controller, der unabhängig von der Anwendung ist.
<?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. Aktionen der Webanwendung
Es gibt vier Aktionen:
- get:init: Dies ist die Aktion, die bei der ersten Anfrage an den Controller ohne Parameter ausgelöst wird. Sie rendert die leere „Form“-Ansicht.
- post:clearform: Diese Aktion wird durch die Schaltfläche [Formular löschen] ausgelöst. Sie rendert die leere [v-form]-Ansicht.
- post:calculateTax: Aktion, die durch die Schaltfläche [Steuer berechnen] ausgelöst wird. Sie generiert entweder die Ansicht [v-form] mit dem fälligen Steuerbetrag oder die Ansicht [v-errors].
- get:returnform: Aktion, die durch den Link [Zurück zum Eingabeformular] ausgelöst wird. Sie rendert die Ansicht [v-form], die bereits mit den falschen Daten vorbelegt ist.
Diese Aktionen sind in der Konfigurationsdatei wie folgt konfiguriert:
<?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');
Jede Aktion ist mit dem Skript verknüpft, das für ihre Verarbeitung zuständig ist. Jede Aktion versetzt die Webanwendung in einen Zustand, der durch das Element $dSession['state']['main'] definiert ist. Dieser Zustand soll in der Sitzung gespeichert werden. Zusätzlich speichert die Aktion im $dResponse-Wörterbuch die Informationen, die zur Anzeige der Ansicht benötigt werden, die mit dem neuen Zustand der Anwendung verknüpft ist.
4.10. Zustände der Webanwendung
Es gibt zwei:
[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.
Die in diesen Zuständen zulässigen Aktionen sind wie folgt:
<?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 einem Status entsprechen die zulässigen Aktionen den Ziel-URLs der Links oder [submit]-Schaltflächen in der diesem Status zugeordneten Ansicht. Zusätzlich ist die Aktion 'get:init' immer zulässig. Dies ermöglicht es dem Benutzer, die URL main.php aus der Adressleiste seines Browsers abzurufen und sie unabhängig vom Status der Anwendung neu zu laden. Dies ist eine Art „manueller“ Reset. Der Status 'sansetat' existiert nur beim Start der Anwendung.
Jeder Anwendungszustand ist mit einem Skript verknüpft, das für die Generierung der diesem Zustand zugeordneten Ansicht zuständig ist:
- Zustand [e-form]: Skript e-formulaire.php
- Zustand [e-errors]: Skript e-errors.php
Der Zustand [e-form] zeigt die Ansicht [v-form] mit verschiedenen Varianten an. Tatsächlich kann die Ansicht [v-form] leer, vorausgefüllt oder mit dem Steuerbetrag angezeigt werden. Die Aktion, die die Anwendung in den Zustand [e-form] versetzt, legt den Hauptzustand der Anwendung in der Variablen $dSession['state']['main'] fest. Der Controller verwendet ausschließlich diese Information. In unserer Anwendung fügt die Aktion, die zum Zustand [e-form] führt, zusätzliche Informationen zu $dSession['state']['secondary'] hinzu, sodass der Antwortgenerator weiß, ob er ein leeres Formular, ein vorausgefülltes Formular oder ein Formular mit oder ohne Steuerbetrag generieren soll. Wir hätten einen anderen Ansatz wählen können, indem wir davon ausgegangen wären, dass es drei verschiedene Zustände und somit drei zu schreibende Ansichtsgeneratoren gäbe.
4.11. Die Konfigurationsdatei „config.php“ für die Webanwendung
<?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. Aktionen in Webanwendungen
4.12.1. Allgemeine Funktionsweise von Aktionsskripten
- Ein Aktionsskript wird vom Controller auf der Grundlage des vom Client empfangenen Aktionsparameters aufgerufen.
- Nach der Ausführung muss das Aktionsskript dem Controller mitteilen, in welchen Zustand die Anwendung versetzt werden soll. Dieser Zustand muss in $dSession['etat']['principal'] angegeben werden.
- Ein Aktionsskript möchte möglicherweise Informationen in der Sitzung speichern. Dazu legt es diese Informationen im $dSession-Wörterbuch ab, das vom Controller am Ende des Anfrage-Antwort-Zyklus automatisch in der Sitzung gespeichert wird.
- Ein Aktionsskript kann Informationen enthalten, die an Ansichten weitergegeben werden sollen. Dieser Aspekt ist unabhängig vom Controller. Es handelt sich um die Schnittstelle zwischen Aktionen und Ansichten, eine für jede Anwendung spezifische Schnittstelle. In dem hier behandelten Beispiel stellen Aktionen Informationen über ein Dictionary namens $dResponse für View-Generatoren bereit.
4.12.2. Die Aktion get:init
Dies ist die Aktion, die das leere Formular generiert. Die Konfigurationsdatei zeigt, dass sie vom Skript a-init.php verarbeitet wird:
Der Code für das Skript a-init.php lautet wie folgt:
<?php
// the input form is displayed
$dSession['etat']=array('principal'=>'e-formulaire', 'secondaire'=>'init');
?>
Dieses Skript legt lediglich den Zustand fest, in dem sich die Anwendung befinden soll – den Zustand [e-formulaire] – in $dSession['etat']['principal'], und liefert eine Beschreibung dieses Zustands in $dSession['etat']['secondaire']. Die Konfigurationsdatei zeigt uns, dass der Controller das Skript e-formulaire.php ausführt, um die Antwort an den Client zu generieren.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Das Skript e-formulaire.php generiert die Ansicht [v-formulaire] in ihrer Variante [init], d. h. das leere Formular.
4.12.3. Die Aktion post:calculateTax
Dies ist die Aktion, die die Steuer auf der Grundlage der im Formular eingegebenen Daten berechnet. Die Konfigurationsdatei legt fest, dass das Skript a-calculimpot.php diese Aktion ausführt:
Der Code für das Skript a-calculimpot.php lautet wie folgt:
<?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
Das Skript tut, was es tun soll: die Steuer berechnen. Wir überlassen es dem Leser, den Verarbeitungscode zu entschlüsseln. Uns interessieren die Zustände, die als Ergebnis dieser Aktion auftreten können:
- Die eingegebenen Daten sind falsch oder es gibt ein Problem beim Zugriff auf die Daten: Die Anwendung wird in den Zustand [e-errors] versetzt. Die Konfigurationsdatei zeigt, dass das Skript e-errors.php für die Generierung der Antwortansicht zuständig ist:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
- In allen anderen Fällen wird die Anwendung in den Status [e-form] versetzt, wobei die in $dSession['state']['secondary'] angegebene Steuerberechnungsvariante verwendet wird. Aus der Konfigurationsdatei geht hervor, dass das Skript e-formulaire.php die Antwortansicht generiert. Es verwendet den Wert von $dSession['state']['secondary'], um ein vorausgefülltes Formular mit den vom Benutzer eingegebenen Werten und dem Steuerbetrag zu erstellen.
4.12.4. Die Aktion post:effacerformulaire
Sie ist per Konfiguration mit dem bereits beschriebenen Skript a-init.php verknüpft.
4.12.5. Die Aktion get:return-form
Sie ermöglicht es Ihnen, vom Status [e-errors] zum Status [e-form] zurückzukehren. Das Skript a-retourformulaire.php verarbeitet diese Aktion:
Das Skript a-retourformulaire.php sieht wie folgt aus:
<?php
// the input form is displayed
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'retourformulaire');
?>
Wir fordern lediglich, dass die Anwendung in ihrer Variante [form-return] auf den Status [e-form] gesetzt wird. Die Konfigurationsdatei zeigt uns, dass der Controller das Skript e-form.php ausführt, um die Antwort an den Client zu generieren.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Das Skript e-formulaire.php generiert die Ansicht [v-formulaire] in ihrer Variante [retourformulaire], d. h. das Formular, das mit den vom Benutzer eingegebenen Werten vorausgefüllt ist, jedoch ohne den Steuerbetrag.
4.13. Ungültige Aktionssequenz
Die gültigen Aktionen aus einem bestimmten Zustand der Anwendung werden durch die Konfiguration festgelegt:
<?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'));
Wir haben diese Konfiguration bereits erläutert. Wird eine ungültige Abfolge von Aktionen erkannt, wird das Skript a-invalid-sequence.php ausgeführt:
Der Code für dieses Skript lautet wie folgt:
<?php
// invalid sequence of actions
$dReponse['erreurs']=array("Enchaînement d'actions invalide");
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'enchainementinvalide');
?>
Dies versetzt die Anwendung in den Status [e-errors]. Wir stellen in $dSession['state']['secondary'] Informationen bereit, die vom Fehlerseitengenerator verwendet werden. Wie wir bereits gesehen haben, ist dieser Generator e-errors.php:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
Wir werden uns den Code für diesen Generator später ansehen. Die an den Client gesendete Ansicht sieht wie folgt aus:

4.14. Die Ansichten der Anwendung
4.14.1. Anzeige der endgültigen Ansicht
Schauen wir uns an, wie der Controller die Antwort an den Client sendet, sobald die vom Client angeforderte Aktion ausgeführt wurde:
<?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
Nach der Rückkehr aus einem Aktionsskript ruft der Controller den Zustand, in den er die Anwendung versetzen muss, aus $dSession['etat']['principal'] ab. Dieser Zustand wurde von der gerade ausgeführten Aktion festgelegt. Der Controller führt dann den mit diesem Zustand verbundenen View-Generator aus. Er findet den Namen des View-Generators in der Konfigurationsdatei. Die Rolle des View-Generators ist wie folgt:
- Legt den Namen der zu verwendenden Antwortvorlage in $dResponse['responseView'] fest. Diese Information wird an den Controller übergeben. Eine Vorlage ist eine Zusammensetzung aus Basisansichten, die zusammen die endgültige Ansicht bilden.
- Bereitet die dynamischen Informationen vor, die in der endgültigen Ansicht angezeigt werden sollen. Dieser Schritt ist unabhängig vom Controller. Er dient als Schnittstelle zwischen dem View-Generator und der endgültigen Ansicht. Er ist spezifisch für jede Anwendung.
- muss mit einem Aufruf der Funktion finSession des Controllers enden. Diese Funktion
- speichert die Sitzung
- die Antwort senden
Der Code für die Funktion finSession lautet wie folgt:
<?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
Die an den Benutzer gesendete Ansicht wird durch die Entität $dResponse['responseView'] definiert, die die für die endgültige Antwort zu verwendende Vorlage festlegt.
4.14.2. Antwortvorlage
Die Anwendung generiert ihre verschiedenen Antworten auf der Grundlage der folgenden einzigen Vorlage:
![]() |
Diese Vorlage ist mit dem Schlüssel „modele1“ im Wörterbuch $dConfig['vuesreponse'] verknüpft:
Das Skript m-reponse.php ist für die Generierung dieser Vorlage zuständig:
<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>
Dieses Skript enthält drei dynamische Elemente, die in einem Wörterbuch $dReponse gespeichert sind und den folgenden Schlüsseln zugeordnet sind:
- urlstyle: URL des Stylesheets der Vorlage
- view1: Name des Skripts, das für die Generierung der Ansicht „view1“ zuständig ist
- vue2: Name des Skripts, das für die Generierung der Ansicht „vue2“ zuständig ist
Ein View-Generator, der die Vorlage modèle1 verwenden möchte, muss diese drei dynamischen Elemente definieren. Wir definieren nun die Basis-Views, die die Elemente [vue1] und [vue2] in der Vorlage ersetzen können.
4.14.3. Die Basisansicht v-bandeau.php
Das Skript v-bandeau.php generiert eine Ansicht, die im Bereich [vue1] platziert wird:
<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>
Der View-Generator muss zwei dynamische Elemente definieren, die in einem Dictionary $dResponse abgelegt und den folgenden Schlüsseln zugeordnet sind:
title: title to display
result: amount of tax due
4.14.4. Die Basisansicht v-form.php
Der Abschnitt [vue2] entspricht entweder der Ansicht [v-form] oder der Ansicht [v-errors]. Die Ansicht [v-form] wird durch das Skript v-formulaire.php generiert:
<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>
Die dynamischen Teile dieser Ansicht, die vom View-Generator definiert werden müssen, sind im $dReponse-Wörterbuch den folgenden Schlüsseln zugeordnet:
- optoui: Status des Optionsfelds mit dem Namen optoui
- optnon: Status des Optionsfelds mit dem Namen optnon
- children: Anzahl der Kinder, die in das Feld txtenfants eingefügt werden sollen
- salary: Jahresgehalt, das in das Feld txtsalary eingefügt werden soll
4.14.5. Die Basisansicht v-erreurs.php
Die Ansicht [v-errors] wird durch das Skript v-errors.php generiert:
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>
Die dynamischen Teile dieser Ansicht, die vom View-Generator definiert werden, sind mit den folgenden Schlüsseln im $dReponse-Dictionary verknüpft:
- errors: Array mit Fehlermeldungen
- info: Informationsmeldung
- link: Text eines Links
- href: Ziel-URL des obigen Links
4.14.6. Das Stylesheet
Alle Ansichten werden durch ein Stylesheet gestaltet. Um das Erscheinungsbild der Anwendung zu ändern, bearbeiten Sie das Stylesheet. Das folgende Stylesheet 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. Generatoren anzeigen
4.15.1. Die Rolle eines View-Generators
Sehen wir uns den Controller-Codeausschnitt an, der einen View-Generator ausführt:
<?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;
Ein View-Generator ist mit dem Zustand verknüpft, in dem die Anwendung platziert wird. Die Verknüpfung zwischen dem Zustand und dem View-Generator wird über die Konfiguration festgelegt:
<?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'));
Wir haben die Rolle eines View-Generators bereits erläutert. Lassen Sie uns dies hier noch einmal zusammenfassen. Ein View-Generator:
- legt den Namen der zu verwendenden Antwortvorlage in $dResponse['responseView'] fest. Diese Information wird an den Controller übergeben. Eine Vorlage ist eine Zusammensetzung aus Basisansichten, die zusammen die endgültige Ansicht bilden.
- bereitet die dynamischen Informationen vor, die in der endgültigen Ansicht angezeigt werden sollen. Dieser Schritt ist unabhängig vom Controller. Er dient als Schnittstelle zwischen dem View-Generator und der endgültigen Ansicht. Er ist spezifisch für jede Anwendung.
- muss mit einem Aufruf der Funktion finSession des Controllers enden. Diese Funktion
- speichert die Sitzung
- die Antwort senden
4.15.2. Der mit dem [e-form]-Zustand verbundene View-Generator
Das Skript, das für die Generierung der mit dem [e-form]-Zustand verbundenen Ansicht zuständig ist, heißt e-form.php:
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Der Code lautet wie folgt:
<?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);
?>
Beachten Sie, dass der View-Generator die Anforderungen an einen View-Generator erfüllt:
- Legen Sie die zu verwendende Antwortvorlage in $dResponse['vuereponse'] fest
- Informationen an diese Vorlage übergeben. Hier erfolgt die Übergabe über das $dResponse-Dictionary.
- Beenden Sie den Vorgang durch Aufruf der Funktion `finSession` des Controllers
Hier wird die Vorlage „template1“ verwendet. Daher definiert der View-Generator die beiden von dieser Vorlage benötigten Informationen: $dResponse['view1'] und $dResponse['view2'].
Im konkreten Fall unserer Anwendung hängt die mit dem Zustand [e-form] verbundene Ansicht von den in der Variablen $dSession['etat']['secondaire'] gespeicherten Informationen ab. Dies ist eine Designentscheidung. Eine andere Anwendung könnte sich dafür entscheiden, zusätzliche Informationen auf andere Weise zu übergeben. Darüber hinaus werden hier alle zur Anzeige der endgültigen Ansicht benötigten Informationen im $dResponse-Dictionary abgelegt. Auch dies ist eine Entscheidung, die dem Entwickler überlassen bleibt. Der [e-form]-Zustand kann nach vier verschiedenen Aktionen auftreten: init, calculateTax, returnForm, clearForm. Die anzuzeigende Ansicht ist nicht in allen Fällen genau gleich. Daher haben wir hier in $dSession['state']['secondary'] drei Fälle unterschieden:
- init: Das Formular wird leer angezeigt
- calculateTax: Das Formular wird mit dem Steuerbetrag und den zur Berechnung verwendeten Daten angezeigt
- returnform: Das Formular wird mit den ursprünglich eingegebenen Daten angezeigt
Oben nutzt das Skript e-formulaire.php diese Informationen, um die Antwort entsprechend diesen drei Varianten darzustellen.
4.15.3. Die Ansicht, die dem Status [e-errors] zugeordnet ist
Das Skript, das für die Generierung der Ansicht für den Status [e-errors] zuständig ist, heißt e-errors.php und sieht wie folgt aus:
<?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. Anzeige der endgültigen Ansicht
Beide Skripte, die die beiden endgültigen Ansichten generieren, enden mit einem Aufruf der finSession-Funktion des Controllers:
<?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
Die an den Benutzer gesendete Ansicht wird durch die Entität $dResponse['responseView'] definiert, die die für die endgültige Antwort zu verwendende Vorlage angibt. Für die Zustände [e-form] und [e-errors] wurde diese Vorlage auf template1 gesetzt:
Diese Vorlage entspricht dem Skript m-reponse.php:
4.16. Ändern der Antwortvorlage
Wir gehen hier davon aus, dass wir das visuelle Erscheinungsbild der an den Client gesendeten Antwort ändern möchten, und möchten verstehen, welche Auswirkungen dies auf den Code hat.
4.16.1. Die neue Vorlage
Die Struktur der Antwort sieht nun wie folgt aus:
![]() |
Diese Vorlage wird template2 heißen, und das Skript, das für die Generierung dieser Vorlage zuständig ist, wird m-response2.php heißen:
Das zu dieser Vorlage gehörende Skript lautet wie folgt:
<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>
Die dynamischen Elemente der Vorlage lauten wie folgt:
- $dReponse['urlstyle']: das zu verwendende Stylesheet
- $dReponse['vue1']: das Skript, das zur Generierung von [vue1] verwendet werden soll
- $dReponse['vue2']: das Skript, das zur Generierung von [vue2] verwendet werden soll
- $dReponse['vue3']: das Skript, das zur Generierung von [vue3] verwendet werden soll
Diese Elemente müssen von den View-Generatoren festgelegt werden.
4.16.2. Die verschiedenen Antwortseiten
Die Anwendung zeigt dem Benutzer nun die folgenden Antworten an. Beim ersten Aufruf sieht die Antwortseite wie folgt aus:
![]() |
Wenn der Benutzer gültige Daten eingibt, wird die Steuer berechnet:
![]() |
Bei Eingabefehlern wird die Fehlerseite angezeigt:
![]() |
Wenn sie den Link [Zurück zum Eingabeformular] verwenden, wird das Formular so angezeigt, wie sie es zuletzt übermittelt haben:
![]() |
Wenn sie im oben genannten Szenario den Link [Formular zurücksetzen] verwenden, wird ein leeres Formular angezeigt:
![]() |
Beachten Sie, dass die Anwendung dieselben Aktionen wie zuvor verwendet. Lediglich die Darstellung der Antworten hat sich geändert.
4.16.3. Grundansichten
Die Basisansicht [view1] wird wie im vorherigen Beispiel mit dem Skript v-bandeau.php verknüpft:
<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>
Diese Ansicht enthält zwei dynamische Elemente:
- $dResponse['title']: anzuzeigender Titel
- $dResponse['resultat']: Höhe der fälligen Steuer
Die Basisansicht [vue2] wird mit dem folgenden Skript v-menu.php verknüpft:
<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>
Diese Ansicht enthält die folgenden dynamischen Elemente:
- $dResponse['links']: Array mit Links, die in [view2] angezeigt werden sollen. Jedes Element des Arrays ist ein Dictionary mit zwei Schlüsseln:
- 'url': die Ziel-URL des Links
- 'text': Linktext
Die Basisansicht [view3] wird mit dem Skript v-form2.php verknüpft, wenn Sie das Eingabeformular anzeigen möchten, oder mit dem Skript v-errors2.php, wenn Sie die Fehlerseite anzeigen möchten. Der Code für das Skript v-form2.php lautet wie folgt:
<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>
Die dynamischen Teile dieser Ansicht, die vom View-Generator definiert werden müssen, sind im $dResponse-Wörterbuch den folgenden Schlüsseln zugeordnet:
- optoui: Status des Optionsfelds mit dem Namen optoui
- optnon: Status des Optionsfelds mit dem Namen optnon
- children: Anzahl der Kinder, die in das Feld txtenfants eingefügt werden sollen
- salaire: Jahresgehalt, das in das Feld txtsalaire eingefügt werden soll
Das Skript, das die Fehlerseite generiert, heißt v-erreurs2.php. Sein Code lautet wie folgt:
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>
Die dynamischen Teile dieser Ansicht, die vom View-Generator definiert werden sollen, sind mit den folgenden Schlüsseln im $dReponse-Dictionary verknüpft:
errors: array of error messages
info: information message
4.16.4. Das Stylesheet
Es hat sich nichts geändert. Es ist weiterhin style1.css.
4.16.5. Die neue Konfigurationsdatei
Um diese neuen Ansichten zu implementieren, müssen wir bestimmte Zeilen in der Konfigurationsdatei ändern.
<?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"
);
?>
Die wichtigste Änderung betrifft die Aktualisierung der mit den Berichten [e-form] und [e-errors] verbundenen View-Generatoren. Sobald dies geschehen ist, sind die neuen View-Generatoren für die Erstellung der neuen Antwortseiten zuständig.
4.16.6. Der mit dem [e-form]-Bericht verknüpfte View-Generator
In der Konfigurationsdatei ist der Status [e-form] nun mit dem View-Generator e-form2.php verknüpft. Der Code für dieses Skript lautet wie folgt:
<?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);
?>
Die wichtigsten Änderungen sind folgende:
- Der View-Generator gibt an, dass er die Antwortvorlage modele2 verwenden möchte
- aus diesem Grund füllt er die dynamischen Elemente $dResponse['vue1'], $dResponse['vue2'], $dResponse['vue3'], die alle drei von der Antwortvorlage modele2 benötigt werden.
- Der View-Generator füllt außerdem das dynamische Element $dResponse['links'] auf, das die Links festlegt, die im Bereich [view2] der Antwort angezeigt werden sollen.
4.16.7. Der dem Status [e-errors] zugeordnete View-Generator
In der Konfigurationsdatei ist der Zustand [e-errors] nun dem View-Generator e-errors2.php zugeordnet. Der Code für dieses Skript lautet wie folgt:
<?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);
?>
Die vorgenommenen Änderungen entsprechen denen am View-Generator e-formulaire2.php.
4.17. Fazit
Anhand eines Beispiels konnten wir die Vorteile unseres generischen Controllers aufzeigen. Wir mussten ihn nicht selbst schreiben. Wir haben lediglich die Aktionsskripte, View-Generatoren und Views für die Anwendung geschrieben. Außerdem haben wir die Vorteile der Trennung von Aktionen und Views demonstriert. Dadurch konnten wir das Erscheinungsbild der Antworten ändern, ohne auch nur eine einzige Zeile Code in den Aktionsskripten zu ändern. Es wurden lediglich die Skripte geändert, die an der View-Generierung beteiligt sind. Damit dies möglich ist, darf das Aktionsskript keine Annahmen über die Ansicht treffen, die die von ihm berechneten Informationen anzeigen wird. Es muss diese Informationen lediglich an den Controller zurückgeben, der sie zur Formatierung an den View-Generator weiterleitet. Dies ist eine unumstößliche Regel: Eine Aktion muss vollständig von den Ansichten entkoppelt sein.
In diesem Kapitel haben wir die Struts-Philosophie untersucht, die Java-Entwicklern wohlbekannt ist. Ein Open-Source-Projekt namens php.mvc ermöglicht die Web-/PHP-Entwicklung nach der Struts-Philosophie. Weitere Informationen finden Sie unter http://www.phpmvc.net/.













