Skip to content

4. Örnek bir uygulama

Yukarıdaki yöntemi bir vergi hesaplama örneği ile açıklamayı amaçlıyoruz.

4.1. Sorun

Bir vergi mükellefinin vergisini hesaplamaya yarayan bir program yazmayı hedefliyoruz. Beyan edeceği tek geliri maaşı olan bir vergi mükellefi gibi basitleştirilmiş bir durum ele alıyoruz:

  • çalışanın pay sayısını şu şekilde hesaplayacağız: nbParts = nbEnfants/2 + 1 (evli değilse), evliyse nbEnfants/2+2 olarak hesaplanır; burada nbEnfants, çocuk sayısıdır. Üç veya daha fazla çocuğu varsa pay sayısı 0,5 artırılır.
  • Vergilendirilebilir geliri R=0,72*S olarak hesaplanır; burada S, yıllık maaşıdır
  • Aile katsayısı Q = R/N olarak hesaplanır
  • Aşağıdaki verilere göre vergi tutarı I hesaplanır
sınır
coeffR
coeffN
12620,0
0
0
13190
0,05
631
15640
0,1
1290,5
24.740
0,15
2072,5
31810
0,2
3309,5
39.970
0,25
4900
48360
0,3
6898,5
55790
0,35
9316,5
92970
0,4
12106
127.860
0,45
16754,5
151250
0,50
23147,5
172.040
0,55
30710
195.000
0,60
39312
0
0,65
49.062
Her satırda 3 sınır alanı vardır: coeffR, coeffN. I vergisini hesaplamak için, QF <= sınır değerine eşit olan ilk satırı ararız. Örneğin, QF = 30000 ise şu satırı buluruz: 31810 0,2 3309,5. Bu durumda I vergisi, 0,2*R - 3309,5*nbParts'e eşittir. Eğer QF, QF<=sınır ilişkisini hiçbir zaman sağlamayacak şekilde ise, o zaman son satırdaki katsayılar kullanılır: 0 0,65 49062; bu da I=0,65*R - 49062*nbParts vergi tutarını verir.

4.2. Veritabanı

Yukarıdaki veriler, dbimpots adlı MySQL veritabanına kaydedilir. seldbimpots kullanıcı adı ve mdpseldbimpots şifresine sahip kullanıcı, veritabanının içeriğine salt okunur erişime sahiptir. Bu veritabanında, yapısı aşağıdaki gibi olan impots adlı tek bir tablo bulunur:

Image

İçeriği şu şekildedir:

Image

4.3. Uygulamanın MVC mimarisi

Uygulamanın mimarisi aşağıdaki gibi olacaktır: MVC

  • main.php denetleyicisi, daha önce açıklanan genel denetleyici olacaktır
  • Müşterinin isteği, main.php?action=xx biçiminde bir istek olarak denetleyiciye gönderilir. action parametresinin değeri, çalıştırılacak ACTIONS bloğunun komut dosyasını belirler. Çalıştırılan eylem komut dosyası, web uygulamasının hangi duruma getirilmesi gerektiğini belirten bir değişkeni denetleyiciye döndürür. Bu durumu alan denetleyici, yanıtı müşteriye göndermek için görünüm oluşturuculardan birini etkinleştirir.
  • impots-data.php, denetleyiciye ihtiyaç duyduğu verileri sağlamakla görevli sınıftır
  • impots-calcul.php, verginin hesaplanmasını sağlayan iş sınıfıdır

4.4. Veri erişim sınıfı

Veri erişim sınıfı, web uygulamasından verilerin kaynağını gizlemek üzere tasarlanmıştır. Arayüzünde, vergi hesaplaması için gerekli olan üç veri dizisini sağlayan getData adlı bir yöntem bulunur. Örneğimizde veriler, MySQL adlı bir veritabanından alınmaktadır. Sınıfı SGBD'in gerçek türünden bağımsız hale getirmek için, ekte açıklanan pear::DB kütüphanesini kullanacağız. Sınıfın kodu şöyledir:

<?php

  // kütüphaneler
  require_once 'DB.php';

  class impots_data{  
    // veri kaynağına erişim sınıfı DBIMPOTS

      // özellikler
    var $sDSN;                    // bağlantı dizesi
      var $sDatabase;            // veritabanı adı
    var $oDB;                        // veritabanına bağlantı
    var $aErreurs;            // hata listesi
    var $oRésultats;        // sorgu sonucu
        var $connecté;            // veritabanına bağlı olup olmadığını gösteren boole değeri
        var $sQuery;                // son çalıştırılan sorgu

    // oluşturucu
    function impots_data($dDSN){

        // $dDSN: kurulacak bağlantıyı tanımlayan sözlük
      // $dDSN['sgbd']: bağlanılması gereken SGBD türü
      // $dDSN['host']: bunu barındıran ana bilgisayarın adı      
      // $dDSN['database'] : bağlanılması gereken veritabanının adı      
      // $dDSN['user'] : veritabanındaki bir kullanıcı
      // $dDSN['mdp'] : şifresi

      // $oDB'te, $dDSN ile tanımlanan veritabanına $dDSN['user'] kimliği altında bir bağlantı oluşturur
      // bağlantı başarılı olursa  
          // $sDSN dosyasına veritabanı bağlantı dizesini kaydeder
          // bağlanılan veritabanının adını $sDataBase'e atar
        // $connecté değerini true olarak ayarlar
      // bağlantı başarısız olursa
          // uygun hata mesajlarını $aErreurs listesine ekler
        // gerekirse bağlantıyı kapatır
        // $connecté değerini "false" olarak ayarlar 

      // hata listesini sıfırlar
            $this->aErreurs=array();

      // $sDSN veritabanına bağlantı kurulur
      $this->sDSN=$dDSN["sgbd"]."://".$dDSN["user"].":".$dDSN["mdp"]."@".$dDSN["host"]."/".$dDSN["database"];
      $this->sDatabase=$dDSN["database"];
      $this->connect();

      // bağlandı mı?
      if( ! $this->connecté) return;

      // bağlantı başarıyla kuruldu     
      $this->connecté=TRUE;     
    }//üretici

    // ------------------------------------------------------------------
    function connect(){
        // veritabanına (yeniden) bağlanma
      // hata listesi sıfırlandı
            $this->aErreurs=array();

      // veritabanına bağlantı kuruluyor $sDSN
        $this->oDB=DB::connect($this->sDSN,true);

        // hata mı?
        if(DB::iserror($this->oDB)){
          // hata kaydediliyor
          $this->aErreurs[]="Echec de la connexion à la base [".$this->sDatabase."] : [".$this->oDB->getMessage()."]";
        // bağlantı başarısız
        $this->connecté=FALSE;
        // son
        return;
      }

      // bağlantı kuruldu
      $this->connecté=TRUE;
    }//bağlan

    // ------------------------------------------------------------------
    function disconnect(){
      // bağlıyken, sunucuya olan bağlantı kesilir $sDSN
        if($this->connecté){
              $this->oDB->disconnect();
          // bağlantı kesildi
        $this->connecté=FALSE;
            }//eğer
    }//bağlantı kes

    // -------------------------------------------------------------------
    function execute($sQuery){
        // $sQuery: yürütülecek istek

        // istek kaydediliyor
            $this->sQuery=$sQuery;    

      // bağlantı kuruldu mu?
      if(! $this->connecté){
          // hatayı kaydediyoruz
        $this->aErreurs[]="Pas de connexion existante à la base [$this->sDatabase]";
        // son
        return;
      }//if

      // isteğin yürütülmesi
      $this->oRésultats=$this->oDB->query($sQuery);

        // hata mı?
        if(DB::iserror($this->oRésultats)){
            // hata kaydediliyor
            $this->aErreurs[]="Echec de la requête [$sQuery] : [".$this->oRésultats->getMessage()."]";
          // geri dönüş
        return;
      }//if     
    }//yürütme

    // ------------------------------------------------------------------
    function getData(){
      // 3 sınır veri dizisi, coeffr, coeffn alınır
      $this->execute('select limites, coeffR, coeffN from impots');
      // hata var mı?
      if(count($this->aErreurs)!=0) return array();
      // select sorgusunun sonucunu tarıyoruz
      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

  }//sınıf
?>      

Bir test programı şu şekilde olabilir:

<?php

  // kütüphane
  require_once "c-impots-data.php";  
  require_once "DB.php";

    // impots-data sınıfı testi
  ini_set('track_errors','on');
  ini_set('display_errors','on');

     // dbimpots veritabanı temel yapılandırması
    $dDSN=array(
        "sgbd"=>"mysql",
        "user"=>"seldbimpots",
        "mdp"=>"mdpseldbimpots",
        "host"=>"localhost",
        "database"=>"dbimpots"
    );

  // oturum açma
  $oImpots=new impots_data($dDSN);
  // hatalar mı?
  if(checkErreurs($oImpots)){
    exit(0);
  }
  // izleme
  echo "Connecté à la base...\n";

  // sınır verileri, coeffr, coeffn verilerinin alınması
  list($limites,$coeffr,$coeffn)=$oImpots->getData();
  // hatalar?
  if( ! checkErreurs($oImpots)){
    // içerik
    echo "données : \n";
    for($i=0;$i<count($limites);$i++){
      echo "[$limites[$i],$coeffr[$i],$coeffn[$i]]\n";
    }//for
  }//if

  // bağlantı kesiliyor
  $oImpots->disconnect();
  // takip
  echo "Déconnecté de la base...\n";  
  // son
  exit(0);

  // ----------------------------------
  function checkErreurs(&$oImpots){
      // hata mı var?
    if(count($oImpots->aErreurs)!=0){
        // görüntüleme
      for($i=0;$i<count($oImpots->aErreurs);$i++){
          echo $oImpots->aErreurs[$i]."\n";
      }//for
      // hatalar
      return true;
    }//if
    // hata yok
    return false;
  }//checkErreurs  

?>     

Bu test programının çalıştırılması sonucunda aşağıdaki sonuçlar elde edilir:

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. Vergi hesaplama sınıfı

Bu sınıf, bir vergi mükellefinin vergisini hesaplamaya yarar. Bu hesaplamayı yapmak için gerekli veriler sınıfın oluşturucusuna sağlanır. Ardından sınıf, ilgili vergiyi hesaplar. Sınıfın kodu şöyledir:

<?php

  class impots_calcul{  
    // vergi hesaplama sınıfı

    // oluşturucu
    function impots_calcul(&$perso,&$data){
      // $perso: aşağıdaki anahtarları içeren sözlük
      // çocuk(lar): çocuk sayısı
      // maaş: yıllık maaş
      // evli: vergi mükellefinin evli olup olmadığını belirten boole değeri
      // vergi(ler): bu oluşturucu tarafından hesaplanan ödenecek vergi
      // $data: Aşağıdaki anahtarları içeren sözlük
      // sınırlar: gelir dilimi sınırlarını gösteren tablo
      // coeffr: gelir katsayıları tablosu
      // pay sayısı katsayıları tablosu
      // 3 tablo da aynı sayıda öğeye sahiptir

      // pay sayısının hesaplanması
      if($perso['marié'])
        $nbParts=$perso['enfants']/2+2;
        else $nbParts=$perso['enfants']/2+1;
      if ($perso['enfants']>=3) $nbParts+=0.5;

      // vergilendirilebilir gelir
      $revenu=0.72*$perso['salaire'];

      // aile katsayısı
      $QF=$revenu/$nbParts;

      // QF'e karşılık gelen vergi diliminin araştırılması
      $nbTranches=count($data['limites']);
      $i=0;
      while($i<$nbTranches-2 && $QF>$data['limites'][$i]) $i++;

      // vergi
      $perso['impot']=floor($data['coeffr'][$i]*$revenu-$data['coeffn'][$i]*$nbParts);
    }//üretici
  }//sınıf
?>

Bir test programı şu şekilde olabilir:

<?php

  // kütüphane
  require_once "c-impots-data.php";
  require_once "c-impots-calcul.php";  

     // dbimpots temel yapılandırması
    $dDSN=array(
        "sgbd"=>"mysql",
        "user"=>"seldbimpots",
        "mdp"=>"mdpseldbimpots",
        "host"=>"localhost",
        "database"=>"dbimpots"
    );

  // oturum açma
  $oImpots=new impots_data($dDSN);
  // hatalar mı?
  if(checkErreurs($oImpots)){
    exit(0);
  }
  // izleme
  echo "Connecté à la base...\n";  
  // sınır verileri, coeffr, coeffn'in alınması
  list($limites,$coeffr,$coeffn)=$oImpots->getData();
  // hatalar?
  if(checkErreurs($oImpots)){
    exit(0);
  }
  // bağlantı kesiliyor
  $oImpots->disconnect();
  // takip
  echo "Déconnecté de la base...\n";  

  // vergi hesaplaması
  $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);

  // son
  exit(0);

  // ----------------------------------
  function checkErreurs(&$oImpots){
      // hatalar mı var?
    if(count($oImpots->aErreurs)!=0){
        // görüntüleme
      for($i=0;$i<count($oImpots->aErreurs);$i++){
          echo $oImpots->aErreurs[$i]."\n";
      }//for
      // hatalar
      return true;
    }//if
    // hata yok
    return false;
  }//checkErreurs  

?>        

Bu test programının çalıştırılması sonucunda aşağıdaki sonuçlar elde edilir:

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. Uygulamanın işleyişi

Vergi hesaplama web uygulaması başlatıldığında, aşağıdaki [v-formulaire] ekranı görüntülenir:

Kullanıcı alanları doldurur ve vergi hesaplamasını talep eder:

Formun, kullanıcının onayladığı haliyle yeniden oluşturulduğu ve ayrıca ödenecek vergi tutarını da gösterdiği dikkatinizi çekecektir. Kullanıcı, veri girişi sırasında hatalar yapabilir. Bu hatalar, [v-erreurs] görünümü olarak adlandırılan bir hata sayfası aracılığıyla kullanıcıya bildirilir.

[Retour au formulaire de saisie] bağlantısı, kullanıcının onayladığı haliyle formu tekrar görüntülemesini sağlar.

Son olarak, [Effacer le formulaire] düğmesi, formu kullanıcının ilk talebinde aldığı haliyle, yani c.a.d'e geri döndürür.

4.7. Uygulamanın MVC mimarisine genel bakış

Uygulamanın mimarisi şu şekildedir: MVC

Az önce impots-data.php ve impots-calcul.php sınıflarını açıkladık. Şimdi mimarinin diğer öğelerini açıklayacağız.

4.8. Uygulamanın denetleyicisi

Uygulamanın main.php denetleyicisi, bu bölümün ilk kısmında açıklanan denetleyicidir. Bu, uygulamadan bağımsız, genel amaçlı bir denetleyicidir.

<?php
     // genel denetleyici

  // yapılandırma okuma
  include 'config.php';

  // kütüphanelerin eklenmesi
  for($i=0;$i<count($dConfig['includes']);$i++){
      include($dConfig['includes'][$i]);
  }//for  

  // oturumu başlatma veya devam ettirme
  session_start();
  $dSession=$_SESSION["session"];
  if($dSession) $dSession=unserialize($dSession);

  // yapılması gereken eylemi alıyoruz
  $sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
  $sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";

     // eylem dizisi normal mi?
  if( ! enchainementOK($dConfig,$dSession,$sAction)){  
    // sıralama anormal
    $sAction='enchainementinvalide';
  }//if

     // eylemin işlenmesi
  $scriptAction=$dConfig['actions'][$sAction] ? 
    $dConfig['actions'][$sAction]['url'] : 
    $dConfig['actions']['actionInvalide']['url'];
  include $scriptAction;


  // yanıtın (görünüm) müşteriye gönderilmesi
  $sEtat=$dSession['etat']['principal'];
  $scriptVue=$dConfig['etats'][$sEtat]['vue'];
  include $scriptVue;

  // komut dosyasının sonu - bir hata olmadığı sürece buraya gelinmemelidir
  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: yapılandırma sözlüğü
      // $dSession: oturum bilgilerini içeren sözlük
         // $dReponse: yanıt sayfasının argüman sözlüğü

    // oturum kaydı
    if(isset($dSession)){
      // istek parametreleri oturuma eklenir
      $dSession['requete']=strtolower($_SERVER['REQUEST_METHOD'])=='get' ? $_GET :
          strtolower($_SERVER['REQUEST_METHOD'])=='post' ? $_POST : array();
        $_SESSION['session']=serialize($dSession);
      session_write_close();
    }else{    
        // oturum yok
      session_destroy();
    }

        // yanıtın görüntülenmesi
        include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];

    // komut dosyasının sonu
    exit(0);
  }//oturum sonu      

  //--------------------------------------------------------------------
    function enchainementOK(&$dConfig,&$dSession,$sAction){
      // önceki duruma göre mevcut eylemin izinli olup olmadığını kontrol eder
    $etat=$dSession['etat']['principal'];
    if(! isset($etat)) $etat='sansetat';

    // eylem doğrulaması
    $actionsautorisees=$dConfig['etats'][$etat]['actionsautorisees'];
    $autorise= ! isset($actionsautorisees) || in_array($sAction,$actionsautorisees);
        return $autorise;    
  }

  //--------------------------------------------------------------------
  function dump($dInfos){
      // bilgi sözlüğünü görüntüler
    while(list($clé,$valeur)=each($dInfos)){
        echo "[$clé,$valeur]<br>\n";
    }//while
  }//izleme

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

4.9. Web uygulamasının eylemleri

Dört eylem vardır:

  • get:init: Denetleyiciye parametre içermeyen ilk istek geldiğinde tetiklenen eylemdir. Boş 'form' görünümünü oluşturur.
  • post:effacerformulaire: [Effacer le formulaire] düğmesi tarafından tetiklenen eylemdir. Boş [v-formulaire] görünümünü oluşturur.
  • post:calculerimpot: [Calculer l'impôt] düğmesi tarafından tetiklenen eylemdir. Ya ödenecek vergi tutarını içeren [v-formulaire] görünümünü ya da [v-erreurs] görünümünü oluşturur.
  • get:retourformulaire: [Retour au formulaire de saisie] bağlantısı tarafından tetiklenen eylem. Hatalı verilerle önceden doldurulmuş [v-formulaire] görünümünü oluşturur.

Bu eylemler, yapılandırma dosyasında şu şekilde yapılandırılmıştır:

<?php

  // uygulama eylemlerinin yapılandırılması
  $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');          

Her eyleme, onu işlemekle görevli bir komut dosyası atanır. Her eylem, web uygulamasını $dSession['etat']['principal'] öğesi tarafından belirlenen bir duruma getirir. Bu durum, oturumda kaydedilmek üzere tasarlanmıştır. Ayrıca, eylem, uygulamanın gireceği yeni durumla ilişkili görünümün görüntülenmesi için gerekli bilgileri $dReponse sözlüğüne kaydeder.

4.10. Web uygulamasının raporları

İki tane vardır:

  • [e-formulaire]: [v-formulaire] görünümünün farklı varyantlarının sunulduğu durum.
  • [e-erreurs]: [v-erreurs] görünümünün sunulduğu durum.

Bu durumlarda izin verilen eylemler şunlardır:

<?php

  // uygulama durumlarının yapılandırılması
  $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'));        

Bir durumda, izin verilen eylemler, durumla ilişkili görünümdeki [submit] bağlantılarının veya düğmelerinin hedefleri olan URL'lere karşılık gelir. Ayrıca, 'get:init' eylemi her zaman izin verilir. Bu, kullanıcının tarayıcısındaki URL main.php listesinden URL öğesini alıp, uygulamanın durumu ne olursa olsun yeniden oynatmasına olanak tanır. Bu, bir tür 'manuel' sıfırlamadır. 'sansetat' durumu yalnızca uygulamanın başlatılması sırasında mevcuttur.

Uygulamanın her durumuna, o durumla ilişkili görünümü oluşturmakla görevli bir komut dosyası atanmıştır:

  • [e-formulaire] durumu: e-formulaire.php komut dosyası
  • [e-erreurs] durumu: e-erreurs.php komut dosyası

[e-formulaire] durumu, [v-formulaire] görünümünü çeşitli varyantlarla gösterecektir. Nitekim, [v-formulaire] görünümü boş, önceden doldurulmuş veya vergi tutarı ile birlikte gösterilebilir. Uygulamayı [e-formulaire] durumuna geçiren eylem, $dSession['etat']['principal'] değişkeninde uygulamanın ana durumunu belirtir. Denetleyici yalnızca bu bilgiyi kullanır. Uygulamamızda, [e-formulaire] durumuna geçişi sağlayan eylem, $dSession['etat']['secondaire'] değişkenine, yanıt oluşturucununboş bir form mu, önceden doldurulmuş bir form mu, vergi tutarı dahil mi yoksa hariç mi oluşturması gerektiğini belirleyecektir. Burada üç farklı durum olduğunu ve dolayısıyla yazılması gereken üç farklı görünüm oluşturucu olduğunu varsayarak farklı bir şekilde de ilerleyebilirdik.

4.11. Web uygulamasının yapılandırma dosyası config.php

<?php

     // PHP yapılandırması
  ini_set("register_globals","off");
  ini_set("display_errors","off");  
  ini_set("expose_php","off");

  // eklenecek modüllerin listesi
  $dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');

  // uygulama denetleyicisi
  $dConfig['webapp']=array('titre'=>"Calculez votre impôt");

  // uygulama görünümlerinin yapılandırılması
  $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';  

  // uygulama eylemlerinin yapılandırılması
  $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');          

  // uygulama durumlarının yapılandırılması
  $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'));

  // uygulama şablon yapılandırması
    $dConfig["DSN"]=array(
        "sgbd"=>"mysql",
        "user"=>"seldbimpots",
        "mdp"=>"mdpseldbimpots",
        "host"=>"localhost",
        "database"=>"dbimpots"
    );
?>

4.12. Web uygulamasının eylemleri

4.12.1. Eylem komut dosyalarının genel işleyişi

  • Bir eylem komut dosyası, denetleyici tarafından istemciden alınan eylem parametresine göre çağrılır.
  • Çalıştırıldıktan sonra, eylem betiği denetleyiciye uygulamanın hangi duruma getirileceğini belirtmelidir. Bu durum, $dSession['etat']['principal'] içinde belirtilmelidir.
  • Bir eylem betiği, oturuma bilgi yerleştirmek isteyebilir. Bunu, bilgileri $dSession sözlüğüne yerleştirerek yapar; bu sözlük, istek-yanıt döngüsünün sonunda denetleyici tarafından otomatik olarak oturuma kaydedilir.
  • Bir eylem betiği, görünümlere aktarılacak bilgilere sahip olabilir. Bu husus, denetleyiciden bağımsızdır. Bu, eylemler ve görünümler arasındaki arayüzdür ve her uygulamaya özgüdür. Burada incelenen örnekte, eylemler $dReponse adlı bir sözlük aracılığıyla görünüm oluşturuculara bilgi sağlayacaktır.

4.12.2. get:init eylemi

Bu eylem, boş formu oluşturan eylemdir. Yapılandırma dosyası, bu eylemin a-init.php komut dosyası tarafından işleneceğini göstermektedir:

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

a-init.php betiğinin kodu şöyledir:

<?php
     // giriş formu görüntülenir
  $dSession['etat']=array('principal'=>'e-formulaire', 'secondaire'=>'init');
?>  

Bu komut dosyası, uygulamanın bulunması gereken durumu $dSession['etat']['principal'] olarak belirler, [e-formulaire] durumunu belirler ve $dSession['etat']['secondaire'] dosyasına bu durumla ilgili ayrıntılı bilgileri ekler. Yapılandırma dosyası, denetleyicinin müşteriye yanıt oluşturmak için e-formulaire.php komut dosyasını çalıştıracağını göstermektedir.

<?php

  $dConfig['etats']['e-formulaire']=array(
       'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
    'vue'=>'e-formulaire.php');

e-formulaire.php komut dosyası, [v-formulaire] görünümünü [init] ve c.a.d varyantlarında oluşturacaktır. Boş form.

4.12.3. post:calculerimpot eylemi

Bu eylem, forma girilen verilerden vergiyi hesaplamayı sağlar. Yapılandırma dosyası, bu eylemi a-calculimpot.php komut dosyasının işleyeceğini belirtir:

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

a-calculimpot.php komut dosyasının kodu şöyledir:

<?php
     // vergi hesaplama talebi

  // öncelikle parametrelerin geçerliliği kontrol edilir
  $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é";
  }

  // hata varsa işlem sona erer
  if(count($erreurs)!=0){
      // hata sayfasının hazırlanması
    $dReponse['erreurs']=&$erreurs;
    $dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'saisie');
      return;
  }//if

  // girilen veriler doğruysa
  // vergi hesaplaması için gerekli veriler alınır
  if(! $dSession['limites']){
      // veriler oturumda yok
    // veriler veri kaynağından alınır
    list($erreurs,$limites,$coeffr,$coeffn)=getData($dConfig['DSN']);
    // hata varsa, hata sayfası görüntüleniyor
    if(count($erreurs)!=0){
        // hata sayfasının hazırlanması
      $dReponse['erreurs']=&$erreurs;
        $dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'database');
      return;
    }//if
    // hata yoksa - veriler oturuma aktarılır
    $dSession['limites']=&$limites;
    $dSession['coeffr']=&$coeffr;
    $dSession['coeffn']=&$coeffn;
  }//if

  // burada vergi hesaplaması için gerekli veriler mevcut
  // vergiyi hesaplıyoruz
  $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);

    // yanıt sayfasının hazırlanması
  $dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'calculimpot');
  $dReponse['impot']=$dPerso['impot'];
  return;

  //-----------------------------------------------------------------------
  function getData($dDSN){
      // $dDSN sözlüğüyle tanımlanan veri kaynağına bağlanma
        $oImpots=new impots_data($dDSN);
    if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
    // sınır verilerinin, coeffr ve coeffn değerlerinin alınması
        list($limites,$coeffr,$coeffn)=$oImpots->getData();
         // bağlantı kesiliyor
        $oImpots->disconnect();
    // sonuç gönderiliyor
    if(count($oImpots->aErreurs)!=0) return array($oImpots->aErreurs);
        else return array(array(),$limites,$coeffr,$coeffn);
  }//getData

Komut dosyası yapması gerekeni yapıyor: vergiyi hesaplıyor. İşlem kodunu çözmeyi okuyucuya bırakıyoruz. Bizim ilgilendiğimiz konu, bu işlemin sonucunda ortaya çıkabilecek durumlardır:

  • Girilen veriler hatalıysa veya verilere erişimde sorun yaşanıyorsa: uygulama [e-erreurs] durumuna geçirilir. Yapılandırma dosyası, yanıt görünümünü oluşturma görevinin e-erreurs.php komut dosyasına ait olduğunu gösterir:
<?php

  $dConfig['etats']['e-erreurs']=array(
      'actionsautorisees'=>array('get:retourformulaire','get:init'),
      'vue'=>'e-erreurs.php');
  • diğer tüm durumlarda, uygulama [e-formulaire] durumuna geçirilir ve $dSession['etat']['secondaire']'te belirtilen calculimpot varyantı kullanılır. Yapılandırma dosyası, yanıt görünümünü oluşturacak komut dosyasının e-formulaire.php olduğunu göstermektedir. Bu komut dosyası, $dSession['etat']['secondaire'] değerini kullanarak, kullanıcı tarafından girilen değerler ve ayrıca vergi tutarı ile önceden doldurulmuş bir form oluşturacaktır.

4.12.4. post:effacerformulaire eylemi

Bu eylem, yapılandırma yoluyla daha önce açıklanan a-init.php komut dosyasıyla ilişkilendirilmiştir.

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

4.12.5. get:retourformulaire eylemi

Bu eylem, [e-erreurs] durumundan [e-formulaire] durumuna geri dönmeyi sağlar. Bu eylemi işleyen komut dosyası a-retourformulaire.php'tir:

  $dConfig['actions']['get:retourformulaire']=array('url'=>'a-retourformulaire.php');

a-retourformulaire.php komut dosyası şu şekildedir:

<?php
     // giriş formu görüntüleniyor
  $dSession['etat']=array('principal'=>'e-formulaire','secondaire'=>'retourformulaire');
?>    

Uygulamanın, [e-formulaire] durumuna, [retourformulaire] varyantında yerleştirilmesi istenmektedir. Yapılandırma dosyası, denetleyicinin müşteriye yanıt oluşturmak için e-formulaire.php komut dosyasını çalıştıracağını göstermektedir.

<?php

  $dConfig['etats']['e-formulaire']=array(
       'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
    'vue'=>'e-formulaire.php');

e-formulaire.php komut dosyası, [v-formulaire] görünümünü [retourformulaire] ve c.a.d varyantlarında oluşturacaktır. Kullanıcı tarafından girilen değerlerle önceden doldurulmuş form, ancak vergi tutarı hariç.

4.13. Geçersiz eylem dizisi

Uygulamanın belirli bir durumundan itibaren geçerli olan eylemler, yapılandırma ile belirlenir:

<?php

  // uygulama durumlarının yapılandırılması
  $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'));

Bu yapılandırmayı daha önce açıklamıştık. Geçersiz bir eylem dizisi tespit edildiğinde, a-enchainementinvalide.php komut dosyası çalıştırılır:

  $dConfig['actions']['enchainementinvalide']=array('url'=>'a-enchainementinvalide.php');

Bu komut dosyasının kodu şöyledir:

<?php 
     // geçersiz eylem dizisi
  $dReponse['erreurs']=array("Enchaînement d'actions invalide");
  $dSession['etat']=array('principal'=>'e-erreurs','secondaire'=>'enchainementinvalide');  
?>

Bu işlem, uygulamayı [e-erreurs] durumuna getirmeyi içerir. $dSession['etat']['secondaire'] durumlarında, hata sayfası oluşturucu tarafından kullanılacak bir bilgi veriyoruz. Daha önce gördüğümüz gibi, bu oluşturucu e-erreurs.php'tir:

<?php

  $dConfig['etats']['e-erreurs']=array(
      'actionsautorisees'=>array('get:retourformulaire','get:init'),
      'vue'=>'e-erreurs.php');

Bu oluşturucunun koduna daha sonra bakacağız. İstemciye gönderilen görünüm şöyledir:

Image

4.14. Uygulamanın görünümleri

4.14.1. Son görünümün görüntülenmesi

Müşteri tarafından talep edilen eylem yürütüldükten sonra denetleyicinin müşteriye yanıtı nasıl gönderdiğine bir göz atalım:

<?php

....
  // oturum başlatılıyor veya devam ettiriliyor
  session_start();
  $dSession=$_SESSION["session"];
  if($dSession) $dSession=unserialize($dSession);

  // yapılması gereken eylem alınır
  $sAction=$_GET['action'] ? strtolower($_GET['action']) : 'init';
  $sAction=strtolower($_SERVER['REQUEST_METHOD']).":$sAction";

     // eylem dizisi normal mi?
  if( ! enchainementOK($dConfig,$dSession,$sAction)){  
    // sıralama anormal
    $sAction='enchainementinvalide';
  }//if

     // eylemin işlenmesi
  $scriptAction=$dConfig['actions'][$sAction] ? 
    $dConfig['actions'][$sAction]['url'] : 
    $dConfig['actions']['actionInvalide']['url'];
  include $scriptAction;

  // yanıtın (görünüm) müşteriye gönderilmesi
  $sEtat=$dSession['etat']['principal'];
  $scriptVue=$dConfig['etats'][$sEtat]['vue'];
  include $scriptVue;

.....

  // ---------------------------------------------------------------
  function finSession(&$dConfig,&$dReponse,&$dSession){
    // $dConfig: yapılandırma sözlüğü
      // $dSession: oturum bilgilerini içeren sözlük
         // $dReponse: yanıt sayfasının argüman sözlüğü

    // oturum kaydı
...

         // yanıtın istemciye gönderilmesi
        include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];

    // komut dosyasının sonu
    exit(0);
  }//oturum sonu      

Bir eylem betiği geri döndüğünde, denetleyici $dSession['etat']['principal'] dosyasından uygulamanın geçmesi gereken durumu alır. Bu durum, az önce yürütülen eylem tarafından belirlenmiştir. Denetleyici daha sonra bu duruma ilişkin görünüm oluşturucuyu çalıştırır. Görünüm oluşturucunun adını yapılandırma dosyasında bulur. Görünüm oluşturucunun rolü şöyledir:

  • $dReponse['vuereponse'] içinde kullanılacak yanıt şablonunun adını belirler. Bu bilgi denetleyiciye aktarılacaktır. Bir şablon, bir araya geldiklerinde nihai görünümü oluşturan temel görünümlerin bir bileşimidir.
  • nihai görünümde görüntülenecek dinamik bilgileri hazırlar. Bu aşama denetleyiciden bağımsızdır. Bu, görünüm oluşturucu ile nihai görünüm arasındaki arayüzdür. Her uygulamaya özeldir.
  • mutlaka denetleyicinin finSession işlevinin çağrılmasıyla sona erer. Bu işlev
    • oturumu kaydeder
    • yanıtı gönderir

finSession işlevinin kodu şöyledir:

<?php

  // ---------------------------------------------------------------
  function finSession(&$dConfig,&$dReponse,&$dSession){
    // $dConfig: yapılandırma sözlüğü
      // $dSession : oturum bilgilerini içeren sözlük
         // $dReponse: yanıt sayfasının argüman sözlüğü

    // oturum kaydı
...

         // yanıtın istemciye gönderilmesi
        include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];

    // komut dosyasının sonu
    exit(0);
  }//oturum sonu      

Kullanıcıya gönderilen görünüm, nihai yanıt için kullanılacak şablonu tanımlayan $dReponse['vuereponse'] varlığı tarafından belirlenir.

4.14.2. Yanıt şablonu

Uygulama, aşağıdaki tek şablona göre çeşitli yanıtlarını oluşturacaktır:

Bu şablon, $dConfig['vuesreponse'] sözlüğündeki modéle1 anahtarıyla ilişkilidir:

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

m-reponse.php komut dosyası bu şablonu oluşturmakla görevlidir:

<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>

Bu komut dosyasında, $dReponse sözlüğüne yerleştirilmiş ve aşağıdaki anahtarlarla ilişkilendirilmiş üç dinamik öğe bulunmaktadır:

  • urlstyle: şablonun stil sayfasının URL'si
  • vue1: vue1 görünümünü oluşturmakla görevli komut dosyasının adı
  • vue2: vue2 görünümünü oluşturmakla görevli komut dosyasının adı

modèle1 modelini kullanmak isteyen bir görünüm oluşturucu, bu üç dinamik öğeyi tanımlamalıdır. Şimdi, modelin [vue1] ve [vue2] öğelerinin yerini alabilecek temel görünümleri tanımlıyoruz.

4.14.3. v-bandeau.php temel görünümü

v-bandeau.php komut dosyası, [vue1] alanına yerleştirilecek bir görünüm oluşturur:

<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>    

Görünüm oluşturucu, $dReponse sözlüğüne yerleştirilen ve aşağıdaki anahtarlarla ilişkilendirilen iki dinamik öğeyi tanımlamalıdır:

  • başlık: görüntülenecek başlık
  • sonuç: ödenecek vergi tutarı

4.14.4. Temel görünüm v-formulaire.php

[vue2] bölümü, ya [v-formulaire] görünümüne ya da [v-erreurs] görünümüne karşılık gelir. [v-formulaire] görünümü, v-formulaire.php komut dosyası tarafından oluşturulur:

<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>                                            

Bu görünümün dinamik kısımları, görünüm oluşturucu tarafından tanımlanması gereken kısımlar olup, $dReponse sözlüğündeki aşağıdaki anahtarlarla ilişkilendirilmiştir:

  • optoui: optoui adlı radyo düğmesinin durumu
  • optnon: optnon adlı radyo düğmesinin durumu
  • çocuklar : txtenfants alanına girilecek çocuk sayısı
  • maaş : txtsalaire alanına yerleştirilecek yıllık maaş

4.14.5. v-erreurs.php temel görünümü

[v-erreurs] görünümü, v-erreurs.php komut dosyası tarafından oluşturulur:

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>

Görünüm oluşturucu tarafından tanımlanacak bu görünümün dinamik kısımları, $dReponse sözlüğündeki aşağıdaki anahtarlarla ilişkilendirilmiştir:

  • hatalar: hata mesajları tablosu
  • bilgi: bilgi mesajı
  • bağlantı: bağlantı metni
  • href: yukarıdaki bağlantının hedef URL'si

4.14.6. Stil sayfası

Tüm görünümler bir stil sayfası ile "giydirilir". Uygulamanın görsel görünümünü değiştirmek için stil sayfası değiştirilir. Aşağıdaki style1.css stil sayfası:

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. Görünüm oluşturucular

4.15.1. Bir görünüm oluşturucunun rolü

Bir görünüm oluşturucuyu çalıştıran denetleyicinin kod dizisini hatırlayalım:

<?php

     // eylemin işlenmesi
  $scriptAction=$dConfig['actions'][$sAction] ? 
    $dConfig['actions'][$sAction]['url'] : 
    $dConfig['actions']['actionInvalide']['url'];
  include $scriptAction;

  // yanıtın (görünüm) müşteriye gönderilmesi
  $sEtat=$dSession['etat']['principal'];
  $scriptVue=$dConfig['etats'][$sEtat]['vue'];
  include $scriptVue;

Bir görünüm oluşturucu, uygulamanın yerleştirileceği durumla ilişkilidir. Durum ile görünüm oluşturucu arasındaki bağlantı, yapılandırma yoluyla belirlenir:

<?php

  // uygulama durumlarının yapılandırılması
  $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'));

Bir görünüm oluşturucunun rolünü daha önce belirtmiştik. Burada tekrar hatırlatalım. Bir görünüm oluşturucu:

  • $dReponse['vuereponse'] dosyasında kullanılacak yanıt şablonunun adını belirler. Bu bilgi denetleyiciye aktarılır. Bir şablon, bir araya geldiklerinde nihai görünümü oluşturan temel görünümlerin bir bileşimidir.
  • son görünümde görüntülenecek dinamik bilgileri hazırlar. Bu aşama denetleyiciden bağımsızdır. Bu, görünüm oluşturucu ile son görünüm arasındaki arayüzdür. Her uygulamaya özeldir.
  • mutlaka denetleyicinin finSession işlevinin çağrılmasıyla sona erer. Bu işlev
    • oturumu kaydeder
    • yanıtı gönderir

4.15.2. [e-formulaire] durumuna ilişkin görünüm oluşturucu

[e-formulaire] durumuna ilişkin görünümü oluşturmakla görevli komut dosyası e-formulaire.php adını taşır:

<?php

  $dConfig['etats']['e-formulaire']=array(
       'actionsautorisees'=>array('post:calculerimpot','get:init','post:effacerformulaire'),
    'vue'=>'e-formulaire.php');

Kodu şöyledir:

<?php
  // form yanıtı hazırlanıyor
  $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'];

  // oluşturulacak form türüne göre yapılandırma
    $type=$dSession['etat']['secondaire'];
  if($type=='init'){
      // boş form
    $dReponse['optnon']='checked';
  }//if
  if($type=='calculimpot'){
      // istekte depolanan giriş parametrelerini yeniden görüntülememiz gerekiyor
    $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'){
      // oturumda saklanan giriş parametrelerini yeniden görüntülememiz gerekiyor
    $dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
    $dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';  
    $dReponse['enfants']=$dSession['requete']['txtenfants'];
    $dReponse['salaire']=$dSession['requete']['txtsalaire'];
  }//if
  // yanıt gönderilir
  finSession($dConfig,$dReponse,$dSession);
?>      

Görünüm oluşturucunun, bir görünüm oluşturucuya getirilen koşulları karşıladığına dikkat edilmelidir:

  • $dReponse['vuereponse'] dosyasında kullanılacak yanıt şablonunu belirlemek
  • bu şablona bilgileri aktarmak. Burada bilgiler, $dReponse sözlüğü aracılığıyla aktarılmaktadır.
  • denetleyicinin finSession işlevinin çağrılmasıyla sonlandırmak

Burada kullanılan şablon 'modèle1'dir. Bu nedenle oluşturucu, bu şablonun ihtiyaç duyduğu iki bilgiyi, yani $dReponse['vue1'] ve $dReponse['vue2']'i tanımlar.

Uygulamamızın bu özel durumunda, [e-formulaire] durumuyla ilişkili görünüm, $dSession['etat']['secondaire'] değişkeninde depolanan bir bilgiye bağlıdır. Bu, bir geliştirme tercihidir. Başka bir uygulama, ek bilgileri farklı bir şekilde aktarmayı tercih edebilir. Ayrıca, burada son görünümün görüntülenmesi için gerekli tüm bilgiler $dReponse sözlüğüne yerleştirilmiştir. Bu da yine geliştiricinin tercihine bağlı bir seçenektir. [e-formulaire] durumu, dört farklı eylemden sonra ortaya çıkabilir: init, calculerimpot, retourformulaire, effacerformulaire. Görüntülenecek görünüm her durumda tam olarak aynı değildir. Bu nedenle, $dSession['etat']['secondaire']'te üç durum ayırt edilmiştir:

  • init: form boş olarak görüntülenir
  • vergi hesapla: form, vergi tutarı ve hesaplamaya yol açan verilerle birlikte görüntülenir
  • retourformulaire: form, başlangıçta girilen verilerle birlikte görüntülenir

Yukarıda, e-formulaire.php komut dosyası bu bilgileri kullanarak yanıtı bu üç farklı şekilde sunar.

4.15.3. [e-erreurs] raporuyla ilişkili görünüm

[e-erreurs] raporuna ilişkin görünümü oluşturmakla görevli komut dosyası e-erreurs.php adını taşır ve şu şekildedir:

<?php

  // hata yanıtını hazırlıyoruz
  $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';

  // ek bilgiler
  $type=$dSession['etat']['secondaire'];
  if($type=='database'){
      $dReponse['info']="Veuillez avertir l'administrateur de l'application";
  }

  // yanıt gönderilir
  finSession($dConfig,$dReponse,$dSession);
?>

4.15.4. Son görünümün görüntülenmesi

İki son görünümü oluşturan her iki komut dosyası da denetleyicinin finSession işlevini çağırarak sona erer:

<?php

  function finSession(&$dConfig,&$dReponse,&$dSession){
    // $dConfig: yapılandırma sözlüğü
      // $dSession: oturum bilgilerini içeren sözlük
         // $dReponse: yanıt sayfasının argüman sözlüğü

....

         // yanıtın gösterilmesi
        include $dConfig['vuesReponse'][$dReponse['vuereponse']]['url'];

    // komut dosyasının sonu
    exit(0);
  }//oturum sonu      

Kullanıcıya gönderilen görünüm, nihai yanıt için kullanılacak şablonu tanımlayan $dReponse['vuereponse'] varlığı tarafından belirlenir. [e-formulaire] ve [e-erreurs] raporları için bu şablon, modele1 ile eşleştirilmiştir:

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

Bu şablon, yapılandırma açısından m-reponse.php komut dosyasına karşılık gelir:

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

4.16. Yanıt şablonunu değiştirme

Burada, müşteriye verilen yanıtın görsel görünümünü değiştirmeye karar verildiğini varsayıyoruz ve bunun kod düzeyinde ne gibi etkileri olacağını anlamaya çalışıyoruz.

4.16.1. Yeni şablon

Yanıtın yapısı artık şu şekilde olacaktır:

Bu şablonun adı modele2 olacak ve bu şablonu oluşturmakla görevli komut dosyasının adı m-reponse2.php olacaktır:

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

Bu şablona karşılık gelen komut dosyası şöyledir:

<html>
    <head>
      <title>Application impots</title>
      <link type="text/css" href="<?php echo $dReponse['urlstyle'] ?>" rel="stylesheet" />
  </head>
  <body>
      <table class='modele2'>
        <!-- banner başlangıcı -->
        <tr>
          <td colspan="2"><?php    include $dReponse['vue1']; ?></td>
      </tr>
        <!-- banner sonu -->            
      <tr>
            <!-- menü başlangıcı -->      
          <td><?php include $dReponse['vue2']; ?></td>
            <!-- menü sonu -->
            <!-- bölge 3 başlangıcı -->                        
          <td><?php include $dReponse['vue3']; ?></td>
            <!-- bölge 3 sonu -->        
      </tr>
   </table>
    </body>
</html>

Şablonun dinamik öğeleri şunlardır:

  • $dReponse['urlstyle']: kullanılacak stil sayfası
  • $dReponse['vue1']: [vue1] dosyasını oluşturmak için kullanılacak komut dosyası
  • $dReponse['vue2']: [vue2] dosyasını oluşturmak için kullanılacak komut dosyası
  • $dReponse['vue3']: [vue3] dosyasını oluşturmak için kullanılacak komut dosyası

Bu öğeler, görünüm oluşturucular tarafından belirlenmelidir.

4.16.2. Farklı yanıt sayfaları

Uygulama artık kullanıcıya aşağıdaki yanıtları sunacaktır. İlk çağrıda yanıt sayfası şu şekilde olacaktır:

Kullanıcı geçerli veriler girerse, vergi hesaplanır:

Giriş hatası yaparsa, hata sayfası görüntülenir:

[Retour au formulaire de saisie] bağlantısını kullanırsa, onayladığı haliyle formu tekrar görebilir:

Yukarıdaki örnekte [Réinitialiser le formulaire] bağlantısını kullanırsa, boş bir formla karşılaşır:

Uygulamanın önceki ile aynı eylemleri kullandığına dikkat edilmelidir. Yalnızca yanıtların görünümü değişmiştir.

4.16.3. Temel görünümler

[vue1] temel görünümü, önceki örnekte olduğu gibi v-bandeau.php komut dosyasıyla ilişkilendirilecektir:

<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>  

Bu görünümde iki dinamik öğe bulunmaktadır:

  • $dReponse['titre']: görüntülenecek başlık
  • $dReponse['resultat']: ödenecek vergi tutarı

[vue2] temel görünümü ise aşağıdaki v-menu.php komut dosyasıyla ilişkilendirilecektir:

<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>

Bu görünümde aşağıdaki dinamik öğeler bulunmaktadır:

  • $dReponse['liens']: [vue2]'te görüntülenecek bağlantı tablosu. Tablodaki her öğe, iki anahtarlı bir sözlükten oluşur:
    • 'url': bağlantının hedef URL'si
    • 'metin': bağlantının metni

Giriş formunu görüntülemek istiyorsak temel görünüm [vue3], v-formulaire2.php komut dosyasıyla; hata sayfasını görüntülemek istiyorsak ise v-erreurs2.php komut dosyasıyla ilişkilendirilecektir. v-formulaire2.php komut dosyasının kodu şöyledir:

<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>

Bu görünümün dinamik kısımları, görünüm oluşturucu tarafından tanımlanması gereken kısımlar olup, $dReponse sözlüğündeki aşağıdaki anahtarlarla ilişkilendirilmiştir:

  • optoui: optoui adlı radyo düğmesinin durumu
  • optnon: optnon adlı radyo düğmesinin durumu
  • çocuklar : txtenfants alanına yerleştirilecek çocuk sayısı
  • salaire: txtsalaire alanına yerleştirilecek yıllık maaş

Hata sayfasını oluşturan komut dosyasının adı v-erreurs2.php'tir. Kod şöyledir:

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>

Görünüm oluşturucu tarafından tanımlanacak bu görünümün dinamik kısımları, $dReponse sözlüğündeki aşağıdaki anahtarlarla ilişkilendirilmiştir:

  • hatalar: hata mesajları tablosu
  • bilgi: bilgi mesajı

4.16.4. Stil sayfası

Değişmemiştir. Hâlâ style1.css'tir.

4.16.5. Yeni yapılandırma dosyası

Bu yeni görünümleri eklemek için yapılandırma dosyasındaki bazı satırları değiştirmemiz gerekiyor.

<?php

     // php yapılandırması
  ini_set("register_globals","off");
  ini_set("display_errors","off");  
  ini_set("expose_php","off");

  // eklenecek modüllerin listesi
  $dConfig['includes']=array('c-impots-data.php','c-impots-calcul.php');

  // uygulama denetleyicisi
  $dConfig['webapp']=array('titre'=>"Calculez votre impôt");

  // uygulama görünümlerinin yapılandırması
  $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';  

  // uygulama eylemlerinin yapılandırılması
  $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');          

  // uygulama durumlarının yapılandırılması
  $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'));

  // uygulama şablon yapılandırması
    $dConfig["DSN"]=array(
        "sgbd"=>"mysql",
        "user"=>"seldbimpots",
        "mdp"=>"mdpseldbimpots",
        "host"=>"localhost",
        "database"=>"dbimpots"
    );
?>

Temel değişiklik, [e-formulaire] ve [e-erreurs] raporlarıyla ilişkili görünüm oluşturucularının değiştirilmesinden ibarettir. Bu işlem tamamlandıktan sonra, yeni görünüm oluşturucular yeni yanıt sayfalarını oluşturmakla görevlendirilir.

4.16.6. [e-formulaire] raporuyla ilişkili görünüm oluşturucu

Yapılandırma dosyasında, [e-formulaire] raporu artık e-formulaire2.php görünüm oluşturucusuyla ilişkilendirilmiştir. Bu komut dosyasının kodu şöyledir:

<?php
  // form yanıtı hazırlanıyor
  $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')
  );              

  // oluşturulacak form türüne göre yapılandırma
    $type=$dSession['etat']['secondaire'];
  if($type=='init'){
      // boş form
    $dReponse['optnon']='checked';
  }//if
  if($type=='calculimpot'){
      // istekte depolanan giriş parametrelerini yeniden görüntülememiz gerekiyor
    $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'){
      // oturumda saklanan giriş parametrelerini yeniden görüntülememiz gerekiyor
    $dReponse['optoui']=$dSession['requete']['optmarie']=='oui' ? 'checked' : '';
    $dReponse['optnon']=$dReponse['optoui']=='' ? 'checked' : '';  
    $dReponse['enfants']=$dSession['requete']['txtenfants'];
    $dReponse['salaire']=$dSession['requete']['txtsalaire'];
  }//if
  // yanıt gönderilir
  finSession($dConfig,$dReponse,$dSession);
?>  

Başlıca değişiklikler şunlardır:

  • Görünüm oluşturucu, modele2 yanıt şablonunu kullanmak istediğini belirtir
  • bu nedenle $dReponse['vue1'], $dReponse['vue2'], $dReponse['vue3'] dinamik öğelerini doldurur; bu üç öğe de modele2 yanıt şablonu için gereklidir.
  • Oluşturucu ayrıca, yanıtın [vue2] alanında görüntülenecek bağlantıları belirleyen $dReponse['liens'] dinamik öğesini de doldurur.

4.16.7. [e-erreurs] durumuna bağlı görünüm oluşturucu

Yapılandırma dosyasında, [e-erreurs] raporu artık e-erreurs2.php görünüm oluşturucusuyla ilişkilendirilmiştir. Bu komut dosyasının kodu şöyledir:

<?php

  // hata yanıtını hazırlıyoruz
  $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')
  );              

  // ek bilgiler
  $type=$dSession['etat']['secondaire'];
  if($type=='database'){
      $dReponse['info']="Veuillez avertir l'administrateur de l'application";
  }

  // yanıt gönderilir
  finSession($dConfig,$dReponse,$dSession);
?>  

Yapılan değişiklikler, e-formulaire2.php görünüm oluşturucusunda yapılanlarla aynıdır.

4.17. Sonuç

Bir örnek üzerinden, genel amaçlı denetleyicimizin faydalarını gösterebildik. Bu denetleyiciyi yazmamıza gerek kalmadı. Yalnızca uygulamanın eylem komut dosyalarını, görünüm oluşturucularını ve görünümlerini yazmakla yetindik. Ayrıca, eylemleri görünümlerden ayırmanın faydalarını da gösterdik. Böylelikle, eylem komut dosyalarındaki tek bir satır kodu bile değiştirmeden yanıtların görünümünü değiştirebildik. Yalnızca görünümlerin oluşturulmasında rol oynayan komut dosyaları değiştirildi. Bunun mümkün olabilmesi için, eylem komut dosyası, hesapladığı bilgileri görüntüleyecek görünüm hakkında hiçbir varsayımda bulunmamalıdır. Bu bilgileri denetleyiciye iletmekle yetinmeli; denetleyici de bunları biçimlendirecek olan görünüm oluşturucuya aktarır. Bu mutlak bir kuraldır: bir eylem, görünümlerden tamamen bağımsız olmalıdır.

Bu bölümde, Java geliştiricileri tarafından iyi bilinen Struts felsefesine değindik. php.mvc adlı bir 'açık kaynak' projesi, Struts felsefesiyle web/php geliştirme yapılmasına olanak tanır. Daha fazla bilgi için http://www.phpmvc.net/ sitesini ziyaret edebilirsiniz.