Skip to content

4. یک برنامهٔ نمونه

ما پیشنهاد می‌کنیم روش قبلی را با مثالی از محاسبه مالیات نشان دهیم.

4.1. مسئله

هدف ما نوشتن برنامه‌ای برای محاسبه بدهی مالیاتی یک مؤدی است. ما مورد ساده‌شده‌ی مؤدی‌ای را در نظر می‌گیریم که تنها حقوق خود را برای اظهار دارد:

  • ما تعداد طبقات مالیاتی کارمند را به صورت nbParts = nbEnfants/2 + 1 در صورتی که متأهل نباشد، محاسبه می‌کنیم، nbEnfants/2 + 2 اگر متأهل باشند، که در آن nbEnfants تعداد فرزندان آنهاست. تعداد پایه‌های مالیاتی در صورت وجود سه فرزند یا بیشتر 0.5 واحد افزایش می‌یابد.
  • درآمد مشمول مالیات او R به صورت R = 0.72 × S محاسبه می‌شود، که در آن S حقوق سالانه او است.
  • ضریب خانوادگی او Q به صورت Q = R/N محاسبه می‌شود.
  • مالیات I او بر اساس داده‌های زیر محاسبه می‌شود
آستانه
coeffR
coeffN
۱۲۶۲۰.۰
0
0
۱۳۱۹۰
0.05
۶۳۱
۱۵٬۶۴۰
0.1
۱٬۲۹۰٫۵
۲۴٬۷۴۰
0.15
۲٬۰۷۲٫۵
۳۱٬۸۱۰
0.2
۳٬۳۰۹٫۵
۳۹٬۹۷۰
0.25
۴٬۹۰۰
۴۸٬۳۶۰
0.3
۶۸۹۸.۵
۵۵٬۷۹۰
0.35
۹٬۳۱۶٫۵
۹۲٬۹۷۰
0.4
۱۲٬۱۰۶
۱۲۷٬۸۶۰
0.45
۱۶٬۷۵۴٫۵
۱۵۱٬۲۵۰
0.50
۲۳٬۱۴۷٫۵
۱۷۲۰۴۰
0.55
۳۰٬۷۱۰
۱۹۵٬۰۰۰
0.60
۳۹٬۳۱۲
0
0.65
۴۹٬۰۶۲
هر سطر سه فیلد محدوده دارد: coeffR، coeffN. برای محاسبه مالیات I، اولین ردیفی را که QF ≤ حد باشد، پیدا می‌کنیم. برای مثال، اگر QF = 30000 باشد، ردیف زیر را پیدا خواهیم کرد: 31810 0.2 3309.5. مالیات I سپس برابر است با 0.2*R – 3309.5*nbParts. اگر QF به گونه‌ای باشد که شرط QF <= limit هرگز برقرار نشود، آنگاه ضرایب ردیف آخر استفاده می‌شوند: 0 0.65 49062، که مالیات I = 0.65*R را می‌دهد. – ۴۹۰۶۲ × nbParts.

4.2. پایگاه داده

داده‌های فوق در پایگاه‌دادهٔ MySQL که با نام dbimpots شناخته می‌شود، ذخیره شده‌اند. کاربر seldbimpots با رمز عبور mdpseldbimpots دسترسی فقط خواندنی به محتویات پایگاه‌داده دارد. پایگاه‌داده شامل یک جدول واحد به نام impots با ساختار زیر است:

Image

محتویات آن به شرح زیر است:

Image

4.3. معماری برنامه MVC

اپلیکیشن معماری زیر را خواهد داشت: MVC:

  • کنترل‌کننده main.php همان کنترل‌کننده عمومی توصیف‌شده در بالا خواهد بود
  • درخواست مشتری در قالب یک پرس‌وجوی به شکل main.php?action=xx به کنترلر ارسال می‌شود. مقدار پارامتر 'action' تعیین می‌کند که کدام اسکریپت در بلوک ACTIONS باید اجرا شود. اسکریپت اکشن، پس از اجرا، یک متغیر را به کنترلر بازمی‌گرداند که وضعیت مورد نظر برای اپلیکیشن وب را مشخص می‌کند. کنترلر با در دست داشتن این وضعیت، یکی از تولیدکننده‌های نما (view generator) را فعال می‌کند تا پاسخ را برای کلاینت ارسال کند.
  • 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;
      }//اگر

      // اجرای پرس‌وجو
      $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;
      }//اگر     
    }//اجرا

    // ------------------------------------------------------------------
    function getData(){
      // سه مجموعه داده‌های محدوده، coeffr، coeffn را بازیابی کنید
      $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'];                
      }//در حالی که
      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";
    }//برای
  }//اگر

  // خروج
  $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;
    }//اگر
    // بدون خطا
    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: دیکشنری با کلیدهای زیر
      // فرزندان: تعداد فرزندان
      // حقوق: حقوق سالانه
      // married: بولی که نشان می‌دهد مالیات‌دهنده متأهل است یا خیر
      // مالیات(ها): مالیات قابل پرداخت محاسبه شده توسط این سازنده
      // $data: دیکشنری حاوی کلیدهای زیر
      //آستانه‌ها: جدول آستانه‌های طبقات مالیاتی
      // coeffr: جدول ضرایب درآمد
      // coeffn: جدول ضرایب برای تعداد سهام
      // هر سه جدول دارای تعداد یکسانی از عناصر هستند

      //محاسبه تعداد سهام
      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;
    }//اگر
    // بدون خطا
    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]);
  }//برای  

  // شروع یا از سرگیری جلسه
  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';
  }//اگر

     //پردازش اقدام
  $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";
    }//در حالی که
  }//پیگیری

  //--------------------------------------------------------------------
  function trace($msg){
      echo $msg."<br>\n";
  }//پیگیری
?>

4.9. اقدامات در برنامه وب

چهار اکشن وجود دارد:

  • get:init: این اکشنی است که در درخواست اولیه به کنترلر بدون هیچ پارامترهایی اجرا می‌شود. این اکشن نمای خالی «form» را تولید می‌کند.
  • post:effacerformulaire: اکشنی که توسط دکمه [Effacer le formulaire] فراخوانی می‌شود. این اکشن نمای خالی [v-formulaire] را تولید می‌کند.
  • post:calculate_tax: اکشنی که با دکمه [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'] تعریف شده است. این حالت قرار است در جلسه (session) ذخیره شود. علاوه بر این، اقدام در دیکشنری $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'));        

درون یک حالت، اقدامات مجاز با اهداف URL پیوندها یا دکمه‌های [submit] در نمای مرتبط با آن حالت مطابقت دارند. علاوه بر این، اقدام «get:init» همیشه مجاز است. این امکان را برای کاربر فراهم می‌کند تا URL main.php را از لیست URL مرورگر خود بازیابی کرده و صرف‌نظر از وضعیت برنامه، آن را باز پخش کند. این نوعی ریست «دستی» است. حالت «بدون حالت» تنها زمانی وجود دارد که برنامه راه‌اندازی می‌شود.

هر وضعیت از برنامه با یک اسکریپت مرتبط است که مسئول تولید نمای مربوط به آن وضعیت است:

  • وضعیت [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'] مشخص شود.
  • ممکن است یک اسکریپت اکشن بخواهد اطلاعاتی را در جلسه (session) ذخیره کند. این کار را با قرار دادن اطلاعات در دیکشنری $dSession انجام می‌دهد، که توسط کنترلر در پایان چرخه درخواست-پاسخ به طور خودکار در جلسه ذخیره می‌شود.
  • یک اسکریپت اکشن ممکن است اطلاعاتی برای ارسال به ویوها داشته باشد. این جنبه مستقل از کنترلر است. این رابط بین اکشن‌ها و ویوها را تشکیل می‌دهد، رابطی که برای هر برنامه مشخص است. در مثال مورد بررسی در اینجا، اکشن‌ها اطلاعات را از طریق یک دیکشنری به نام $dReponse در اختیار تولیدکنندگان ویو قرار می‌دهند.

4.12.2. اقدام get:init

این اکشنی است که فرم خالی را تولید می‌کند. فایل پیکربندی نشان می‌دهد که این توسط اسکریپت a-init.php مدیریت خواهد شد:

  $dConfig['actions']['get:init']=array('url'=>'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:calculate_tax»

این اکشن مالیات را بر اساس داده‌های وارد شده در فرم محاسبه می‌کند. فایل پیکربندی مشخص می‌کند که اسکریپت a-calculimpot.php این اکشن را مدیریت خواهد کرد:

  $dConfig['actions']['post:calculerimpot']=array('url'=>'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(! $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;
    }//اگر
    // بدون خطا – داده‌ها در جلسه قرار می‌گیرند
    $dSession['limites']=&$limites;
    $dSession['coeffr']=&$coeffr;
    $dSession['coeffn']=&$coeffn;
  }//اگر

  // در اینجا داده‌های لازم برای محاسبه مالیات را داریم
  // ما مالیات را محاسبه می‌کنیم
  $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] و با نوع محاسبه مالیات مشخص‌شده در $dSession['etat']['secondaire'] تنظیم می‌شود. فایل پیکربندی نشان می‌دهد که این اسکریپت e-formulaire.php است که نمای پاسخ را تولید خواهد کرد. این اسکریپت از مقدار موجود در $dSession['etat']['secondaire'] برای تولید یک فرم از پیش پرشده با مقادیر واردشده توسط کاربر و همچنین مبلغ مالیات استفاده خواهد کرد.

4.12.4. عملکرد ارسال: پاک کردن فرم

این پیکربندی شده است تا با اسکریپت a-init.php که در بالا توضیح داده شده است، مرتبط باشد.

  $dConfig['actions']['post:effacerformulaire']=array('url'=>'a-init.php');

4.12.5. عمل GET: return-form

این امکان را برای کاربر فراهم می‌کند تا از گزارش [e-erreurs] به گزارش [e-formulaire] بازگردد. اسکریپت a-retourformulaire.php این اقدام را مدیریت می‌کند:

  $dConfig['actions']['get:retourformulaire']=array('url'=>'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 اجرا می‌شود:

  $dConfig['actions']['enchainementinvalide']=array('url'=>'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');

ما بعداً به کد این ژنراتور نگاه خواهیم کرد. نمایی که به کلاینت ارسال می‌شود به شرح زیر است:

Image

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';
  }//اگر

     // اقدام را پردازش کنید
  $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. قالب پاسخ

برنامه پاسخ‌های مختلف خود را بر اساس یک قالب واحد زیر تولید خواهد کرد:

این مدل با کلید 'model1' در دیکشنری $dConfig['vuesreponse'] مرتبط است:

  $dConfig['vuesReponse']['modele1']=array('url'=>'m-reponse.php');

اسکریپت 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 صفحهٔ سبک قالب
  • view1: نام اسکریپت مسئول تولید view1
  • 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 تعریف کند که با کلیدهای زیر مرتبط هستند:

  • عنوان: عنوانی که باید نمایش داده شود
  • result: مبلغ مالیات پرداختنی

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»
  • children: تعداد فرزندانی که باید در فیلد txtenfants قرار گیرند
  • salary: حقوق سالانه برای قرار گرفتن در فیلد txtsalary

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";
        }//برای
    ?>
</ul>
<div class="info"><?php echo $dReponse["info"] ?></div>
<br>
<a href="<?php echo $dReponse["href"] ?>"><?php echo $dReponse["lien"] ?></a>

بخش‌های پویا این نما که باید توسط تولیدکننده نما تعریف شوند، با کلیدهای زیر در فرهنگ لغت $dReponse مرتبط هستند:

  • errors: آرایه پیام‌های خطا
  • info: پیام اطلاعاتی
  • link: متن یک پیوند
  • href: نشانی هدف پیوند بالا

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-formulairee-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($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($type=='retourformulaire'){
      // اگر نیاز باشد پارامترهای ورودی ذخیره‌شده در جلسه را مجدداً نمایش دهیم
    $dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
    $dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';  
    $dReponse['enfants']=$dSession['requete']['txtenfants'];
    $dReponse['salaire']=$dSession['requete']['txtsalaire'];
  }//اگر
  // پاسخ را ارسال می‌کنیم
  finSession($dConfig,$dReponse,$dSession);
?>      

شایان ذکر است که ژنراتور نما با شرایط تحمیل‌شده بر یک ژنراتور نما مطابقت دارد:

  • تعیین قالب پاسخ مورد استفاده در $dReponse['vuereponse']
  • اطلاعات را به این قالب ارسال کنید. در اینجا، این اطلاعات از طریق دیکشنری $dReponse ارسال می‌شود.
  • با فراخوانی تابع کنترل‌کننده finSession پایان می‌یابد

در اینجا، مدل مورد استفاده 'model1' است. بنابراین، ژنراتور دو مورد اطلاعات مورد نیاز این مدل را تعریف می‌کند: $dReponse['vue1'] و $dReponse['vue2'].

در مورد خاص برنامه ما، نمای مرتبط با وضعیت [e-formulaire] به اطلاعاتی که در متغیر $dSession['etat']['secondaire'] ذخیره شده است، بستگی دارد. این یک انتخاب توسعه‌ای است. یک برنامهٔ دیگر ممکن است اطلاعات اضافی را به روش متفاوتی منتقل کند. علاوه بر این، در اینجا تمام اطلاعات مورد نیاز برای نمایش نمای نهایی در دیکشنری $dReponse قرار داده شده است. باز هم، این یک انتخاب است که به توسعه‌دهنده واگذار شده است. وضعیت [e-formulaire] می‌تواند در پی چهار اقدام مختلف رخ دهد: init، calculateTax، returnForm، clearForm. نمائی که باید نمایش داده شود در همه موارد دقیقاً یکسان نیست. بنابراین، سه حالت در اینجا در $dSession['etat']['secondaire'] متمایز شده‌اند:

  • init: فرم خالی نمایش داده می‌شود
  • محاسبه مالیات: فرم با مبلغ مالیات و داده‌های مورد استفاده برای محاسبه آن نمایش داده می‌شود
  • 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' تنظیم شده است:

    $dReponse['vuereponse']='modele1';

این قالب، بر اساس پیکربندی، با اسکریپت m-reponse.php مطابقت دارد:

  $dConfig['vuesReponse']['modele1']=array('url'=>'m-reponse.php');

4.16. ویرایش قالب پاسخ

ما در اینجا فرض می‌کنیم که تصمیمی برای تغییر ظاهر بصری پاسخ ارسال‌شده به مشتری گرفته شده است و ما علاقه‌مند به درک پیامدهای این موضوع برای کد هستیم.

4.16.1. قالب جدید

ساختار پاسخ اکنون به شرح زیر خواهد بود:

این قالب modele2 نامیده خواهد شد و اسکریپت مسئول تولید این قالب m-reponse2.php نامیده خواهد شد:

  $dConfig['vuesReponse']['modele2']=array('url'=>'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>
            <!--پایان منو -->
            <!-- شروع بخش ۳ -->                        
          <td><?php include $dReponse['vue3']; ?></td>
            <!--پایان بخش ۳ -->        
      </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."
    }//$i
  ?>
</table>

این نما شامل عناصر پویا زیر است:

  • $dReponse['liens']: آرایه‌ای از لینک‌ها که باید در [vue2] نمایش داده شوند. هر عنصر این آرایه یک دیکشنری با دو کلید است:
    • 'url': URL مقصد لینک
    • 'text': متن لینک

ویوی پایه [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
  • children: تعداد فرزندانی که باید در فیلد txtenfants قرار گیرند
  • salary: حقوق سالانه که باید در فیلد txtsalary قرار گیرد

اسکریپتی که صفحه خطا را تولید می‌کند، 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 مرتبط هستند:

  • errors: آرایه پیام‌های خطا
  • 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($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($type=='retourformulaire'){
      // اگر نیاز باشد پارامترهای ورودی ذخیره شده در جلسه را مجدداً نمایش دهیم
    $dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
    $dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';  
    $dReponse['enfants']=$dSession['requete']['txtenfants'];
    $dReponse['salaire']=$dSession['requete']['txtsalaire'];
  }//اگر
  // پاسخ را ارسال می‌کنیم
  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 را که برای توسعه‌دهندگان جاوا به خوبی شناخته شده است، بررسی کردیم. یک پروژه متن‌باز به نام php.mvc توسعه وب/PHP را با استفاده از فلسفه Struts امکان‌پذیر می‌سازد. لطفاً برای اطلاعات بیشتر به http://www.phpmvc.net/ مراجعه کنید.