Skip to content

3. Genel bir denetleyici

3.1. Giriş

Önceki yöntemde, main.php adlı denetleyiciyi yazmamız gerektiği anlaşılmıştı. Biraz deneyim kazandıkça, bu denetleyicinin genellikle aynı işleri yaptığı fark edilir ve bu durumda çoğu web uygulamasında kullanılabilecek genel bir denetleyici yazmak cazip hale gelir. Bu denetleyicinin kodu şu şekilde olabilir:

<?php
     // genel denetleyici

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

  // kütüphanelerin dahil edilmesi
  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 parametrelerini oturuma kaydediyoruz
      $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 görüntülenir
        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

?>

3.2. Uygulamanın yapılandırma dosyası

Uygulama, mutlaka config.php adını taşıyan bir komut dosyasında yapılandırılır. Uygulama parametreleri, hem denetleyici hem de eylem komut dosyaları, modeller ve temel görünümler tarafından kullanılan $dConfig adlı bir sözlükte yer alır.

3.3. Denetleyiciye eklenecek kütüphaneler

Denetleyici koduna eklenecek kütüphaneler, $dConfig['includes'] tablosunda yer alır. Denetleyici, bunları aşağıdaki kod dizisiyle ekler:

<?php
...
  // yapılandırmayı okuma
  include "config.php";

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

3.4. Oturum yönetimi

Genel denetleyici, oturumu otomatik olarak yönetir. Oturumun içeriğini $dSession sözlüğü aracılığıyla kaydeder ve geri yükler. Bu sözlük, daha sonra doğru şekilde geri yüklenebilmesi için serileştirilmesi gereken nesneler içerebilir. Bu sözlüğe atanan anahtar 'session'dır. Dolayısıyla, bir oturumu geri yüklemek için aşağıdaki kod kullanılır:

<?php

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

Bir eylem, oturumda bilgileri kaydetmek isterse, $dSession sözlüğüne anahtarlar ve değerler ekler. Tüm eylemler aynı oturumu paylaştığından, uygulama birden fazla kişi tarafından bağımsız olarak geliştirilirse oturum anahtarları arasında çakışma riski ortaya çıkar. Bu bir zorluktur. Oturum anahtarlarını listeleyen ve herkes tarafından paylaşılan bir referans havuzu geliştirilmelidir. Her eylemin, aşağıdaki finSession işlevini çağırarak sona erdiğini göreceğiz:

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

Bir eylem, bir oturumu sürdürmeme kararı alabilir. Bunun için, finSession işlevinin $dSession parametresine herhangi bir değer aktarmaması yeterlidir; bu durumda oturum silinir (session_destroy). $dSession sözlüğü varsa, oturumda kaydedilir ve ardından oturum kaydedilir (session_write_close). Dolayısıyla, mevcut işlem, $dSession sözlüğüne öğeler ekleyerek oturumda öğeleri saklayabilir. Denetleyicinin, geçerli isteğin parametrelerini otomatik olarak oturumda sakladığı unutulmamalıdır. Bu, bir sonraki isteği işlemek için gerektiğinde bu parametrelerin geri alınmasını sağlar.

3.5. Cevabın müşteriye gönderilmesi

finSession işlevinin nihai amacı, kullanıcıya bir yanıt göndermektir. Bir yanıtın farklı sayfa şablonlarına sahip olabileceğini belirtmiştik. Bu şablonlar, yapılandırma yoluyla $dConfig['vuesReponse']'e yerleştirilir. İki şablonlu bir uygulamada, örneğin şunlar olabilir:

<?php

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

Yürütülmekte olan eylem, $dReponse['vuereponse'] içinde istenen modeli belirtir. Bu model, denetleyici tarafından şu komutla görüntülenir:

<?php

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

Bu yanıt müşteriye gönderildikten sonra denetleyici durur (exit).

3.6. Eylemlerin Yürütülmesi

Denetleyici, action=XX parametresine sahip istekleri bekler. Eğer istekte bu parametre yoksa ve istek GET şeklindeyse, eylem 'init' değerini alır. Bu durum, denetleyiciye yapılan ve http://machine:port/chemin/main.php biçimindeki ilk istek için geçerlidir.

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

Yapılandırmaya göre, her eyleme bu eylemi işlemekle görevli bir komut dosyası atanır. Örneğin:

<?php
... 
// uygulamanın 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');          

Önceden tanımlanmış iki eylem vardır:

enchainementInvalide
mevcut eylemin bir önceki eylemi takip edemediği durumlar
actionInvalide
istenen eylem, eylem sözlüğünde mevcut değilse

Uygulamaya özgü eylemler, yöntem:eylem biçiminde belirtilir; burada yöntem, isteğin get veya post yöntemidir ve eylem ise istenen eylemdir; örneğin: init, calculerimpot, retourformulaire, effacerformulaire. Parametrelerin gönderilmesinde kullanılan yöntem (GET veya POST) ne olursa olsun, eylemin şu diziyle alındığına dikkat edilmelidir:

<?php

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

Aslında, bir form gönderilmiş olsa bile, yine de şunu yazabiliriz:

<form method='post' action='main.php?action=calculerimpot'>
..
</form>

Form öğeleri gönderilecektir (method='post'). Ancak istenen URL, main.php?action=calculerimpot olacaktır. Bu URL adresindeki parametreler $_GET sözlüğünden alınırken, formun diğer öğeleri ise $_POST sözlüğünden alınacaktır.

Eylem sözlüğüyle donatılmış denetleyici, istenen eylemi şu şekilde yürütür:

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

İstenen eylem eylem sözlüğünde bulunmuyorsa, geçersiz bir eyleme karşılık gelen komut dosyası çalıştırılır. Eylem komut dosyası denetleyiciye yüklendikten sonra çalıştırılır. Kontrolörün değişkenlerine ($dConfig, $dSession) ve PHP'in süper-global sözlüklerine ($_GET, $_POST, $_SERVER, $_ENV, $_SESSION) söz konusu sözlüklerine erişimi olduğu unutulmamalıdır. Komut dosyasında uygulama mantığı ve iş sınıflarına yapılan çağrılar bulunur. Her durumda, eylem

  • $dSession sözlüğünü doldurmalıdır; eğer öğelerin mevcut oturumda kaydedilmesi gerekiyorsa
  • $dReponse['vuereponse'] içinde görüntülenecek yanıt şablonunun adı belirtilmelidir
  • finSession($dConfig, $dReponse, $dSession) çağrısıyla sonlanmalıdır. Oturumun sonlandırılması gerekiyorsa, eylem sadece finSession($dConfig, $dReponse) çağrısıyla sona erecektir.

Tutarlılık amacıyla, eylem, görünümler için gerekli tüm bilgileri $dReponse sözlüğüne ekleyebilir. Ancak bu zorunlu değildir. Yalnızca $dReponse['vuereponse'] değeri zorunludur. Her eylem komut dosyasının, finSession işlevinin çağrılmasıyla sona erdiği ve bu işlevin de bir exit işlemiyle bittiği dikkat edilmelidir. Dolayısıyla, bir eylem komut dosyasından geri dönüş yapılmaz.

3.7. Eylemlerin sıralanması

Bir web uygulamasını sonlu durumlu bir otomat olarak düşünebiliriz. Uygulamanın farklı durumları, kullanıcıya sunulan görünümlerle ilişkilidir. Kullanıcı, bir bağlantı veya düğme aracılığıyla başka bir görünüme geçer. Web uygulaması durum değiştirir. Bir eylemin http://machine:port/chemin/main.php?action=XX gibi bir istekle başlatıldığını görmüştük. Bu URL, kullanıcıya sunulan görünümde yer alan bir bağlantıdan gelmelidir. Zira, bir kullanıcının URL http://machine:port/chemin/main.php?action=XX adresini doğrudan yazarak uygulamanın kendisi için öngördüğü yolu atlamasını önlemek istiyoruz. Bu durum, istemci bir program olsa bile geçerlidir.

Talep edilen URL, kullanıcıya sunulan son görünümden talep edilebilen bir URL ise, bu akış doğru kabul edilir. Bunların listesi kolayca belirlenebilir. Bu liste,

  • görünümde yer alan, ya bağlantı ya da submit türünde eylem hedefleri şeklinde bulunan URL'lerden
  • ve bir kullanıcıya görünüm sunulduğunda tarayıcısına doğrudan yazma yetkisi verilen URL'lerden oluşur.

Uygulamanın durumlarının listesi, mutlaka görünümlerin listesiyle aynı değildir. Örneğin, aşağıdaki temel erreurs.php görünümünü ele alalım:

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>
<a href="<?php echo $dReponse["href"] ?>"><?php echo $dReponse["lien"] ?></a>

Bu temel görünüm, yanıtı oluşturacak temel görünümlerin bir bileşimine entegre edilecektir. Bu görünümde, dinamik olarak konumlandırılabilen bir bağlantı bulunmaktadır. erreurs.php görünümü, duruma göre n farklı bağlantı ile görüntülenebilir. Bu, uygulama için n farklı durumun ortaya çıkmasına neden olacaktır. i numaralı durumda, erreurs.php görünümü lieni bağlantısı ile görüntülenecektir. Bu durumda, yalnızca lieni bağlantısının kullanılması kabul edilebilir.

Bir uygulamanın durum listesi ve her durumda gerçekleştirilebilecek eylemler, $dConfig['etats'] sözlüğüne kaydedilecektir:

<?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'));

Yukarıdaki uygulamanın "e-form" ve "e-hatalar" adlı iki durumu vardır. Uygulamanın başlangıçta herhangi bir durumu olmadığı zamana karşılık gelen "sansetat" adlı bir durum daha eklenir. Bir E durumunda, izin verilen eylemlerin listesi $dConfig['etats'][E]['actionsautorisees'] tablosunda bulunur. Burada, eylem için izin verilen yöntem (get/post) ve eylemin adı belirtilir. Yukarıdaki örnekte dört olası eylem bulunmaktadır: get:init, post:alculerimpot, get:retourformulaire ve post:effacerformulaire.

$dConfig['etats'] sözlüğüne sahip olan denetleyici, mevcut uygulama durumunda $sAction eyleminin izin verilip verilmediğini belirleyebilir. Bu durum, her eylem tarafından oluşturulur ve oturumda $dSession['etat'] altında saklanır. Mevcut eylemin izinli olup olmadığını kontrol etmek için kullanılan denetleyici kodu şöyledir:

<?php
.....
     // eylem dizisi normal mi?
  if( ! enchainementOK($dConfig,$dSession,$sAction)){  
    // anormal akış
    $sAction='enchainementinvalide';
  }//if

     // eylemin işlenmesi
  $scriptAction=$dConfig['actions'][$sAction] ? 
    $dConfig['actions'][$sAction]['url'] : 
    $dConfig['actions']['actionInvalide']['url'];
  include $scriptAction;
..........
  //--------------------------------------------------------------------
    function enchainementOK(&$dConfig,&$dSession,$sAction){
      // Cari eylemin bir önceki duruma göre izin verilip verilmediğini 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;    
  }

Mantık şöyledir: bir eylem, $sAction listesinde yer alıyorsa veya bu liste mevcut değilse ve bu durumda tüm eylemler izin verilir. $etat, önceki istemci isteği/sunucu yanıtı döngüsünün sonunda uygulamanın durumudur. Bu durum oturumda depolanmıştır ve buradan alınır. İstenen eylemin geçersiz olduğu tespit edilirse, $dConfig['actions']['enchainementInvalide']['url'] komut dosyası çalıştırılır. Bu komut dosyası, müşteriye uygun bir yanıt iletmekle görevlidir.

Geliştirme aşamasında, $dConfig['etats'] sözlüğü doldurulmayabilir. Bu durumda, her durum tüm eylemleri izin verir. Uygulama tamamen hata ayıklaması tamamlandıktan sonra sözlük geliştirilebilir. Bu sözlük, uygulamayı yetkisiz eylemlerden koruyacaktır.

3.8. Hata ayıklama

Denetleyici iki hata ayıklama işlevi sunar:

  • "trace" işlevi, HTML akışında bir mesajın görüntülenmesini sağlar
  • dump işlevi, aynı akışta bir sözlüğün içeriğini görüntülemeye olanak tanır

Herhangi bir eylem komut dosyası bu iki işlevi kullanabilir. Zira eylem komut dosyasının kodu denetleyicinin koduna dahil edildiğinden (include), trace ve dump işlevleri komut dosyaları tarafından görülebilir.

3.9. Sonuç

Genel denetleyici, geliştiricinin uygulamasının eylemlerine ve görünümlerine odaklanmasını sağlamayı amaçlar. Geliştirici için şunları sağlar:

  • oturum yönetimi (geri yükleme, kaydetme)
  • istenen eylemlerin geçerliliğinin doğrulanması
  • eylemle ilişkili komut dosyasının yürütülmesi
  • eylemin yürütülmesinin sonucuna uygun yanıtın istemciye gönderilmesi