4. Ein anschauliches Beispiel
Wir möchten die vorstehende Methode anhand eines Beispiels zur Steuerberechnung veranschaulichen.
4.1. Die Aufgabe
Wir wollen ein Programm schreiben, mit dem sich die Steuer eines Steuerpflichtigen berechnen lässt. Wir betrachten den vereinfachten Fall eines Steuerpflichtigen, der nur sein Gehalt anzugeben hat:
- Wir berechnen die Anzahl der Steueranteile des Arbeitnehmers nbParts = nbEnfants/2 + 1, wenn er unverheiratet ist, nbEnfants/2+2, wenn er verheiratet ist, wobei nbEnfants die Anzahl seiner Kinder ist. Die Anzahl der Anteile wird um 0,5 erhöht, wenn drei oder mehr Kinder vorhanden sind.
- Man berechnet sein zu versteuerndes Einkommen R = 0,72 * S, wobei S sein Jahresgehalt ist
- Man berechnet seinen Familienkoeffizienten Q = R/N
- Man berechnet seine Steuer I anhand der folgenden Daten
| Jede Zeile enthält drei Grenzwerte: coeffR, coeffN. Um die Steuer I zu berechnen, wird die erste Zeile gesucht, in der QF ≤ dem Grenzwert ist. Wenn beispielsweise QF = 30000 ist, wird folgende Zeile gefunden: 31810 0,2 3309,5. Die Steuer I beträgt dann 0,2*R – 3309,5*nbParts. Ist QF so gewählt, dass die Beziehung QF <= Grenzwert niemals erfüllt ist, werden die Koeffizienten der letzten Zeile verwendet: 0 0,65 49062, was die Steuer I = 0,65 * R ergibt – 49062 * nbParts ergibt. |
4.2. Die Datenbank
Die oben genannten Daten werden in einer Datenbank mit dem Namen MySQL namens „dbimpots“ gespeichert. Der Benutzer „seldbimpots“ mit dem Passwort „mdpseldbimpots“ hat Lesezugriff auf den Inhalt der Datenbank. Diese enthält eine einzige Tabelle namens „impots“, deren Struktur wie folgt aussieht:

Ihr Inhalt lautet wie folgt:

4.3. Die Architektur MVC der Anwendung
Die Anwendung wird die folgende Architektur „MVC“ aufweisen:
![]() |
- Der Controller main.php ist der zuvor vorgestellte generische Controller
- Die Anfrage des Kunden wird in Form einer Anfrage mit dem Format main.php?action=xx an den Controller gesendet. Der Wert des Parameters „action“ bestimmt das auszuführende Skript des Blocks ACTIONS. Das ausgeführte Aktionsskript gibt dem Controller eine Variable 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 dem Controller die benötigten Daten bereitstellt
- impots-calcul.php ist die Fachklasse, die die Berechnung der Steuer ermöglicht
4.4. Die Datenzugriffsklasse
Die Datenzugriffsklasse dient dazu, die Herkunft der Daten vor der Webanwendung zu verbergen. In ihrer Schnittstelle findet sich eine Methode getData, die die drei für die Steuerberechnung erforderlichen Datenarrays bereitstellt. In unserem Beispiel werden die Daten aus einer Datenbank MySQL abgerufen. Um die Klasse vom tatsächlichen Typ der Datenbank SGBD unabhängig zu machen, verwenden wir die im Anhang beschriebene Bibliothek pear::DB. Der Code der Klasse lautet wie folgt:
<?php
// Bibliotheken
require_once 'DB.php';
class impots_data{
// Zugriffsklasse auf die Datenquelle DBIMPOTS
// Attribute
var $sDSN; // die Verbindungszeichenfolge
var $sDatabase; // Name der Datenbank
var $oDB; // Verbindung zur Datenbank
var $aErreurs; // Fehlerliste
var $oRésultats; // Ergebnis einer Abfrage
var $connecté; // Boolescher Wert, der angibt, ob eine Verbindung zur Datenbank besteht oder nicht
var $sQuery ; // die zuletzt ausgeführte Abfrage
// Konstruktor
function impots_data($dDSN){
// $dDSN: Dictionary, das die herzustellende Verbindung definiert
// $dDSN['sgbd']: der Typ des SGBD, mit dem eine Verbindung hergestellt werden soll
// $dDSN['host']: Name des Host-Rechners, auf dem es gehostet wird
// $dDSN['database']: der Name der Datenbank, mit der eine Verbindung hergestellt werden soll
// $dDSN['user']: ein Benutzer der Datenbank
// $dDSN['mdp']: sein Passwort
// erstellt in $oDB eine Verbindung zur Datenbank, die durch $dDSN definiert ist, unter der Identität von $dDSN['user']
// wenn die Verbindung erfolgreich hergestellt wurde
// speichert in $sDSN die Verbindungszeichenfolge zur Datenbank
// speichert den Namen der Datenbank, mit der eine Verbindung hergestellt wird, in $sDataBase
// setzt $connecté auf „wahr“
// falls die Verbindung fehlschlägt
// trägt die entsprechenden Fehlermeldungen in die Liste $aErreurs ein
// schließt die Verbindung bei Bedarf
// setzt $connecté auf „falsch“
// löscht die Fehlerliste
$this->aErreurs=array();
// Es wird eine Verbindung zur Datenbank $sDSN hergestellt
$this->sDSN=$dDSN["sgbd"]."://".$dDSN["user"].":".$dDSN["mdp"]."@".$dDSN["host"]."/".$dDSN["database"];
$this->sDatabase=$dDSN["database"];
$this->connect();
// Verbunden?
if( ! $this->connecté) return;
// Die Verbindung wurde erfolgreich hergestellt
$this->connecté=TRUE;
}//Hersteller
// ------------------------------------------------------------------
function connect(){
// (Wieder-)Verbindung zur Datenbank
// Fehlerliste zurücksetzen
$this->aErreurs=array();
// Es wird eine Verbindung zur Datenbank hergestellt $sDSN
$this->oDB=DB::connect($this->sDSN,true);
// Fehler?
if(DB::iserror($this->oDB)){
// Fehler wird protokolliert
$this->aErreurs[]="Echec de la connexion à la base [".$this->sDatabase."] : [".$this->oDB->getMessage()."]";
// Die Verbindung ist fehlgeschlagen
$this->connecté=FALSE;
// Ende
return;
}
// Verbindung hergestellt
$this->connecté=TRUE;
}//Verbinden
// ------------------------------------------------------------------
function disconnect(){
// Wenn eine Verbindung besteht, wird die Verbindung zur Basisstation getrennt $sDSN
if($this->connecté){
$this->oDB->disconnect();
// Man ist nicht verbunden
$this->connecté=FALSE;
}//if
}//Verbindung trennen
// -------------------------------------------------------------------
function execute($sQuery){
// $sQuery: auszuführende Abfrage
// Die Anfrage wird gespeichert
$this->sQuery=$sQuery;
// Sind wir angemeldet?
if(! $this->connecté){
// Der Fehler wird vermerkt
$this->aErreurs[]="Pas de connexion existante à la base [$this->sDatabase]";
// Ende
return;
}//if
// Abfrage ausführen
$this->oRésultats=$this->oDB->query($sQuery);
// Fehler?
if(DB::iserror($this->oRésultats)){
// Der Fehler wird vermerkt
$this->aErreurs[]="Echec de la requête [$sQuery] : [".$this->oRésultats->getMessage()."]";
// Zurück
return;
}//if
}//ausführen
// ------------------------------------------------------------------
function getData(){
// Die drei Datensätze „limites“, „coeffr“ und „coeffn“ werden abgerufen
$this->execute('select limites, coeffR, coeffN from impots');
// Gibt es Fehler?
if(count($this->aErreurs)!=0) return array();
// Das Ergebnis der SELECT-Anweisung wird durchlaufen
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
}//Klasse
?>
Ein Testprogramm könnte wie folgt aussehen:
<?php
// Bibliothek
require_once "c-impots-data.php";
require_once "DB.php";
// Test der Klasse „impots-data“
ini_set('track_errors','on');
ini_set('display_errors','on');
// Grundkonfiguration von dbimpots
$dDSN=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
// Anmeldung
$oImpots=new impots_data($dDSN);
// Fehler?
if(checkErreurs($oImpots)){
exit(0);
}
// Nachverfolgung
echo "Connecté à la base...\n";
// Abruf der Grenzwerte, Koeffizienten „coeffr“ und „coeffn“
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// Fehler?
if( ! checkErreurs($oImpots)){
// Inhalt
echo "données : \n";
for($i=0;$i<count($limites);$i++){
echo "[$limites[$i],$coeffr[$i],$coeffn[$i]]\n";
}//für
}//if
// Die Verbindung wird getrennt
$oImpots->disconnect();
// Weiterverfolgung
echo "Déconnecté de la base...\n";
// Ende
exit(0);
// ----------------------------------
function checkErreurs(&$oImpots){
// Fehler?
if(count($oImpots->aErreurs)!=0){
// Anzeige
for($i=0;$i<count($oImpots->aErreurs);$i++){
echo $oImpots->aErreurs[$i]."\n";
}//für
// Fehler
return true;
}//if
// keine Fehler
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 Klasse zur Steuerberechnung
Diese Klasse dient zur Berechnung der Steuer eines Steuerpflichtigen. Dem Konstruktor werden die für diese Berechnung erforderlichen Daten übergeben. Anschließend berechnet er die entsprechende Steuer. Der Code der Klasse lautet wie folgt:
<?php
class impots_calcul{
// Steuerberechnungsklasse
// Konstruktor
function impots_calcul(&$perso,&$data){
// $perso: Wörterbuch mit folgenden Schlüsseln
// Kinder: Anzahl der Kinder
// Gehalt: Jahresgehalt
// verheiratet: Boolescher Wert, der angibt, ob der Steuerpflichtige verheiratet ist oder nicht
// Steuer(n): von diesem Konstruktor berechnete zu zahlende Steuer
// $data: Wörterbuch mit den folgenden Schlüsseln
// Grenzen: Tabelle der Steuerklassengrenzen
// Koeffizienten: Tabelle der Einkommenskoeffizienten
// coeffn: Tabelle der Koeffizienten für die Anzahl der Anteile
// Die drei Tabellen haben die gleiche Anzahl an Elementen
// Berechnung der Anzahl der Anteile
if($perso['marié'])
$nbParts=$perso['enfants']/2+2;
else $nbParts=$perso['enfants']/2+1;
if ($perso['enfants']>=3) $nbParts+=0.5;
// steuerpflichtiges Einkommen
$revenu=0.72*$perso['salaire'];
// Familienquotient
$QF=$revenu/$nbParts;
// Ermittlung der Steuerklasse entsprechend QF
$nbTranches=count($data['limites']);
$i=0;
while($i<$nbTranches-2 && $QF>$data['limites'][$i]) $i++;
// die Steuer
$perso['impot']=floor($data['coeffr'][$i]*$revenu-$data['coeffn'][$i]*$nbParts);
}//Ersteller
}//Klasse
?>
Ein Testprogramm könnte wie folgt aussehen:
<?php
// Bibliothek
require_once "c-impots-data.php";
require_once "c-impots-calcul.php";
// Grundkonfiguration der Steuerdatenbank
$dDSN=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
// Anmeldung
$oImpots=new impots_data($dDSN);
// Fehler?
if(checkErreurs($oImpots)){
exit(0);
}
// Nachverfolgung
echo "Connecté à la base...\n";
// Abruf der Grenzwerte, Koeffr, Koeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// Fehler?
if(checkErreurs($oImpots)){
exit(0);
}
// Abmeldung
$oImpots->disconnect();
// Nachverfolgung
echo "Déconnecté de la base...\n";
// Steuerberechnung
$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);
// Ende
exit(0);
// ----------------------------------
function checkErreurs(&$oImpots){
// Fehler?
if(count($oImpots->aErreurs)!=0){
// Anzeige
for($i=0;$i<count($oImpots->aErreurs);$i++){
echo $oImpots->aErreurs[$i]."\n";
}//für
// Fehler
return true;
}//if
// keine Fehler
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. Funktionsweise der Anwendung
Beim Starten der Web-Anwendung zur Steuerberechnung wird die folgende Ansicht [v-formulaire] angezeigt:
![]() |
Der Benutzer füllt die Felder aus und fordert die Steuerberechnung an:
![]() |
Es ist zu beachten, dass das Formular in dem Zustand neu generiert wird, in dem der Benutzer es bestätigt hat, und dass es zusätzlich den zu zahlenden Steuerbetrag anzeigt. Dem Benutzer können Eingabefehler unterlaufen. Diese werden ihm auf einer Fehlerseite angezeigt, die wir als Ansicht [v-erreurs] bezeichnen.
![]() |
![]() |
Über den Link [Retour au formulaire de saisie] kann der Benutzer das Formular in der von ihm freigegebenen Form aufrufen.
![]() |
Schließlich versetzt die Schaltfläche [Effacer le formulaire] das Formular in seinen ursprünglichen Zustand zurück, c.a.d, so wie der Benutzer es bei der ursprünglichen Anfrage erhalten hat.
4.7. Rückblick auf die Architektur MVC der Anwendung
Die Anwendung weist die folgende Architektur MVC auf:
![]() |
Wir haben soeben die beiden Klassen impots-data.php und impots-calcul.php beschrieben. Nun beschreiben wir die übrigen Elemente der Architektur.
4.8. Der Controller der Anwendung
Der Anwendungscontroller main.php ist derjenige, der im ersten Teil dieses Kapitels beschrieben wurde. Es handelt sich um einen generischen, anwendungsunabhängigen Controller.
<?php
// generischer Controller
// Konfiguration lesen
include 'config.php';
// Einbindung von Bibliotheken
for($i=0;$i<count($dConfig['includes']);$i++){
include($dConfig['includes'][$i]);
}//für
// Starten oder Fortsetzen der Sitzung
session_start();
$dSession=$_SESSION["session"];
if($dSession) $dSession=unserialize($dSession);
// die auszuführende Aktion wird abgerufen
$sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
$sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";
// Ist die Abfolge der Aktionen normal?
if( ! enchainementOK($dConfig,$dSession,$sAction)){
// Ablauf ist nicht normal
$sAction='enchainementinvalide';
}//if
// Verarbeitung der Aktion
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// Senden der Antwort (Ansicht) an den Client
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
// Ende des Skripts – hier sollte man eigentlich nicht hinkommen, es sei denn, es liegt ein Fehler vor
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: Konfigurationswörterbuch
// $dSession: Wörterbuch mit den Sitzungsinformationen
// $dReponse: das Wörterbuch der Argumente der Antwortseite
// Sitzungsprotokoll
if(isset($dSession)){
//: Die Parameter der Anfrage werden in die Sitzung geschrieben
$dSession['requete']=strtolower($_SERVER['REQUEST_METHOD'])=='get' ? $_GET :
strtolower($_SERVER['REQUEST_METHOD'])=='post' ? $_POST : array();
$_SESSION['session']=serialize($dSession);
session_write_close();
}else{
// keine Sitzung
session_destroy();
}
// die Antwort wird angezeigt
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// Ende des Skripts
exit(0);
}//endsession
//--------------------------------------------------------------------
function enchainementOK(&$dConfig,&$dSession,$sAction){
// Prüft, ob die aktuelle Aktion im Hinblick auf den vorherigen Status zulässig ist
$etat=$dSession['etat']['principal'];
if(! isset($etat)) $etat='sansetat';
// Aktionsprüfung
$actionsautorisees=$dConfig['etats'][$etat]['actionsautorisees'];
$autorise= ! isset($actionsautorisees) || in_array($sAction,$actionsautorisees);
return $autorise;
}
//--------------------------------------------------------------------
function dump($dInfos){
// zeigt ein Informationswörterbuch an
while(list($clé,$valeur)=each($dInfos)){
echo "[$clé,$valeur]<br>\n";
}//while
}//Nachverfolgung
//--------------------------------------------------------------------
function trace($msg){
echo $msg."<br>\n";
}//Nachverfolgung
?>
4.9. Die Aktionen der Webanwendung
Es gibt vier Aktionen:
- get:init: Diese Aktion wird bei der ersten Anfrage ohne Parameter an den Controller ausgelöst. Sie generiert die leere Ansicht „Formular“.
- post:effacerformulaire: Diese Aktion wird durch die Schaltfläche [Effacer le formulaire] ausgelöst. Sie generiert die leere Ansicht [v-formulaire].
- post:calculerimpot: Diese Aktion wird durch die Schaltfläche [Calculer l'impôt] ausgelöst. Sie generiert entweder die Ansicht [v-formulaire] mit dem zu zahlenden Steuerbetrag oder die Ansicht [v-erreurs].
- get:retourformulaire: Aktion, die durch den Link [Retour au formulaire de saisie] ausgelöst wird. Sie generiert die Ansicht [v-formulaire], die mit den fehlerhaften Daten vorausgefüllt ist.
Diese Aktionen sind in der Konfigurationsdatei wie folgt eingerichtet:
<?php
…
// Konfiguration der Anwendungsaktionen
$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');
Jeder Aktion ist das Skript zugeordnet, das für ihre Verarbeitung zuständig ist. Jede Aktion versetzt die Webanwendung in einen Zustand, der durch das Element $dSession['etat']['principal'] festgelegt wird. Dieser Zustand soll in der Sitzung gespeichert werden. Darüber hinaus speichert die Aktion im Dictionary $dReponse die Informationen, die für die Anzeige der Ansicht erforderlich sind, die mit dem neuen Zustand der Webanwendung verknüpft ist.
4.10. Die Berichte der Webanwendung
Es gibt zwei davon:
- [e-formulaire]: Bericht, in dem die verschiedenen Varianten der Ansicht [v-formulaire] dargestellt werden.
- [e-erreurs]: Zustand, in dem die Ansicht [v-erreurs] dargestellt wird.
Die in diesen Berichten zulässigen Aktionen sind folgende:
<?php
…
// Konfiguration der Anwendungsberichte
$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 Zielen der Links oder Schaltflächen [submit] in der dem Status zugeordneten Ansicht. Darüber hinaus ist die Aktion „get:init“ stets zulässig. Dadurch kann der Benutzer den URL main.php aus der Liste der URL seines Browsers abrufen und unabhängig vom Status der Anwendung erneut abspielen. Dies ist eine Art „manuelles“ Zurücksetzen. Der Zustand „sansetat“ existiert nur beim Start der Anwendung.
Jedem Zustand der Anwendung ist ein Skript zugeordnet, das die dem Zustand entsprechende Ansicht generiert:
- Zustand [e-formulaire]: Skript e-formulaire.php
- Zustand [e-erreurs]: Skript e-erreurs.php
Der Bericht [e-formulaire] zeigt die Ansicht [v-formulaire] mit verschiedenen Varianten an. So kann die Ansicht [v-formulaire] leer, vorausgefüllt oder mit dem Steuerbetrag angezeigt werden. Die Aktion, die die Anwendung in den Status [e-formulaire] versetzt, legt in der Variablen $dSession['etat']['principal'] den Hauptstatus der Anwendung fest. Der Controller verwendet ausschließlich diese Information. In unserer Anwendung fügt die Aktion, die zum Status [e-formulaire] führt, in $dSession['etat']['secondaire'] eine zusätzliche Information hinzu, anhand derer der Antwortgenerator erkennen kann, ober ein leeres, vorausgefülltes Formular mit oder ohne Steuerbetrag generieren soll. Man hätte auch anders vorgehen können, indem man davon ausgegangen wäre, dass es sich hier um drei verschiedene Zustände handelt und somit drei View-Generatoren zu schreiben wären.
4.11. Die Konfigurationsdatei der Webanwendung config.php
<?php
// PHP-Konfiguration
ini_set("register_globals","off");
ini_set("display_errors","off");
ini_set("expose_php","off");
// Liste der einzubindenden Module
$dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');
// Anwendungs-Controller
$dConfig['webapp']=array('titre'=>"Calculez votre impôt");
// Konfiguration der Ansichten der Anwendung
$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';
// Konfiguration der Anwendungsaktionen
$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');
// Konfiguration der Anwendungsberichte
$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'));
// Konfiguration der Anwendungsvorlage
$dConfig["DSN"]=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
?>
4.12. Aktionen der Webanwendung
4.12.1. Allgemeine Funktionsweise von Aktionsskripten
- Ein Aktionsskript wird vom Controller entsprechend dem Aktionsparameter aufgerufen, den dieser vom Client erhalten hat.
- Nach der Ausführung muss das Aktionsskript dem Controller mitteilen, in welchen Status die Anwendung versetzt werden soll. Dieser Status muss in $dSession['etat']['principal'] angegeben werden.
- Ein Aktionsskript möchte möglicherweise Informationen in die Sitzung einfügen. Dies geschieht, indem diese Informationen in das Wörterbuch $dSession eingefügt werden; dieses Wörterbuch wird am Ende des Anfrage-Antwort-Zyklus vom Controller automatisch in der Sitzung gespeichert.
- Ein Aktionsskript kann Informationen an die Ansichten weitergeben. Dieser Aspekt ist unabhängig vom Controller. Es handelt sich um die Schnittstelle zwischen den Aktionen und den Ansichten, die für jede Anwendung spezifisch ist. Im hier betrachteten Beispiel stellen die Aktionen den Ansichtsgeneratoren Informationen über ein Dictionary namens $dReponse zur Verfügung.
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 des Skripts a-init.php lautet wie folgt:
<?php
// Das Eingabeformular wird angezeigt
$dSession['etat']=array('principal'=>'e-formulaire', 'secondaire'=>'init');
?>
Dieses Skript legt in $dSession['etat']['principal'] lediglich den Zustand fest, in dem sich die Anwendung befinden soll, den Status [e-formulaire], und liefert in $dSession['etat']['secondaire'] eine Präzisierung zu diesem Status. 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 den Varianten [init] und c.a.d – das leere Formular.
4.12.3. Die Aktion „post:calculerimpot“
Diese Aktion dient dazu, die Steuer anhand der im Formular eingegebenen Daten zu berechnen. Die Konfigurationsdatei gibt an, dass das Skript a-calculimpot.php diese Aktion verarbeitet:
Der Code des Skripts a-calculimpot.php lautet wie folgt:
<?php
// Anfrage zur Steuerberechnung
// Zunächst wird die Gültigkeit der Parameter überprüft
$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é";
}
// Bei Fehlern ist der Vorgang beendet
if(count($erreurs)!=0){
// Vorbereitung der Fehlerseite
$dReponse['erreurs']=&$erreurs;
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'saisie');
return;
}//if
// sind die eingegebenen Daten korrekt
// Die für die Steuerberechnung erforderlichen Daten werden abgerufen
if(! $dSession['limites']){
// Die Daten sind nicht in der Sitzung vorhanden
// sie werden aus der Datenquelle abgerufen
list($erreurs,$limites,$coeffr,$coeffn)=getData($dConfig['DSN']);
// Bei Fehlern wird die Fehlerseite angezeigt
if(count($erreurs)!=0){
// Vorbereitung der Fehlerseite
$dReponse['erreurs']=&$erreurs;
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'database');
return;
}//if
// keine Fehler – die Daten werden in die Sitzung geschrieben
$dSession['limites']=&$limites;
$dSession['coeffr']=&$coeffr;
$dSession['coeffn']=&$coeffn;
}//if
// Hier liegen die für die Steuerberechnung erforderlichen Daten vor
// die Steuer wird berechnet
$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);
// Vorbereitung der Antwortseite
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'calculimpot');
$dReponse['impot']=$dPerso['impot'];
return;
//-----------------------------------------------------------------------
function getData($dDSN){
// Verbindung zur im Dictionary definierten Datenquelle $dDSN
$oImpots=new impots_data($dDSN);
if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
// Abruf der Grenzwerte, Koeffizienten „coeffr“ und „coeffn“
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// Verbindung wird getrennt
$oImpots->disconnect();
// Das Ergebnis wird zurückgegeben
if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
else return array(array(),$limites,$coeffr,$coeffn);
}//getData
Das Skript erfüllt seine Aufgabe: die Berechnung der Steuer. Wir überlassen es dem Leser, den Code der Verarbeitung zu entschlüsseln. Uns interessieren die Zustände, die infolge dieser Aktion auftreten können:
- Die eingegebenen Daten sind fehlerhaft oder der Zugriff auf die Daten schlägt fehl: Die Anwendung wird in den Status [e-erreurs] versetzt. Aus der Konfigurationsdatei geht hervor, dass das Skript e-erreurs.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-formulaire] versetzt, wobei die in $dSession['etat']['secondaire'] angegebene Variante „calculimpot“ verwendet wird. Die Konfigurationsdatei zeigt, dass das Skript e-formulaire.php die Antwortansicht generieren wird. Es verwendet den Wert aus $dSession['etat']['secondaire'], um ein Formular zu generieren, das mit den vom Benutzer eingegebenen Werten sowie dem Steuerbetrag vorausgefüllt ist.
4.12.4. Die Aktion „post:effacerformulaire“
Sie ist konfigurationsbedingt mit dem bereits beschriebenen Skript a-init.php verknüpft.
4.12.5. Die Aktion „get:retourformulaire“
Sie ermöglicht die Rückkehr zum Bericht [e-formulaire] aus dem Bericht [e-erreurs]. Diese Aktion wird vom Skript a-retourformulaire.php verarbeitet:
Das Skript a-retourformulaire.php lautet wie folgt:
<?php
// Das Eingabeformular wird angezeigt
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'retourformulaire');
?>
Es wird lediglich verlangt, dass die Anwendung in den Status [e-formulaire] in seiner Variante [retourformulaire] versetzt wird. Die Konfigurationsdatei zeigt uns, dass der Controller das Skript e-formulaire.php ausführt, um die Antwort an den Kunden 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 den Varianten [retourformulaire] und c.a.d. Das Formular wird mit den vom Benutzer eingegebenen Werten vorausgefüllt, jedoch ohne den Steuerbetrag.
4.13. Ungültige Abfolge von Aktionen
Die gültigen Aktionen ausgehend von einem bestimmten Zustand der Anwendung werden über die Konfiguration festgelegt:
<?php
…
// Konfiguration der Anwendungszustände
$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'));
Diese Konfiguration haben wir bereits erläutert. Wird eine ungültige Abfolge von Aktionen erkannt, wird das Skript a-enchainementinvalide.php ausgeführt:
Der Code dieses Skripts lautet wie folgt:
<?php
// Ungültige Abfolge von Aktionen
$dReponse['erreurs']=array("Enchaînement d'actions invalide");
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'enchainementinvalide');
?>
Dabei wird die Anwendung in den Status [e-erreurs] versetzt. In $dSession['etat']['secondaire'] geben wir eine Information an, die vom Generator der Fehlerseite verarbeitet wird. Wie wir bereits gesehen haben, ist dieser Generator e-erreurs.php:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
Wir werden uns den Code dieses Generators 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
…
....
// Die Sitzung wird gestartet oder fortgesetzt
session_start();
$dSession=$_SESSION["session"];
if($dSession) $dSession=unserialize($dSession);
// Die auszuführende Aktion wird abgerufen
$sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
$sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";
// Ist die Abfolge der Aktionen normal?
if( ! enchainementOK($dConfig,$dSession,$sAction)){
// Ablauf ist nicht normal
$sAction='enchainementinvalide';
}//if
// Verarbeitung der Aktion
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// Senden der Antwort (Ansicht) an den Kunden
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
.....
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: Konfigurationswörterbuch
// $dSession: Wörterbuch mit den Sitzungsinformationen
// $dReponse: das Wörterbuch der Argumente der Antwortseite
// Speicherung der Sitzung
...
// Senden der Antwort an den Client
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// Ende des Skripts
exit(0);
}//endsession
Nach der Rückkehr eines Aktionsskripts ruft der Controller aus $dSession['etat']['principal'] den Zustand ab, in den er die Anwendung versetzen muss. Dieser Zustand wurde durch die soeben ausgeführte Aktion festgelegt. Der Controller lässt daraufhin den dem Zustand zugeordneten View-Generator ausführen. Den Namen des View-Generators findet er in der Konfigurationsdatei. Die Aufgabe des View-Generators ist folgende:
- Er legt in $dReponse['vuereponse'] den Namen der zu verwendenden Antwortvorlage fest. Diese Information wird an den Controller weitergeleitet. Eine Vorlage ist eine Zusammensetzung aus Elementaransichten, 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. Es handelt sich um die Schnittstelle zwischen dem View-Generator und der endgültigen Ansicht. Sie ist anwendungsspezifisch.
- muss zwingend mit dem Aufruf der Funktion finSession des Controllers enden. Diese Funktion
- die Sitzung speichern
- die Antwort senden
Der Code der Funktion finSession lautet wie folgt:
<?php
…
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: Konfigurationswörterbuch
// $dSession: Wörterbuch mit den Sitzungsinformationen
// $dReponse: das Wörterbuch der Argumente der Antwortseite
// Speicherung der Sitzung
...
// Senden der Antwort an den Client
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// Ende des Skripts
exit(0);
}//Session beenden
Die an den Benutzer gesendete Ansicht wird durch die Entität $dReponse['vuereponse'] definiert, die die für die endgültige Antwort zu verwendende Vorlage festlegt.
4.14.2. Vorlage für die Antwort
Die Anwendung generiert ihre verschiedenen Antworten nach der folgenden einheitlichen Vorlage:
![]() |
Diese Vorlage ist dem Schlüssel „modéle1“ des Wörterbuchs $dConfig['vuesreponse'] zugeordnet:
Das Skript m-reponse.php ist für die Erstellung 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 Dictionary mit dem Namen $dReponse abgelegt und den folgenden Schlüsseln zugeordnet sind:
- urlstyle: URL des Stylesheets der Vorlage
- vue1: Name des Skripts, das für die Generierung der Ansicht „vue1“ zuständig ist
- vue2: Name des Skripts, das für die Generierung der Ansicht „vue2“ zuständig ist
Ein Ansichtsgenerator, der die Vorlage „modèle1“ verwenden möchte, muss diese drei dynamischen Elemente definieren. Wir definieren nun die Elementaransichten, die an die Stelle der Elemente [vue1] und [vue2] der Vorlage treten können.
4.14.3. Die Elementaransicht 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 $dReponse abgelegt und den folgenden Schlüsseln zugeordnet sind:
- Titel: anzuzeigender Titel
- Ergebnis: Höhe der zu zahlenden Steuer
4.14.4. Die Elementaransicht v-formulaire.php
Der Teil [vue2] entspricht entweder der Ansicht [v-formulaire] oder der Ansicht [v-erreurs]. Die Ansicht [v-formulaire] 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 Ansichtsgenerator definiert werden müssen, sind den folgenden Schlüsseln des Dictionaries $dReponse zugeordnet:
- optoui: Status des Optionsfelds mit dem Namen „optoui“
- optnon: Status des Optionsfelds mit dem Namen „optnon“
- Kinder: Anzahl der Kinder, die in das Feld „txtenfants“ eingegeben werden sollen
- Gehalt: Jahresgehalt, das in das Feld „txtsalaire“ eingefügt werden soll
4.14.5. Die Elementarsicht v-erreurs.php
Die Ansicht [v-erreurs] wird durch das Skript v-erreurs.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 Ansichtsgenerator definiert werden, sind den folgenden Schlüsseln des Dictionaries $dReponse zugeordnet:
- Fehler: Tabelle mit Fehlermeldungen
- Info: Informationsmeldung
- Link: Text eines Links
- href: Ziel-URL des oben genannten Links
4.14.6. Das Stylesheet
Alle Ansichten werden durch ein Stylesheet „gestaltet“. Um das Erscheinungsbild der Anwendung zu ändern, muss das Stylesheet angepasst werden. 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. View-Generatoren
4.15.1. Die Rolle eines View-Generators
Erinnern wir uns an den Codeabschnitt im Controller, der einen View-Generator ausführt:
<?php
…
// Bearbeitung der Aktion
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// Senden der Antwort (Ansicht) an den Kunden
$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 Zustand und View-Generator wird über die Konfiguration festgelegt:
<?php
…
// Konfiguration der Anwendungszustände
$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 bereits erläutert, welche Rolle ein View-Generator spielt. Lassen Sie uns dies hier noch einmal zusammenfassen. Ein View-Generator:
- legt in $dReponse['vuereponse'] den Namen der zu verwendenden Antwortvorlage fest. Diese Information wird an den Controller weitergeleitet. Eine Vorlage ist eine Zusammensetzung aus Elementaransichten, 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. Es handelt sich um die Schnittstelle zwischen dem View-Generator und der endgültigen Ansicht. Sie ist für jede Anwendung spezifisch.
- muss zwingend mit dem Aufruf der Controller-Funktion finSession enden. Diese Funktion
- die Sitzung speichern
- die Antwort senden
4.15.2. Der dem Bericht zugeordnete Ansichtsgenerator [e-formulaire]
Das Skript, das für die Generierung der dem Bericht [e-formulaire] zugeordneten Ansicht zuständig ist, heißt e-formulaire.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
// Die Formularantwort wird vorbereitet
$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'];
// Konfiguration entsprechend dem zu generierenden Formulartyp
$type=$dSession['etat']['secondaire'];
if($type=='init'){
// Leeres Formular
$dReponse['optnon']='checked';
}//if
if($type=='calculimpot'){
// müssen wir die in der Abfrage gespeicherten Eingabeparameter erneut anzeigen
$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'){
// müssen die in der Sitzung gespeicherten Eingabeparameter erneut angezeigt werden
$dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';
$dReponse['enfants']=$dSession['requete']['txtenfants'];
$dReponse['salaire']=$dSession['requete']['txtsalaire'];
}//if
// Die Antwort wird gesendet
finSession($dConfig,$dReponse,$dSession);
?>
Es ist zu beachten, dass der Ansichtsgenerator die für einen Ansichtsgenerator geltenden Bedingungen erfüllt:
- in $dReponse['vuereponse'] das zu verwendende Antwortmodell festlegen
- Informationen an diese Vorlage übergeben. Hier werden sie über das Dictionary $dReponse übergeben.
- mit dem Aufruf der Funktion finSession des Controllers abschließen
Hier wird das Modell „modèle1“ verwendet. Daher definiert der Generator die beiden Informationen, die dieses Modell benötigt: $dReponse['vue1'] und $dReponse['vue2'].
Im konkreten Fall unserer Anwendung hängt die dem Zustand [e-formulaire] zugeordnete Ansicht von einer Information ab, die in der Variablen $dSession['etat']['secondaire'] gespeichert ist. Dies ist eine Entwicklungsentscheidung. Eine andere Anwendung könnte sich dafür entscheiden, zusätzliche Informationen auf andere Weise weiterzugeben. Außerdem werden hier alle für die Anzeige der endgültigen Ansicht erforderlichen Informationen im Dictionary $dReponse abgelegt. Auch dies ist eine Entscheidung, die dem Entwickler überlassen bleibt. Der Status [e-formulaire] kann nach vier verschiedenen Aktionen auftreten: init, calculerimpot, retourformulaire, effacerformulaire. Die anzuzeigende Ansicht ist nicht in allen Fällen genau dieselbe. Daher wurden hier in $dSession['etat']['secondaire'] drei Fälle unterschieden:
- init: Das Formular wird leer angezeigt
- Steuerberechnung: Das Formular wird mit dem Steuerbetrag und den Daten angezeigt, die zu dessen Berechnung geführt haben
- retourformulaire: Das Formular wird mit den ursprünglich eingegebenen Daten angezeigt
Das oben genannte Skript e-formulaire.php nutzt diese Informationen, um die Antwort entsprechend diesen drei Varianten darzustellen.
4.15.3. Die dem Bericht [e-erreurs] zugeordnete Ansicht
Das Skript, das für die Generierung der zum Bericht [e-erreurs] gehörenden Ansicht zuständig ist, heißt e-erreurs.php und lautet wie folgt:
<?php
// die Fehlermeldung wird vorbereitet
$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';
// zusätzliche Informationen
$type=$dSession['etat']['secondaire'];
if($type=='database'){
$dReponse['info']="Veuillez avertir l'administrateur de l'application";
}
// die Antwort wird gesendet
finSession($dConfig,$dReponse,$dSession);
?>
4.15.4. Anzeige der endgültigen Ansicht
Die beiden Skripte, die die beiden Endansichten generieren, enden beide mit dem Aufruf der Controller-Funktion finSession:
<?php
…
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: Konfigurationswörterbuch
// $dSession: Wörterbuch mit den Sitzungsinformationen
// $dReponse: das Wörterbuch der Argumente der Antwortseite
....
// die Antwort wird angezeigt
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// Ende des Skripts
exit(0);
}//Ende der Sitzung
Die an den Benutzer gesendete Ansicht wird durch die Entität $dReponse['vuereponse'] definiert, die die für die endgültige Antwort zu verwendende Vorlage festlegt. Für die Berichte [e-formulaire] und [e-erreurs] wurde diese Vorlage auf „modele1“ festgelegt:
Diese Vorlage entspricht in der Konfiguration dem Skript m-reponse.php:
4.16. Die Antwortvorlage bearbeiten
Wir gehen hier davon aus, dass man beschließt, das Erscheinungsbild der Antwort an den Kunden zu ändern, 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 „modele2“ heißen, und das Skript, das diese Vorlage generiert, wird „m-reponse2.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'>
<!-- Beginn des Banners -->
<tr>
<td colspan="2"><?php include $dReponse['vue1']; ?></td>
</tr>
<!-- Ende des Banners -->
<tr>
<!-- Menü-Anfang -->
<td><?php include $dReponse['vue2']; ?></td>
<!-- Ende des Menüs -->
<!-- Anfang von Bereich 3 -->
<td><?php include $dReponse['vue3']; ?></td>
<!-- Ende Bereich 3 -->
</tr>
</table>
</body>
</html>
Die dynamischen Elemente der Vorlage sind folgende:
- $dReponse['urlstyle']: das zu verwendende Stylesheet
- $dReponse['vue1']: das zu verwendende Skript zur Generierung von [vue1]
- $dReponse['vue2']: das zur Erzeugung von [vue2] zu verwendende Skript
- $dReponse['vue3']: Das Skript, das zur Generierung von [vue3] verwendet werden soll
Diese Elemente müssen von den Erstellern der Ansichten festgelegt werden.
4.16.2. Die verschiedenen Antwortseiten
Die Anwendung zeigt dem Benutzer nun die folgenden Antworten an. Beim ersten Aufruf lautet die Antwortseite wie folgt:
![]() |
Wenn der Benutzer gültige Daten eingibt, wird die Steuer berechnet:
![]() |
Bei Eingabefehlern wird die Fehlerseite angezeigt:
![]() |
Wenn er den Link [Retour au formulaire de saisie] verwendet, gelangt er zurück zu dem Formular, das er bereits abgesendet hat:
![]() |
Wenn er im obigen Fall den Link [Réinitialiser le formulaire] verwendet, wird ein leeres Formular angezeigt:
![]() |
Es ist zu beachten, dass die Anwendung tatsächlich dieselben Aktionen wie zuvor verwendet. Lediglich die Darstellung der Antworten hat sich geändert.
4.16.3. Die Elementarsichten
Die Elementaransicht [vue1] wird wie im vorherigen Beispiel dem Skript v-bandeau.php zugeordnet:
<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:
- $dReponse['titre']: Anzuzeigender Titel
- $dReponse['resultat']: Höhe der zu zahlenden Steuer
Die Elementaransicht [vue2] wird dem folgenden Skript v-menu.php zugeordnet:
<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'].
'">'.$dReponseQZXW2HTMLBWydsaWVucyddZQXQZXW2HTMLBWyRpXQZQXQZXW2HTMLBWyd0ZXh0ZSddZQX."</a></div></td></tr>\n";
}//$i
?>
</table>
Diese Ansicht enthält die folgenden dynamischen Elemente:
- $dReponse['liens']: Tabelle der Links, die in [vue2] angezeigt werden sollen. Jedes Element der Tabelle ist ein Wörterbuch mit zwei Schlüsseln:
- „url“: Ziel-URL des Links
- 'text': Text des Links
Die Elementaransicht [vue3] wird entweder mit dem Skript v-formulaire2.php verknüpft, wenn das Eingabeformular angezeigt werden soll, oder mit dem Skript v-erreurs2.php, wenn die Fehlerseite angezeigt werden soll. Der Code des Skripts v-formulaire2.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 Ansichtsgenerator definiert werden müssen, sind den folgenden Schlüsseln des Dictionaries $dReponse zugeordnet:
- optoui: Status des Optionsfelds mit dem Namen „optoui“
- optnon: Status des Optionsfelds mit dem Namen „optnon“
- Kinder: 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";
}//für
?>
</ul>
<div class="info"><?php echo $dReponse["info"] ?></div>
Die dynamischen Teile dieser Ansicht, die vom Ansichtsgenerator definiert werden, sind den folgenden Schlüsseln im Dictionary $dReponse zugeordnet:
- Fehler: Tabelle mit Fehlermeldungen
- Info: Informationsmeldung
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 einzufügen, müssen wir einige Zeilen in der Konfigurationsdatei ändern.
<?php
// PHP-Konfiguration
ini_set("register_globals","off");
ini_set("display_errors","off");
ini_set("expose_php","off");
// Liste der einzubindenden Module
$dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');
// Anwendungscontroller
$dConfig['webapp']=array('titre'=>"Calculez votre impôt");
// Konfiguration der Ansichten der Anwendung
$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';
// Konfiguration der Anwendungsaktionen
$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');
// Konfiguration der Anwendungsberichte
$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'));
// Konfiguration des Anwendungsmodells
$dConfig["DSN"]=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
?>
Die wesentliche Änderung besteht darin, die den Berichten [e-formulaire] und [e-erreurs] zugeordneten Ansichtsgeneratoren zu ändern. Anschließend werden die neuen Ansichtsgeneratoren mit der Erstellung der neuen Antwortseiten beauftragt.
4.16.6. Der dem Bericht [e-formulaire] zugeordnete View-Generator
In der Konfigurationsdatei ist der Bericht [e-formulaire] nun dem View-Generator e-formulaire2.php zugeordnet. Der Code dieses Skripts lautet wie folgt:
<?php
// Vorbereitung der Formularantwort
$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')
);
// Konfiguration je nach Art des zu generierenden Formulars
$type=$dSession['etat']['secondaire'];
if($type=='init'){
// Leeres Formular
$dReponse['optnon']='checked';
}//if
if($type=='calculimpot'){
// müssen wir die in der Abfrage gespeicherten Eingabeparameter erneut anzeigen
$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'){
// müssen wir die in der Sitzung gespeicherten Eingabeparameter erneut anzeigen
$dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';
$dReponse['enfants']=$dSession['requete']['txtenfants'];
$dReponse['salaire']=$dSession['requete']['txtsalaire'];
}//if
// Die Antwort wird gesendet
finSession($dConfig,$dReponse,$dSession);
?>
Die wichtigsten Änderungen sind folgende:
- Der Ansichtsgenerator gibt an, dass er das Antwortmodell „modele2“ verwenden möchte
- Aus diesem Grund füllt er die dynamischen Elemente $dReponse['vue1'], $dReponse['vue2'], $dReponse['vue3'], die alle drei für die Antwortvorlage „modele2“ erforderlich sind.
- Der Generator füllt außerdem das dynamische Element $dReponse['liens'] aus, das die im Bereich [vue2] der Antwort anzuzeigenden Links festlegt.
4.16.7. Der dem Bericht [e-erreurs] zugeordnete Ansichtsgenerator
In der Konfigurationsdatei ist der Bericht [e-erreurs] nun dem Ansichtsgenerator e-erreurs2.php zugeordnet. Der Code dieses Skripts lautet wie folgt:
<?php
// die Fehlerantwort wird vorbereitet
$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')
);
// zusätzliche Informationen
$type=$dSession['etat']['secondaire'];
if($type=='database'){
$dReponse['info']="Veuillez avertir l'administrateur de l'application";
}
// die Antwort wird gesendet
finSession($dConfig,$dReponse,$dSession);
?>
Die vorgenommenen Änderungen entsprechen denen am View-Generator e-formulaire2.php.
4.17. Fazit
Anhand eines Beispiels konnten wir den Nutzen unseres generischen Controllers aufzeigen. Wir mussten diesen nicht selbst schreiben. Wir haben uns darauf beschränkt, die Skripte für die Aktionen, die View-Generatoren und die Views der Anwendung zu schreiben. Außerdem haben wir den Vorteil der Trennung von Aktionen und Views aufgezeigt. So konnten wir das Erscheinungsbild der Antworten ändern, ohne auch nur eine einzige Zeile Code in den Aktionsskripten zu ändern. Nur die Skripte, die an der Generierung der Ansichten beteiligt sind, wurden geändert. Damit dies möglich ist, darf das Aktionsskript keinerlei Annahmen über die Ansicht treffen, die die von ihm berechneten Informationen anzeigen wird. Es muss sich darauf beschränken, diese Informationen an den Controller zu übergeben, der sie an den Ansichtsgenerator weiterleitet, der sie dann formatiert. Dies ist eine unumstößliche Regel: Eine Aktion muss vollständig von den Ansichten entkoppelt sein.
In diesem Kapitel haben wir uns mit der Struts-Philosophie befasst, 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 auf der Website http://www.phpmvc.net/.













