4. Ілюстративний приклад
Ми пропонуємо проілюструвати описаний вище метод на прикладі розрахунку податків.
4.1. Задача
Ми пропонуємо написати програму, що дозволяє розрахувати податок платника податків. Розглянемо спрощений випадок, коли платник податків має задекларувати лише свою заробітну плату:
- розраховуємо кількість часткок працівника nbParts=nbEnfants/2 +1, якщо він не одружений, nbEnfants/2+2, якщо він одружений, де nbEnfants — кількість його дітей. Кількість часткок збільшується на 0,5, якщо дітей троє або більше.
- розраховується його оподатковуваний дохід R=0,72*S, де S — його річна заробітна плата
- розраховується його сімейний коефіцієнт Q = R/N
- розраховується його податок I на основі таких даних
| Кожен рядок має 3 граничні поля: coeffR, coeffN. Щоб обчислити податок I, шукаємо перший рядок, у якому QF <= граничне значення. Наприклад, якщо QF = 30000, то знайдемо такий рядок: 31810 0,2 3309,5. Тоді податок I дорівнює 0,2*R - 3309,5*nbParts. Якщо QF є таким, що співвідношення QF <= межа ніколи не виконується, то використовуються коефіцієнти останнього рядка: 0 0,65 49062, що дає податок I = 0,65*R - 49062*nbParts. |
4.2. База даних
Наведені вище дані зберігаються в базі даних MySQL під назвою dbimpots. Користувач seldbimpots із паролем mdpseldbimpots має доступ до вмісту бази даних лише для читання. База даних містить єдину таблицю під назвою impots, структура якої така:

Її вміст такий:

4.3. Архітектура MVC додатка
Додаток матиме таку архітектуру MVC:
![]() |
- контролер main.php буде тим самим загальним контролером, що й раніше
- запит клієнта надсилається до контролера у вигляді запиту такого формату: main.php?action=xx. Значення параметра action визначає, який скрипт блоку ACTIONS слід виконати. Виконаний скрипт action повертає контролеру змінну, що вказує стан, у який має бути переведений веб-додаток. Отримавши цей стан, контролер активує один із генераторів представлень, щоб надіслати відповідь клієнту.
- impots-data.php — це клас, відповідальний за надання контролеру необхідних даних
- impots-calcul.php — це бізнес-клас, що забезпечує розрахунок податку
4.4. Клас доступу до даних
Клас доступу до даних створено для того, щоб приховати від веб-додатка джерело походження даних. У його інтерфейсі міститься метод getData, який подає три масиви даних, необхідні для розрахунку податку. У нашому прикладі дані беруться з бази даних MySQL. Щоб зробити клас незалежним від фактичного типу SGBD, ми використаємо бібліотеку pear::DB, описану в додатку. Код класу такий:
<?php
// бібліотеки
require_once 'DB.php';
class impots_data{
// клас доступу до джерела даних DBIMPOTS
// атрибути
var $sDSN; // рядок підключення
var $sDatabase; // назва бази даних
var $oDB; // підключення до бази даних
var $aErreurs; // список помилок
var $oRésultats; // результат запиту
var $connecté; // логічне значення, яке вказує, чи підключено до бази даних
var $sQuery; // останній виконаний запит
// конструктор
function impots_data($dDSN){
// $dDSN: словник, що визначає з’єднання, яке потрібно встановити
// $dDSN['sgbd']: тип об’єкта SGBD, до якого потрібно підключитися
// $dDSN['host']: ім’я хост-машини, на якій він розміщений
// $dDSN['database']: ім’я бази даних, до якої потрібно підключитися
// $dDSN['user']: користувач бази даних
// $dDSN['mdp']: його пароль
// створює в $oDB з’єднання з базою даних, визначеною $dDSN, під ім’ям користувача $dDSN['user']
// якщо з’єднання встановлено
// записує в $sDSN рядок підключення до бази даних
// записує в $sDataBase ім’я бази даних, до якої здійснюється підключення
// встановлює для $connecté значення «true»
// якщо підключення не вдалося
// додає відповідні повідомлення про помилки до списку $aErreurs
// закриває з'єднання, якщо це необхідно
// встановлює для $connecté значення «false»
// очищає список помилок
$this->aErreurs=array();
// створюється з'єднання з базою даних $sDSN
$this->sDSN=$dDSN["sgbd"]."://".$dDSN["user"].":".$dDSN["mdp"]."@".$dDSN["host"]."/".$dDSN["database"];
$this->sDatabase=$dDSN["database"];
$this->connect();
// підключено?
if( ! $this->connecté) return;
// з'єднання встановлено
$this->connecté=TRUE;
}//виробник
// ------------------------------------------------------------------
function connect(){
// (повторне) підключення до бази даних
// очищення списку помилок
$this->aErreurs=array();
// створюється з'єднання з базою даних $sDSN
$this->oDB=DB::connect($this->sDSN,true);
// помилка?
if(DB::iserror($this->oDB)){
// помилка зафіксована
$this->aErreurs[]="Echec de la connexion à la base [".$this->sDatabase."] : [".$this->oDB->getMessage()."]";
// підключення не вдалося
$this->connecté=FALSE;
// кінець
return;
}
// підключено
$this->connecté=TRUE;
}//підключено
// ------------------------------------------------------------------
function disconnect(){
// якщо з'єднання встановлено, закриваємо з'єднання з базою $sDSN
if($this->connecté){
$this->oDB->disconnect();
// з'єднання розірвано
$this->connecté=FALSE;
}//якщо
}//відключення
// -------------------------------------------------------------------
function execute($sQuery){
// $sQuery: запит до виконання
// запитується
$this->sQuery=$sQuery;
// чи є з'єднання?
if(! $this->connecté){
// помилка зафіксована
$this->aErreurs[]="Pas de connexion existante à la base [$this->sDatabase]";
// кінець
return;
}//if
// виконання запиту
$this->oRésultats=$this->oDB->query($sQuery);
// помилка?
if(DB::iserror($this->oRésultats)){
// помічено помилку
$this->aErreurs[]="Echec de la requête [$sQuery] : [".$this->oRésultats->getMessage()."]";
// повернення
return;
}//if
}//виконати
// ------------------------------------------------------------------
function getData(){
// отримуємо 3 ряди даних: межі, коефіцієнти, коефіцієнти
$this->execute('select limites, coeffR, coeffN from impots');
// чи є помилки?
if(count($this->aErreurs)!=0) return array();
// проглядаємо результат запиту 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
}//клас
?>
Програма для тестування може виглядати так:
<?php
// бібліотека
require_once "c-impots-data.php";
require_once "DB.php";
// тест класу impots-data
ini_set('track_errors','on');
ini_set('display_errors','on');
// базова конфігурація dbimpots
$dDSN=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
// вхід у систему
$oImpots=new impots_data($dDSN);
// помилки?
if(checkErreurs($oImpots)){
exit(0);
}
// моніторинг
echo "Connecté à la base...\n";
// отримання даних про ліміти, коефіцієнти coeffr та coeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// помилки?
if( ! checkErreurs($oImpots)){
// вміст
echo "données : \n";
for($i=0;$i<count($limites);$i++){
echo "[$limites[$i],$coeffr[$i],$coeffn[$i]]\n";
}//for
}//if
// відключення
$oImpots->disconnect();
// відстеження
echo "Déconnecté de la base...\n";
// кінець
exit(0);
// ----------------------------------
function checkErreurs(&$oImpots){
// помилок?
if(count($oImpots->aErreurs)!=0){
// відображення
for($i=0;$i<count($oImpots->aErreurs);$i++){
echo $oImpots->aErreurs[$i]."\n";
}//для
// помилки
return true;
}//if
// помилок немає
return false;
}//checkErreurs
?>
Виконання цієї тестової програми дає такі результати:
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. Клас для розрахунку податку
Цей клас дозволяє розрахувати податок платника податків. У його конструктору вказуються дані, необхідні для цього розрахунку. Потім він розраховує відповідний податок. Код класу такий:
<?php
class impots_calcul{
// клас розрахунку податку
// конструктор
function impots_calcul(&$perso,&$data){
// $perso: словник із такими ключами
// діти: кількість дітей
// зарплата: річна зарплата
// marié(e): логічне значення, що вказує, чи перебуває платник податків у шлюбі
// податок(и): податок до сплати, розрахований цим конструктором
// $data: словник із такими ключами
// ліміти: таблиця меж податкових груп
// коефіцієнти: таблиця коефіцієнтів доходу
// coeffn — таблиця коефіцієнтів кількості часток
// усі 3 таблиці мають однакову кількість елементів
// розрахунок кількості часток
if($perso['marié'])
$nbParts=$perso['enfants']/2+2;
else $nbParts=$perso['enfants']/2+1;
if ($perso['enfants']>=3) $nbParts+=0.5;
// оподатковуваний дохід
$revenu=0.72*$perso['salaire'];
// сімейний коефіцієнт
$QF=$revenu/$nbParts;
// пошук податкової групи, що відповідає QF
$nbTranches=count($data['limites']);
$i=0;
while($i<$nbTranches-2 && $QF>$data['limites'][$i]) $i++;
// податок
$perso['impot']=floor($data['coeffr'][$i]*$revenu-$data['coeffn'][$i]*$nbParts);
}//виробник
}//клас
?>
Програма для тестування може виглядати так:
<?php
// бібліотека
require_once "c-impots-data.php";
require_once "c-impots-calcul.php";
// базова конфігурація dbimpots
$dDSN=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
// вхід у систему
$oImpots=new impots_data($dDSN);
// помилки?
if(checkErreurs($oImpots)){
exit(0);
}
// моніторинг
echo "Connecté à la base...\n";
// отримання даних про ліміти, коефіцієнт coeffr, коефіцієнт coeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// помилки?
if(checkErreurs($oImpots)){
exit(0);
}
// відключення
$oImpots->disconnect();
// відстеження
echo "Déconnecté de la base...\n";
// розрахунок податку
$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);
// кінець
exit(0);
// ----------------------------------
function checkErreurs(&$oImpots){
// помилки?
if(count($oImpots->aErreurs)!=0){
// відображення
for($i=0;$i<count($oImpots->aErreurs);$i++){
echo $oImpots->aErreurs[$i]."\n";
}//для
// помилки
return true;
}//if
// помилок немає
return false;
}//checkErreurs
?>
Виконання цієї програми тестування дає такі результати:
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. Робота додатка
Після запуску веб-додатку для розрахунку податку з'являється таке вікно [v-formulaire]:
![]() |
Користувач заповнює поля та запускає розрахунок податку:
![]() |
Слід зауважити, що форма оновлюється у тому стані, в якому користувач її підтвердив, і додатково відображає суму податку до сплати. Користувач може припуститися помилок під час введення даних. Про них йому повідомляється на сторінці помилок, яку ми назвемо екраном [v-erreurs].
![]() |
![]() |
Посилання [Retour au formulaire de saisie] дозволяє користувачеві переглянути форму в тому вигляді, в якому він її підтвердив.
![]() |
Нарешті, кнопка [Effacer le formulaire] повертає форму до початкового стану, c.a.d, у якому користувач отримав її під час початкового запиту.
4.7. Огляд архітектури MVC додатка
Додаток має таку архітектуру MVC:
![]() |
Ми щойно описали два класи impots-data.php та impots-calcul.php. Тепер опишемо інші елементи архітектури.
4.8. Контролер додатка
Контролер main.php додатка — це той самий контролер, що був описаний у першій частині цього розділу. Це загальний контролер, незалежний від додатка.
<?php
// універсальний контролер
// читання конфігурації
include 'config.php';
// включення бібліотек
for($i=0;$i<count($dConfig['includes']);$i++){
include($dConfig['includes'][$i]);
}//for
// запуск або відновлення сеансу
session_start();
$dSession=$_SESSION["session"];
if($dSession) $dSession=unserialize($dSession);
// отримання дії, яку потрібно виконати
$sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
$sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";
// чи є послідовність дій нормальною?
if( ! enchainementOK($dConfig,$dSession,$sAction)){
// послідовність ненормальна
$sAction='enchainementinvalide';
}//if
// обробка дії
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// відправлення відповіді (перегляду) клієнту
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
// кінець скрипта — сюди не слід потрапляти, якщо тільки не стався збій
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: словник конфігурації
// $dSession: словник, що містить інформацію про сесію
// $dReponse: словник аргументів сторінки відповіді
// запис сеансу
if(isset($dSession)){
// параметри запиту заносяться в сесію
$dSession['requete']=strtolower($_SERVER['REQUEST_METHOD'])=='get' ? $_GET :
strtolower($_SERVER['REQUEST_METHOD'])=='post' ? $_POST : array();
$_SESSION['session']=serialize($dSession);
session_write_close();
}else{
// сесія відсутня
session_destroy();
}
// відображення відповіді
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// кінець скрипта
exit(0);
}//закінчення сесії
//--------------------------------------------------------------------
function enchainementOK(&$dConfig,&$dSession,$sAction){
// перевіряє, чи дозволена поточна дія з огляду на попередній стан
$etat=$dSession['etat']['principal'];
if(! isset($etat)) $etat='sansetat';
// перевірка дії
$actionsautorisees=$dConfig['etats'][$etat]['actionsautorisees'];
$autorise= ! isset($actionsautorisees) || in_array($sAction,$actionsautorisees);
return $autorise;
}
//--------------------------------------------------------------------
function dump($dInfos){
// виводить словник інформації
while(list($clé,$valeur)=each($dInfos)){
echo "[$clé,$valeur]<br>\n";
}//while
}//відстеження
//--------------------------------------------------------------------
function trace($msg){
echo $msg."<br>\n";
}//відстеження
?>
4.9. Дії веб-додатку
Існує чотири дії:
- get:init: ця дія запускається під час початкового запиту до контролера без параметрів. Вона створює порожній вигляд «форма».
- post:effacerformulaire: дія, що запускається кнопкою [Effacer le formulaire]. Вона створює порожній вигляд [v-formulaire].
- post:calculerimpot: дія, що запускається кнопкою [Calculer l'impôt]. Вона генерує або вигляд [v-formulaire] із сумою податку до сплати, або вигляд [v-erreurs].
- get:retourformulaire: дія, що запускається посиланням [Retour au formulaire de saisie]. Вона генерує вікно [v-formulaire], попередньо заповнене помилковими даними.
Ці дії налаштовані у файлі конфігурації наступним чином:
<?php
…
// налаштування дій додатка
$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');
З кожною дією пов'язаний скрипт, який відповідає за її обробку. Кожна дія переводить веб-додаток у стан, визначений елементом $dSession['etat']['principal']. Цей стан призначений для збереження в сесії. Крім того, дія записує у словник $dReponse інформацію, необхідну для відображення подання, пов’язаного з новим станом, у якому перебуватиме додаток.
4.10. Стани веб-додатку
Їх є два:
- [e-formulaire]: стан, у якому представлені різні варіанти подання [v-formulaire].
- [e-erreurs]: стан, у якому відображається вигляд [v-erreurs].
У цих станах дозволені такі дії:
<?php
…
// налаштування станів додатка
$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'));
У стані дозволені дії відповідають цілям посилань або кнопок [submit] у вікні, пов'язаному з цим станом. Крім того, дія «get:init» завжди дозволена. Це дозволяє користувачеві отримати URL main.php зі списку URL свого браузера та відтворити його незалежно від стану додатка. Це своєрідне «ручне» скидання. Стан «sansetat» існує лише під час запуску додатка.
З кожним станом додатка пов’язаний скрипт, який відповідає за формування відповідного вигляду:
- стан [e-formulaire]: скрипт e-formulaire.php
- звіт [e-erreurs]: скрипт e-erreurs.php
Звіт [e-formulaire] відображатиме вигляд [v-formulaire] з різними варіантами. Так, вигляд [v-formulaire] може бути порожнім, попередньо заповненим або містити суму податку. Дія, яка переведе додаток у стан [e-formulaire], вказує у змінній $dSession['etat']['principal'] основний стан додатка. Контролер використовує лише цю інформацію. У нашому додатку дія, яка переводить додаток у стан [e-formulaire], додасть у $dSession['etat']['secondaire'] додаткову інформацію, яка дозволить генератору відповіді визначити, чинеобхідно генерувати порожню форму, попередньо заповнену форму, з сумою податку чи без неї. Можна було б вчинити інакше, вважаючи, що тут є три різні стани, а отже, потрібно написати три генератори подання.
4.11. Файл конфігурації веб-додатку config.php
<?php
// налаштування PHP
ini_set("register_globals","off");
ini_set("display_errors","off");
ini_set("expose_php","off");
// список модулів для включення
$dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');
// контролер додатка
$dConfig['webapp']=array('titre'=>"Calculez votre impôt");
// налаштування переглядів додатка
$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';
// конфігурація дій додатка
$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');
// конфігурація станів додатка
$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'));
// конфігурація шаблону додатка
$dConfig["DSN"]=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
?>
4.12. Дії веб-додатку
4.12.1. Загальний принцип роботи скриптів дій
- Скрипт дії викликається контролером відповідно до параметра action, який він отримав від клієнта.
- Після виконання скрипт дії повинен вказати контролеру стан, у який слід перевести додаток. Цей стан має бути вказаний у $dSession['etat']['principal'].
- Скрипт дії може потребувати розміщення інформації в сесії. Для цього він розміщує її у словнику $dSession, який контролер автоматично зберігає в сесії наприкінці циклу «запит-відповідь».
- Скрипт дії може мати інформацію, яку потрібно передати до представлень. Цей аспект не залежить від контролера. Йдеться про інтерфейс між діями та представленнями, який є специфічним для кожного додатка. У розглянутому тут прикладі дії надаватимуть інформацію генераторам представлень через словник під назвою $dReponse.
4.12.2. Дія get:init
Це дія, яка генерує порожню форму. Конфігураційний файл показує, що її оброблятиме скрипт a-init.php:
Код скрипта a-init.php такий:
<?php
// відображення форми введення даних
$dSession['etat']=array('principal'=>'e-formulaire', 'secondaire'=>'init');
?>
Цей скрипт просто встановлює в $dSession['etat']['principal'] стан, в якому має перебувати додаток, стан [e-formulaire], а також вносить у $dSession['etat']['secondaire'] уточнення щодо цього стану. Конфігураційний файл показує, що контролер виконає скрипт e-formulaire.php для формування відповіді клієнту.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Скрипт e-formulaire.php згенерує подання [v-formulaire] у його варіантах [init] та c.a.d — порожню форму.
4.12.3. Дія post:calculerimpot
Це дія, яка дозволяє розрахувати податок на основі даних, введених у форму. У файлі конфігурації вказано, що цю дію оброблятиме скрипт a-calculimpot.php:
Код скрипта a-calculimpot.php такий:
<?php
// запит на розрахунок податку
// спочатку перевіряється правильність параметрів
$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(count($erreurs)!=0){
// підготовка сторінки з повідомленням про помилки
$dReponse['erreurs']=&$erreurs;
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'saisie');
return;
}//if
// введені дані правильні
// отримуємо дані, необхідні для розрахунку податку
if(! $dSession['limites']){
// дані відсутні в сесії
// їх отримують із джерела даних
list($erreurs,$limites,$coeffr,$coeffn)=getData($dConfig['DSN']);
// якщо є помилки, відображається сторінка помилок
if(count($erreurs)!=0){
// підготовка сторінки помилок
$dReponse['erreurs']=&$erreurs;
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'database');
return;
}//if
// помилок немає — дані заносяться в сесію
$dSession['limites']=&$limites;
$dSession['coeffr']=&$coeffr;
$dSession['coeffn']=&$coeffn;
}//if
// тут є дані, необхідні для розрахунку податку
// розраховуємо податок
$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);
// підготовка сторінки відповіді
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'calculimpot');
$dReponse['impot']=$dPerso['impot'];
return;
//-----------------------------------------------------------------------
function getData($dDSN){
// підключення до джерела даних, визначеного словником $dDSN
$oImpots=new impots_data($dDSN);
if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
// отримання даних про межі, коефіцієнт coeffr, коефіцієнт coeffn
list($limites,$coeffr,$coeffn)=$oImpots->getData();
// відключення
$oImpots->disconnect();
// повернення результату
if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
else return array(array(),$limites,$coeffr,$coeffn);
}//getData
Скрипт виконує своє завдання: обчислює податок. Розшифрування коду обробки залишаємо на розсуд читача. Нас цікавлять стани, які можуть виникнути в результаті цієї дії:
- введені дані є некоректними або виникають проблеми з доступом до даних: додаток переходить у стан [e-erreurs]. Конфігураційний файл показує, що саме скрипт e-erreurs.php відповідатиме за формування відповіді:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
- у всіх інших випадках додаток переводиться у стан [e-formulaire] із варіантом calculimpot, вказаним у $dSession['etat']['secondaire']. Конфігураційний файл показує, що саме скрипт e-formulaire.php буде генерувати відповідь. Він використовуватиме значення з $dSession['etat']['secondaire'] для формування попередньо заповненої форми зі значеннями, введеними користувачем, а також сумою податку.
4.12.4. Дія post:effacerformulaire
Вона пов’язана налаштуваннями зі скриптом a-init.php, який вже було описано.
4.12.5. Дія get:повернутиформу
Вона дозволяє повернутися до стану [e-formulaire] зі стану [e-erreurs]. Цю дію обробляє скрипт a-retourformulaire.php:
Скрипт a-retourformulaire.php має такий вигляд:
<?php
// відображення форми введення
$dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'retourformulaire');
?>
Потрібно просто перевести додаток у стан [e-formulaire] у його варіанті [retourformulaire]. Конфігураційний файл показує, що контролер виконає скрипт e-formulaire.php для формування відповіді клієнту.
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Скрипт e-formulaire.php згенерує подання [v-formulaire] у його варіантах [retourformulaire] та c.a.d. Форму, попередньо заповнену значеннями, введеними користувачем, але без суми податку.
4.13. Неправильна послідовність дій
Дії, які є допустимими з певного стану додатка, визначаються конфігурацією:
<?php
…
// налаштування станів додатка
$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'));
Ми вже пояснювали цю конфігурацію. Якщо виявлено недійсну послідовність дій, запускається скрипт a-enchainementinvalide.php:
Код цього скрипта такий:
<?php
// неправильна послідовність дій
$dReponse['erreurs']=array("Enchaînement d'actions invalide");
$dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'enchainementinvalide');
?>
Він полягає у переведенні додатка у стан [e-erreurs]. У $dSession['etat']['secondaire'] ми вказуємо інформацію, яка буде використана генератором сторінки помилок. Як ми вже бачили, цим генератором є e-erreurs.php:
<?php
…
$dConfig['etats']['e-erreurs']=array(
'actionsautorisees'=>array('get:retourformulaire','get:init'),
'vue'=>'e-erreurs.php');
Ми розглянемо код цього генератора пізніше. Клієнту надсилається таке зображення:

4.14. Види додатка
4.14.1. Відображення кінцевого виду
Давайте розглянемо, як контролер надсилає відповідь клієнту після виконання дії, яку той запросив:
<?php
…
....
// запуск або відновлення сеансу
session_start();
$dSession=$_SESSION["session"];
if($dSession) $dSession=unserialize($dSession);
// отримано дію, яку потрібно виконати
$sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
$sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";
// чи є послідовність дій нормальною?
if( ! enchainementOK($dConfig,$dSession,$sAction)){
// послідовність ненормальна
$sAction='enchainementinvalide';
}//if
// обробка дії
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// відправлення відповіді (перегляду) клієнту
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
.....
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: словник конфігурації
// $dSession: словник, що містить інформацію про сесію
// $dReponse: словник аргументів сторінки відповіді
// запис сеансу
...
// відправлення відповіді клієнту
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// завершення скрипта
exit(0);
}//закінчення сесії
Після повернення скрипта дії контролер отримує з $dSession['etat']['principal'] стан, у який він повинен перевести додаток. Цей стан був визначений щойно виконаною дією. Потім контролер запускає генератор подання, пов’язаний із цим станом. Він знаходить його ім’я у файлі конфігурації. Роль генератора подання полягає в наступному:
- визначає у $dReponse['vuereponse'] ім’я шаблону відповіді, який слід використовувати. Ця інформація передається контролеру. Шаблон — це сукупність елементарних представлень, які разом утворюють кінцеве представлення.
- готує динамічну інформацію для відображення в кінцевому вигляді. Цей етап не залежить від контролера. Це інтерфейс між генератором видів та кінцевим видом. Він є специфічним для кожного додатка.
- обов’язково завершується викликом функції finSession контролера. Ця функція
- збереже сесію
- надіслати відповідь
Код функції finSession такий:
<?php
…
// ---------------------------------------------------------------
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: словник конфігурації
// $dSession: словник, що містить інформацію про сесію
// $dReponse: словник аргументів сторінки відповіді
// запис сеансу
...
// відправлення відповіді клієнту
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// завершення скрипта
exit(0);
}//закінчення сеансу
Вигляд, що надсилається користувачеві, визначається сутністю $dReponse['vuereponse'], яка визначає шаблон, що використовується для остаточної відповіді.
4.14.2. Шаблон відповіді
Додаток генеруватиме різні відповіді відповідно до такого єдиного шаблону:
![]() |
Ця модель пов’язана з ключем «модель1» у словнику $dConfig['vuesreponse']:
Скрипт m-reponse.php відповідає за генерацію цього шаблону:
<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>
Цей скрипт має три динамічні елементи, розміщені у словнику $dReponse та пов’язані з такими ключами:
- urlstyle: URL-адреса таблиці стилів шаблону
- vue1: назва скрипта, відповідального за генерацію подання vue1
- vue2: ім’я скрипта, що відповідає за генерацію подання vue2
Генератор подання, який бажає використовувати модель modèle1, повинен визначити ці три динамічні елементи. Тепер ми визначаємо елементарні подання, які можуть замінити елементи [vue1] та [vue2] у моделі.
4.14.3. Елементарний вигляд v-bandeau.php
Скрипт v-bandeau.php генерує вигляд, який буде розміщено в зоні [vue1]:
<table>
<tr>
<td><img src="univ01.gif"></td>
<td>
<table>
<tr>
<td><div class='titre'><?php echo $dReponse['titre'] ?></div></td>
</tr>
<tr>
<td><div class='resultat'><?php echo $dReponse['resultat']?></div></td>
</tr>
</table>
</td>
</tr>
</table>
Генератор подання повинен визначити два динамічні елементи, розміщені у словнику $dReponse та пов’язані з такими ключами:
- заголовок: заголовок, що відображається
- resultat: сума податку до сплати
4.14.4. Елементарний вигляд v-formulaire.php
Частина [vue2] відповідає або погляду [v-formulaire], або погляду [v-erreurs]. Вигляд [v-formulaire] генерується скриптом v-formulaire.php:
<form method="post" action="main.php?action=calculerimpot">
<table>
<tr>
<td class="libelle">Etes-vous marié(e)</td>
<td class="valeur">
<input type="radio" name="optmarie" <?php echo $dReponse['optoui'] ?> value="oui">oui
<input type="radio" name="optmarie" <?php echo $dReponse['optnon'] ?> value="non">non
<td>
<tr>
<td class="libelle">Nombre d'enfants</td>
<td class="valeur">
<input type="text" class="text" name="txtenfants" size="3" value="<?php echo $dReponse['enfants'] ?>"
</td>
</tr>
<tr>
<td class="libelle">Salaire annuel</td>
<td class="valeur">
<input type="text" class="text" name="txtsalaire" size="10" value="<?php echo $dReponse['salaire'] ?>"
</td>
</tr>
</table>
<hr>
<input type="submit" class="submit" value="Calculer l'impôt">
</form>
<form method="post" action="main.php?action=effacerformulaire">
<input type="submit" class="submit" value="Effacer le formulaire">
</form>
Динамічні частини цього виду, які повинні бути визначені генератором видів, пов'язані з наступними ключами словника $dReponse:
- optoui: стан перемикача з іменем optoui
- optnon: стан перемикача з назвою optnon
- діти: кількість дітей, яку слід розмістити в полі txtenfants
- salaire: річний оклад, який слід розмістити в полі txtsalaire
4.14.5. Елементарний вигляд v-erreurs.php
Вигляд [v-erreurs] генерується скриптом v-erreurs.php:
Les erreurs suivantes se sont produites :
<ul>
<?php
for($i=0;$i<count($dReponse["erreurs"]);$i++){
echo "<li class='erreur'>".$dReponse["erreurs"][$i]."</li>\n";
}//for
?>
</ul>
<div class="info"><?php echo $dReponse["info"] ?></div>
<br>
<a href="<?php echo $dReponse["href"] ?>"><?php echo $dReponse["lien"] ?></a>
Динамічні частини цього виду, які визначаються генератором видів, пов'язані з наступними ключами словника $dReponse:
- помилки: масив повідомлень про помилки
- info: інформаційне повідомлення
- посилання: текст посилання
- href: URL-адреса, на яку веде вищезазначене посилання
4.14.6. Таблиця стилів
Усі види «оформлюються» за допомогою таблиці стилів. Щоб змінити зовнішній вигляд програми, потрібно змінити її таблицю стилів. Наступна таблиця стилів 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. Генератори переглядів
4.15.1. Роль генератора подання
Нагадаємо послідовність коду контролера, що запускає генератор подання:
<?php
…
// обробка дії
$scriptAction=$dConfig['actions'][$sAction] ?
$dConfig['actions'][$sAction]['url'] :
$dConfig['actions']['actionInvalide']['url'];
include $scriptAction;
// відправлення відповіді (перегляду) клієнту
$sEtat=$dSession['etat']['principal'];
$scriptVue=$dConfig['etats'][$sEtat]['vue'];
include $scriptVue;
Генератор подання пов'язаний зі станом, у якому буде розміщено додаток. Зв'язок між станом і генератором подання встановлюється за допомогою конфігурації:
<?php
…
// налаштування станів додатка
$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'));
Ми вже розповідали про роль генератора подання. Нагадаємо про це ще раз. Генератор подання:
- визначає у $dReponse['vuereponse'] ім’я шаблону відповіді, який слід використовувати. Ця інформація передається контролеру. Шаблон — це сукупність елементарних подань, які разом утворюють кінцеве подання.
- готує динамічну інформацію для відображення в кінцевому вигляді. Цей етап не залежить від контролера. Це інтерфейс між генератором видів та кінцевим видом. Він є специфічним для кожного додатка.
- обов’язково завершується викликом функції finSession контролера. Ця функція
- збереже сесію
- надіслати відповідь
4.15.2. Генератор подання, пов'язаний зі станом [e-formulaire]
Скрипт, що відповідає за генерацію подання, пов’язаного зі станом [e-formulaire], називається e-formulaire.php:
<?php
…
$dConfig['etats']['e-formulaire']=array(
'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
'vue'=>'e-formulaire.php');
Його код такий:
<?php
// підготовка відповіді у вигляді форми
$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'];
// налаштування відповідно до типу форми, що генерується
$type=$dSession['etat']['secondaire'];
if($type=='init'){
// порожня форма
$dReponse['optnon']='checked';
}//if
if($type=='calculimpot'){
// необхідно знову відобразити параметри введення, збережені в запиті
$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'){
// потрібно знову відобразити параметри введення, збережені в сесії
$dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';
$dReponse['enfants']=$dSession['requete']['txtenfants'];
$dReponse['salaire']=$dSession['requete']['txtsalaire'];
}//if
// надсилаємо відповідь
finSession($dConfig,$dReponse,$dSession);
?>
Слід зауважити, що генератор подання відповідає вимогам, що висуваються до генератора подання:
- у файлі $dReponse['vuereponse'] задано шаблон відповіді, який слід використовувати
- передавати інформацію до цієї моделі. Тут вона передається за допомогою словника $dReponse.
- завершується викликом функції finSession контролера
Тут використовується модель «модель1». Тому генератор визначає дві величини, необхідні цій моделі: $dReponse['vue1'] та $dReponse['vue2'].
У конкретному випадку нашого додатка представлення, пов’язане зі станом [e-formulaire], залежить від інформації, що зберігається у змінній $dSession['etat']['secondaire']. Це вибір розробників. Інший додаток міг би вирішити передавати додаткову інформацію іншим способом. Крім того, тут уся інформація, необхідна для відображення кінцевого виду, розміщується у словнику $dReponse. І в цьому випадку вибір залишається за розробником. Стан [e-formulaire] може виникнути після чотирьох різних дій: init, calculerimpot, retourformulaire, effacerformulaire. Вигляд, який потрібно відобразити, не є однаковим у всіх випадках. Тому в $dSession['etat']['secondaire'] було виділено три випадки:
- init: форма відображається порожньою
- calculimpot: форма відображається із сумою податку та даними, на основі яких було здійснено розрахунок
- retourformulaire: форма відображається з даними, що були введені спочатку
Вищезазначений скрипт e-formulaire.php використовує цю інформацію для відображення відповіді у цих трьох варіантах.
4.15.3. Вигляд, пов’язаний зі звітом [e-erreurs]
Скрипт, що відповідає за формування подання, пов’язаного зі звітом [e-erreurs], має назву e-erreurs.php і виглядає наступним чином:
<?php
// готуємо відповідь на помилки
$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';
// додаткова інформація
$type=$dSession['etat']['secondaire'];
if($type=='database'){
$dReponse['info']="Veuillez avertir l'administrateur de l'application";
}
// надсилаємо відповідь
finSession($dConfig,$dReponse,$dSession);
?>
4.15.4. Відображення кінцевого виду
Обидва скрипти, що генерують обидва кінцеві види, закінчуються викликом функції finSession контролера:
<?php
…
function finSession(&$dConfig,&$dReponse,&$dSession){
// $dConfig: словник конфігурації
// $dSession: словник, що містить інформацію про сесію
// $dReponse: словник аргументів сторінки відповіді
....
// відображення відповіді
include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];
// кінець скрипта
exit(0);
}//закінчення сесії
Вигляд, що надсилається користувачеві, визначається сутністю $dReponse['vuereponse'], яка визначає шаблон, що використовується для остаточної відповіді. Для звітів [e-formulaire] та [e-erreurs] цей шаблон було визначено як modele1:
Цей шаблон за конфігурацією відповідає скрипту m-reponse.php:
4.16. Зміна шаблону відповіді
Тут ми припускаємо, що вирішено змінити візуальний вигляд відповіді, що надається клієнту, і нас цікавить, які наслідки це матиме на рівні коду.
4.16.1. Новий шаблон
Тепер структура відповіді буде такою:
![]() |
Цей шаблон називатиметься modele2, а скрипт, відповідальний за його генерацію, — m-reponse2.php:
Скрипт, що відповідає цій моделі, має такий вигляд:
<html>
<head>
<title>Application impots</title>
<link type="text/css" href="<?php echo $dReponse['urlstyle'] ?>" rel="stylesheet" />
</head>
<body>
<table class='modele2'>
<!-- початок банера -->
<tr>
<td colspan="2"><?php include $dReponse['vue1']; ?></td>
</tr>
<!-- кінець банера -->
<tr>
<!-- початок меню -->
<td><?php include $dReponse['vue2']; ?></td>
<!-- кінець меню -->
<!-- початок зони 3 -->
<td><?php include $dReponse['vue3']; ?></td>
<!-- кінець зони 3 -->
</tr>
</table>
</body>
</html>
Динамічні елементи шаблону такі:
- $dReponse['urlstyle']: таблиця стилів, яку слід використовувати
- $dReponse['vue1']: скрипт, який слід використовувати для генерації [vue1]
- $dReponse['vue2']: скрипт, який слід використовувати для генерації [vue2]
- $dReponse['vue3']: скрипт, який слід використовувати для генерації [vue3]
Ці елементи повинні бути визначені генераторами переглядів.
4.16.2. Різні сторінки відповідей
Відтепер додаток відображатиме користувачеві такі відповіді. Під час першого виклику сторінка відповіді буде такою:
![]() |
Якщо користувач вкаже правильні дані, податок буде розраховано:
![]() |
Якщо він допустить помилки при введенні даних, відобразиться сторінка з повідомленням про помилки:
![]() |
Якщо він скористається посиланням [Retour au formulaire de saisie], то повернеться до форми в тому вигляді, в якому її підтвердив:
![]() |
Якщо вище він використовує посилання [Réinitialiser le formulaire], то бачить порожню форму:
![]() |
Слід зауважити, що додаток використовує ті самі дії, що й раніше. Змінився лише вигляд відповідей.
4.16.3. Елементарні види
Елементарний вигляд [vue1], як і в попередньому прикладі, буде пов’язаний зі скриптом v-bandeau.php:
<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>
Цей вигляд має два динамічні елементи:
- $dReponse['titre']: заголовок, що відображається
- $dReponse['resultat']: сума податку до сплати
Елементарний вигляд [vue2] буде пов’язаний із таким скриптом v-menu.php:
<table class="menu">
<tr>
<td><div class="menu">Options</div></td>
</tr>
<?php
for($i=0;$i<count($dReponse['liens']);$i++){
echo '<tr><td><div class="option"><a href="'.
$dReponse['liens'][$i]['url'].
'">'.$dReponseQZXW2HTMLBWydsaWVucyddZQXQZXW2HTMLBWyRpXQZQXQZXW2HTMLBWyd0ZXh0ZSddZQX."</a></div></td></tr>\n";
}//$i
?>
</table>
Цей вигляд містить такі динамічні елементи:
- $dReponse['liens']: масив посилань, які потрібно відобразити в [vue2]. Кожен елемент масиву є словником із двома ключами:
- 'url' — цільова URL-адреса посилання
- 'текст' — текст посилання
Елементарний вигляд [vue3] буде пов'язаний зі скриптом v-formulaire2.php, якщо потрібно відобразити форму введення даних, або зі скриптом v-erreurs2.php, якщо потрібно відобразити сторінку помилок. Код скрипта v-formulaire2.php такий:
<form method="post" action="main.php?action=calculerimpot">
<table>
<tr>
<td class="libelle">Etes-vous marié(e)</td>
<td class="valeur">
<input type="radio" name="optmarie" <?php echo $dReponse['optoui'] ?> value="oui">oui
<input type="radio" name="optmarie" <?php echo $dReponse['optnon'] ?> value="non">non
</td>
</tr>
<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>
Динамічні частини цього виду, які повинні бути визначені генератором видів, пов'язані з наступними ключами словника $dReponse:
- optoui: стан перемикача з іменем optoui
- optnon: стан перемикача з назвою optnon
- діти: кількість дітей, яку слід розмістити в полі txtenfants
- salaire: річний оклад, який слід розмістити у полі txtsalaire
Скрипт, що генерує сторінку помилок, називається v-erreurs2.php. Його код такий:
Les erreurs suivantes se sont produites :
<ul>
<?php
for($i=0;$i<count($dReponse["erreurs"]);$i++){
echo "<li class='erreur'>".$dReponse["erreurs"][$i]."</li>\n";
}//для
?>
</ul>
<div class="info"><?php echo $dReponse["info"] ?></div>
Динамічні частини цього виду, які визначаються генератором видів, пов'язані з наступними ключами словника $dReponse:
- помилки: масив повідомлень про помилки
- info: інформаційне повідомлення
4.16.4. Таблиця стилів
Він не змінився. Це все ще style1.css.
4.16.5. Новий файл конфігурації
Щоб впровадити ці нові види, нам доводиться змінити деякі рядки у файлі конфігурації.
<?php
// налаштування PHP
ini_set("register_globals","off");
ini_set("display_errors","off");
ini_set("expose_php","off");
// список модулів для включення
$dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');
// контролер додатка
$dConfig['webapp']=array('titre'=>"Calculez votre impôt");
// конфігурація подання додатка
$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';
// конфігурація дій додатка
$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');
// конфігурація станів додатка
$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'));
// конфігурація шаблону додатка
$dConfig["DSN"]=array(
"sgbd"=>"mysql",
"user"=>"seldbimpots",
"mdp"=>"mdpseldbimpots",
"host"=>"localhost",
"database"=>"dbimpots"
);
?>
Основна зміна полягає у заміні генераторів переглядів, пов’язаних із звітами [e-formulaire] та [e-erreurs]. Після цього нові генератори переглядів відповідають за формування нових сторінок відповідей.
4.16.6. Генератор подання, пов’язаний зі звітом [e-formulaire]
У файлі конфігурації звіт [e-formulaire] тепер пов’язаний із генератором перегляду e-formulaire2.php. Код цього скрипта такий:
<?php
// підготовка відповіді форми
$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')
);
// налаштування залежно від типу форми, що генерується
$type=$dSession['etat']['secondaire'];
if($type=='init'){
// порожня форма
$dReponse['optnon']='checked';
}//if
if($type=='calculimpot'){
// необхідно знову відобразити параметри введення, збережені в запиті
$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'){
// потрібно знову відобразити параметри введення, збережені в сесії
$dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
$dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';
$dReponse['enfants']=$dSession['requete']['txtenfants'];
$dReponse['salaire']=$dSession['requete']['txtsalaire'];
}//if
// надсилаємо відповідь
finSession($dConfig,$dReponse,$dSession);
?>
Основні зміни такі:
- генератор подання вказує, що він хоче використовувати шаблон відповіді modele2
- з цієї причини він заповнює динамічні елементи $dReponse['vue1'], $dReponse['vue2'], $dReponse['vue3'] — усі три необхідні для шаблону відповіді modele2.
- генератор також заповнює динамічний елемент $dReponse['liens'], який визначає посилання, що мають відображатися в області [vue2] відповіді.
4.16.7. Генератор подання, пов’язаний зі станом [e-erreurs]
У файлі конфігурації звіт [e-erreurs] тепер пов’язаний із генератором подання e-erreurs2.php. Код цього скрипта такий:
<?php
// готуємо відповідь на помилки
$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')
);
// додаткова інформація
$type=$dSession['etat']['secondaire'];
if($type=='database'){
$dReponse['info']="Veuillez avertir l'administrateur de l'application";
}
// відправляється відповідь
finSession($dConfig,$dReponse,$dSession);
?>
Внесені зміни ідентичні змінам, внесеним до генератора подання e-formulaire2.php.
4.17. Висновок
На прикладі ми змогли продемонструвати переваги нашого універсального контролера. Нам не довелося його писати. Ми обмежилися написанням скриптів дій, генераторів подання та подань додатка. Крім того, ми продемонстрували переваги відокремлення дій від подань. Таким чином, ми змогли змінити вигляд відповідей, не змінюючи жодного рядка коду в скриптах дій. Змінювалися лише скрипти, пов’язані з генерацією подань. Щоб це було можливо, скрипт дії не повинен робити жодних припущень щодо подання, яке відображатиме обчислені ним дані. Він повинен лише передавати ці дані контролеру, який, у свою чергу, передає їх генератору подань для форматування. Це абсолютне правило: дія повинна бути повністю відокремлена від подань.
У цьому розділі ми ознайомилися з філософією Struts, добре відомою розробникам Java. Проєкт з відкритим кодом під назвою php.mvc дозволяє здійснювати веб-розробку на PHP з використанням філософії Struts. Більше інформації можна знайти на сайті http://www.phpmvc.net/.













