Adventure,PHP,Framework,PageController,FrontController,Pattern,Objektorientierung,OO,Software,Design,Wiederverwendbarkeit,UML,Tutorial,Benchmark,ausgezeichnete Performance

Suche:    
Downloads  |  SVN!  |  Roadmap  |  Forum!  |  Bugtracking  |  Gästebuch  |  Backlinks!  |  Referenzen!  |  Sitemap  |  Impressum  
 
Deutsch Adventure PHP Framework  Bookmark @ Technorati Bookmark @ del.icio.us Bookmark @ Mr. Wong Bookmark @ Simpy Bookmark @ Google Bookmark @ Digg.com Adventure PHP Framework Seite 058_gaestebuch_tutorial_2 drucken!

Gästebuch-Tutorial (2)

Artikel bewerten:
Dieser Artikel wurde noch nicht bewertet. Bewerten Sie diesen Artikel als erstes!
Die folgenden Kapiteln beschreiben die Implementierungsdatails des Gästebuchs. Die Ausgabe desselben kann unter Gästebuch eingesehen werden.


6. Implementierung der Datenschicht

Die Hauptaufgabe des guestbookMapper's ist es, Daten zwischen Datenhaltung und Anwendung zu übersetzen. Im Fall des Lesens muss ein Resultset in ein Domänen-Objekt übersetzt werden, im Fall des Schreibens muss ein Domänen-Objekt in seine Bestandteile zerlegt und in den zugehörigen Tabellen gespeichert werden. Dazu werden - wie im Design beschrieben - jeweils eine Mapping-Methode für jedes Objekt der Anwendung erstellt. Das Schreiben übernehmen die save*()-Methoden. Hier zunächst der Quellcode des Gästebuchs:

guestbookMapper.php:
import('modules::guestbook::biz','Guestbook');
import('modules::guestbook::biz','Entry');
import('modules::guestbook::biz','Comment');
import('core::database','MySQLHandler');

class 
guestbookMapper extends coreObject
{

   function 
guestbookMapper(){
   }

   function 
loadEntryByID($EntryID){

      
// Instanz des MySQLHandlers holen
      
$SQL = &$this->__getServiceObject('core::database','MySQLHandler');

      
// Daten lesen und zurückgeben
      
$T = &Singleton::getInstance('benchmarkTimer');
      
$T->start('loadEntryByID('.$EntryID.')');
      
$select 'SELECT * FROM entry WHERE EntryID = \''.$EntryID.'\';';
      
$result $SQL->executeTextStatement($select);

      
$T->start('__mapEntry2DomainObject('.$EntryID.')');
      
$Entry $this->__mapEntry2DomainObject($SQL->fetchData($result));
      
$T->stop('__mapEntry2DomainObject('.$EntryID.')');

      
$T->stop('loadEntryByID('.$EntryID.')');

      return 
$Entry;

    
// end function
   
}

   function 
loadCommentByID($CommentID){

      
// Instanz des MySQLHandlers holen
      
$SQL = &$this->__getServiceObject('core::database','MySQLHandler');

      
// Daten lesen und zurückgeben
      
$select 'SELECT * FROM comment WHERE CommentID = \''.$CommentID.'\';';
      
$result $SQL->executeTextStatement($select);
      return 
$this->__mapComment2DomainObject($SQL->fetchData($result));

    
// end function
   
}

   function 
loadGuestbookByID($GuestbookID){

      
// Instanz des MySQLHandlers holen
      
$SQL = &$this->__getServiceObject('core::database','MySQLHandler');

      
// Daten lesen und zurückgeben
      
$select 'SELECT * FROM guestbook WHERE GuestbookID = \''.$GuestbookID.'\';';
      
$result $SQL->executeTextStatement($select);
      return 
$this->__mapGuestbook2DomainObject($SQL->fetchData($result));

    
// end function
   
}

   function 
loadEntryWithComments($EntyID){

      
// Instanz des MySQLHandlers holen
      
$SQL = &$this->__getServiceObject('core::database','MySQLHandler');


      
// Eintrag laden
      
$Entry $this->loadEntryByID($EntyID);


      
// Kommentare hinzuladen
      
$select 'SELECT comment.CommentID AS ID FROM comment
                 INNER JOIN comp_entry_comment ON comment.CommentID = comp_entry_comment.CommentID
                 INNER JOIN entry ON comp_entry_comment.EntryID = entry.EntryID
                 WHERE entry.EntryID = \''
.$Entry->get('ID').'\';';
      
$result $SQL->executeTextStatement($select);

      while(
$data $SQL->fetchData($result)){
         
$Comment $this->loadCommentByID($data['ID']);
         
$Entry->addComment($Comment);
         
$Comment null;
       
// end while
      
}


      
// Eintrag zurückgeben
      
return $Entry;

    
// end function
   
}

   function 
loadGuestbookWithEntries($GuestbookID){

      
// Instanz des MySQLHandlers holen
      
$SQL = &$this->__getServiceObject('core::database','MySQLHandler');


      
// Gästebuch laden
      
$Guestbook $this->loadGuestbookByID($GuestbookID);


      
// Kommentare hinzuladen
      
$select 'SELECT entry.EntryID AS ID FROM entry
                 INNER JOIN comp_guestbook_entry ON entry.EntryID = comp_guestbook_entry.EntryID
                 INNER JOIN guestbook ON comp_guestbook_entry.GuestbookID = guestbook.GuestbookID
                 WHERE guestbook.GuestbookID = \''
.$Guestbook->get('ID').'\';';
      
$result $SQL->executeTextStatement($select);

      while(
$data $SQL->fetchData($result)){
         
$Entry $this->loadEntryWithComments($data['ID']);
         
$Guestbook->addEntry($Entry);
         
$Entry null;
       
// end while
      
}


      
// Gästebuch zurückgeben
      
return $Guestbook;

    
// end function
   
}

   ...

 
// end class

6.1. Lese-Mapper-Methoden

Um der Business-Schicht Objekte zur Verfügung stellen zu können muss ein Ergebnis einer Datenbank-Abfrage in die Business-Objekte gemappt werden. Dazu wurden die Funktionen _mapEntry2DomainObject(), __mapGuestbook2DomainObject und __mapComment2DomainObject vorgesehen. Diese wiederum werden von den load*ByID()- und load*WithEntries()-Methoden verwendet. Jede dieser Methoden stellt der Business-Schicht einen Service zur Verfügung, mit dem Daten aus der Datenquelle geladen werden können. Zur Kommunikation mit der Datenbank kommt der MySQLHandler zur Verfügung. Dieses Service-Objekt kennt die Methoden executeTextStatement() um ein SQL- Statement auszuführen und fetchData() um Daten abzuholen. Der MySQLHandler stellt eine Abstraktionsschicht für den Datenzugriff dar.


6.2. Schreibe-Mapper-Methoden

Da das Gästebuch keine rein lesenden Anwendung ist, muss die Anwendung Daten auch wieder persistieren können. Um sicherzustellen, dass sich die Anwendung nicht um die Spezifika der Datenschicht kümmern muss werden save*()-Methoden angeboten. Mit diesen kann durch Übergabe eines Objekts oder auch eines Objekt-Baums die Objekte oder Bäume transparent für die Anwendung gespeichert werden. Beim Erstellen eines Gästebuch-Eintrags beispielsweise muss lediglich das zugehörige Gästebuch der Methode saveGuestbook() übergeben werden und die Datenschicht kümmert sich um die Speicherung des Gästebuchs, bzw. der Einträge. Innerhalb dieser Funktion wird dann überprüft, ob das übergebene Gästebuch bereits existiert. Wenn nein, wird es gespeichert, wenn ja nur upgedatet. Ebenso werden nur neue Einträge mit Hilfe der Funktion saveEntry() gespeichert. Damit die Zuordnung eines Eintrags zu deinem Gästebuch konsistent bleibt, kümmerst sich jede dieser Methoden darum, dass die Beziehungsinformationen richtig gespeichert werden.



7. Implementierung der Business-Schicht

In den Implementierungen des Frameworks werden die Business- und Datenschicht-Komponenten in der Regel als Service-Objekte verwendet. Um diese in einer Methode verwenden zu können ist in jeder Klasse, die direkt oder indirekt von coreObject erbt die Methode __getServiceObject() oder __getAndInitServiceObject(). Die beiden Funktionen liefern dabei jeweils eine Referenz auf die Instanz des spezifizierten Service-Objekts zurück. Um als Service-Objekt aufgerufen und erzeugt zu werden muss diese Klasse direkt oder indirekt von coreObject erben und falls ein Service mit __getAndInitServiceObject() erstellt wird die Methode init() implementieren. Letzter dient dazu einen Service zu initialisieren. Dazu besitzt __getAndInitServiceObject() einen dritten Parameter, der als Initialisierungs-Parameter an die Methode init() weitergegeben wird. Wird jedes Service-Layer mit den genannten Funktionen erstellt, so ist sichergestellt, dass die Layer die für die Anwendung wichtigen Attribute wie Context und Language kennen. Dies ist insbesondere für das Auslesen von Konfigurations-Dateien wichtig.

guestbookManager.php:
import('modules::guestbook::biz','Guestbook');
import('modules::guestbook::biz','Entry');
import('modules::guestbook::biz','Comment');
import('modules::guestbook::data','guestbookMapper');
import('modules::pager::biz','pagerManager');
import('core::session','sessionManager');

class 
guestbookManager extends coreObject
{

   var 
$__GuestbookID;
   var 
$__Guestbook null;
   var 
$__sessMgr null;


   function 
guestbookManager(){
   }

   function 
init($GuestbookID){

      
// GuestbookID speichern
      
$this->__GuestbookID $GuestbookID;

      
// SessionManager initialisieren
      
$this->__sessMgr = new sessionManager('Guestbook');

    
// end function
   
}

   function 
loadGuestbook(){

      
// Falls Gästebuch noch nicht geladen wurde...
      
if($this->__Guestbook == null){

         
// pagerManager holen
         
$pMF = &$this->__getServiceObject('modules::pager::biz','pagerManagerFabric');
         
$pM = &$pMF->getPagerManager('Guestbook',array('GuestbookID' => $this->__GuestbookID));


         
// GuestbookMapper holen
         
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');


         
// Gästebuch laden
         
$this->__Guestbook $gM->loadGuestbookByID($this->__GuestbookID);


         
// Eintrag-IDs, die angezeigt werden sollen laden
         
$EntryIDs $pM->loadEntries();


         
// Einträge laden
         
$Entries = array();

         for(
$i 0$i count($EntryIDs); $i++){
            
$Entries[] = $gM->loadEntryWithComments($EntryIDs[$i]);
          
// end for
         
}


         
// Einträge zum Gästebuch hinzufügen
         
$this->__Guestbook->setEntries($Entries);

       
// end if
      
}

      
// Gästebuch zurückgeben
      
return $this->__Guestbook;

    
// end function
   
}

   function 
loadGuestbookObject(){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Gästebuch-Objekt laden
      
return $gM->loadGuestbookByID($this->__GuestbookID);

    
// end function
   
}

   function 
getURLParameters(){

      
// pagerManager holen
      
$pMF = &$this->__getServiceObject('modules::pager::biz','pagerManagerFabric');
      
$pM = &$pMF->getPagerManager('Guestbook',array('GuestbookID' => $this->__GuestbookID));

      
// Pager-Ausgabe hinzufügen
      
return $pM->getPagerURLParameters();

    
// end function
   
}

   function 
getPager(){

      
// pagerManager holen
      
$pMF = &$this->__getServiceObject('modules::pager::biz','pagerManagerFabric');
      
$pM = &$pMF->getPagerManager('Guestbook',array('GuestbookID' => $this->__GuestbookID));

      
// Pager-Ausgabe hinzufügen
      
return $pM->getPager();

    
// end function
   
}

   function 
saveEntry($Entry){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Gästebuch laden
      
$Guestbook $gM->loadGuestbookByID($this->__GuestbookID);

      
// Eintrag hinzufügen
      
$Guestbook->addEntry($Entry);

      
// Gästebuch speichern
      
$gM->saveGuestbook($Guestbook);

      
// pagerManager holen
      
$pMF = &$this->__getServiceObject('modules::pager::biz','pagerManagerFabric');
      
$pM = &$pMF->getPagerManager('Guestbook',array('GuestbookID' => $this->__GuestbookID));

      
// Auf Anzeige-Seite weiterleiten
      
$URLParams $pM->getPagerURLParameters();
      
$Link linkHandler::generateLink($_SERVER['REQUEST_URI'],array($URLParams['StartName'] => ''$URLParams['CountName'] => '''gbview' => 'display'));
      
header('Location: '.$Link);

    
// end function
   
}

   function 
saveComment($EntryID,$Comment){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Gästebuch laden
      
$Guestbook $gM->loadGuestbookByID($this->__GuestbookID);

      
// Entry laden
      
$Entry $gM->loadEntryByID($EntryID);

      
// Comment zum Entry hinzufügen
      
$Entry->addComment($Comment);

      
// Eintrag hinzufügen
      
$Guestbook->addEntry($Entry);

      
// Gästebuch speichern
      
$gM->saveGuestbook($Guestbook);

      
// pagerManager holen
      
$pMF = &$this->__getServiceObject('modules::pager::biz','pagerManagerFabric');
      
$pM = &$pMF->getPagerManager('Guestbook',array('GuestbookID' => $this->__GuestbookID));

      
// Auf Anzeige-Seite weiterleiten
      
$URLParams $pM->getPagerURLParameters();
      
$Link linkHandler::generateLink($_SERVER['REQUEST_URI'],array($URLParams['StartName'] => ''$URLParams['CountName'] => '''gbview' => 'display','commentid' => '''entryid' => ''));
      
header('Location: '.$Link);

    
// end function
   
}

   function 
loadEntry($EntryID){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Eintrag ausgeben
      
return $gM->loadEntryByID($EntryID);

    
// end function
   
}

   function 
loadComment($CommentID){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Eintrag ausgeben
      
return $gM->loadCommentByID($CommentID);

    
// end function
   
}

   function 
validateCrendentials($Username,$Password){

      
// Gästebuch-Objekt laden
      
$Guestbook $this->loadGuestbookObject();

      
// Zugangsdaten validieren
      
if($Guestbook->get('Admin_Username') == $Username && $Guestbook->get('Admin_Password') == $Password){
         return 
true;
       
// end if
      
}
      else{
         return 
false;
       
// end else
      
}

    
// end function
   
}

   function 
deleteEntry($Entry){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Eintrag löschen
      
$gM->deleteEntry($Entry);

    
// end function
   
}

   function 
deleteComment($Comment){

      
// GuestbookMapper holen
      
$gM = &$this->__getServiceObject('modules::guestbook::data','guestbookMapper');

      
// Eintrag löschen
      
$gM->deleteComment($Comment);

    
// end function
   
}

 
// end class

7.1. Initialisierung

Da allein die Präsentations-Schicht über den "<core:importdesign />"-Tag die Gästebuch-ID kennt, muss die Präsentations-Schicht eine Möglichkeit haben diese dem Business-Layer mitzuteilen. Dazu wird die bereits genannte Methode __getAndInitServiceObject() verwendet um die Business-Schicht zu initialisieren. Die Business-Schicht implementiert dazu die Funktion init(), die einen Parameter zur Initialisierung erwartet. Beim Aufrufen der Business- Schicht wird dann jeweils die ID des Gästebuchs mitgegeben.


7.2. Laden von Einträgen

Um das Anzeigen von Einträgen zu erleichtern, wird die Pager-Komponente bereits in der Business- Schicht eingesetzt. So muss sich die Präsentations-Schicht keine Gedanken zur Menge der darzustellenden Einträge machen. Die Pager-Komponente wird hier in Form des pagerManager's aus dem Package modules::pager eingesetzt. Das ist eine bereits fertig implementierte Komponente, die lediglich fü den Einsatz konfiguriert werden muss. Um mehrere Instanzen des pagerManager's innerhalb der Applikation verwenden zu können, wurde eine pagerManagerFabric implementiert. Diese liefert bei Aufruf der Funktion getPagerManager die initialisierte Instanz eines pagerManager's zurück. Der Pager gibt bei Aufruf der Methode loadEntries() die IDs der anzuzeigenden Eintäge zurück. Diese können dann mit Hilfe der Daten-Schicht geladen und an das Gästebuch gehängt werden.


7.3. Ausgabe des Pagers

Die unter 7.2. eingeführte Pager-Komponente bietet die Möglichkeit eine HTML-Ausgabe auszugeben. Diese beinhaltet das Blättern in Seiten und die Wahl der Einträge pro Seite. Hierzu muss einfach die Methode getPager() aufgerufen werden. Diese gibt dei HTML-Ausgabe zurück, die in der Präsentations-Schicht in die Seite oder ein Template eingesetzt werden kann.


7.4. Speichern von Einträgen

Der Präsentations-Schicht wird mit der Methode saveEntry() ein weiterer Service bereit gestellt. Um diesen nutzen zu können muss die Präsentations-Schicht die Methode aufrufen und ein Domain-Objekt Entry übergeben. Dieses wird dann gespeichert und die Funktion leitet den Benutzer auf den display-View weiter.



8. Implementierung der Präsentations-Schicht

Die Präsentations-Schicht besteht aus zwei Views: der Anzeige der Einträge und dem Formular. Dies zwei Views werden durch jeweils eine Template- und eine Controller-Datei repräsentiert. Um die Anzeige der Views zu erleichtern, wird das Gästebuch mit einem weiteren Wrapper-Template eingebunden: guestbook.html. Diese beinhaltet die globalen Ausgaben eines Gästbuchs und verfügt ebenfalls über einen Controller.


8.1. Gästebuch Design-Rahmen

Die Datei guestbook.html beinhaltet die globalen Ausgaben eines Gästebuchs.
<@controller namespace="modules::guestbook::pres::documentcontroller" class="guestbook_v1_controller" file="guestbook_v1_controller" @>
<font style="font-size: 26px; font weight: bold;"><html:placeholder name="Name" /></font>
<br />
<br />
<html:placeholder name="Description" />
<br />
<core:importdesign namespace="modules::guestbook::pres::templates" template="[gbview=display]" incparam="gbview" />
Hier werden Platzhalter für die Ausgabe des Namens und der Beschreibung sowie die Einbindung der oben genannten Views per "<core:importdesign />"-Tag definiert. Der zugehörige Controller liest zur Generierung der Darstellung das Gästebuch-Objekt aus und stellt die genannten Attribute dar.
import('modules::guestbook::biz','guestbookManager');

class 
guestbook_v1_controller extends baseController
{

   var 
$_LOCALS;


   function 
guestbook_v1_controller(){
   }

   function 
transformContent(){

      
// guestbookid holen
      
$GuestbookID $this->__Attributes['guestbookid'];

      
// Gästebuch laden
      
$gM = &$this->__getAndInitServiceObject('modules::guestbook::biz','guestbookManager',$GuestbookID);
      
$Guestbook $gM->loadGuestbookObject();

      
// Name und Beschreibung anzeigen
      
$this->setPlaceHolder('Name',$Guestbook->get('Name'));
      
$this->setPlaceHolder('Description',$Guestbook->get('Description'));

    
// end function
   
}

 
// end class

8.2. Display-View

Der Display-View definiert Platzhalter für Pager, Link zum Formular und der Eintrags-Liste sowie Templates für die Darstellung der Domain-Objekte "Entry" und "Comment".
<@controller namespace="modules::guestbook::pres::documentcontroller" class="guestbook_display_v1_controller" file="guestbook_display_v1_controller" @>
<html:placeholder name="Pager" />
<html:placeholder name="CreateEntry" />
<br />
<html:placeholder name="ControlGuestbook" />
<br />
<br />
<br />
<html:placeholder name="Content" />

<html:template name="CreateEntry_de">
  » Klicken Sie
  <a href="<template:placeholder name="Link" />" title="Eintrag hinzufügen!">
    hier
  </a>
  um einen Eintrag hinzuzufügen!
</html:template>

<html:template name="CreateEntry_en">
  » Please click
  <a href="<template:placeholder name="Link" />" title="Add new entry!">
    here
  </a>
  to add a new entry!
</html:template>

<html:template name="ControlGuestbook_Login_de">
  » Klicken Sie
  <a href="<template:placeholder name="Link" />" title="Gästebuch administrieren!">
    hier
  </a>
  um das Gästebuch zu administrieren!
</html:template>

<html:template name="ControlGuestbook_Login_en">
  » Please click
  <a href="<template:placeholder name="Link" />" title="Manage guestbook!">
    here
  </a>
  to manage the guestbook!
</html:template>

<html:template name="ControlGuestbook_Logout_de">
  » Klicken Sie
  <a href="<template:placeholder name="Link" />" title="Administrations-Modus verlassen!">
    hier
  </a>
  um den Administrations-Modus zu verlassen!
</html:template>

<html:template name="ControlGuestbook_Logout_en">
  » Please click
  <a href="<template:placeholder name="Link" />" title="Leave administration mode!">
    here
  </a>
  to leave the administration mode!
</html:template>

<html:template name="Entry">
  <template:addtaglib namespace="tools::html::taglib" prefix="template" class="getstring" />
  <div style="width: 100%;">
    <div style="background-color: white; border-bottom: 2px solid gray; padding-bottom: 3px;"><img src="/frontend/media/guestbook/elephant_small.png" alt="" border="0" />  <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.EntryNo" /> <template:placeholder name="ID" /></strong></div>
    <div class="guestbook_padding_background">
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Name" />:</strong> <template:placeholder name="Name" />
      <br />
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.EMail" />:</strong> <template:placeholder name="EMail" />
      <br />
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.City" />:</strong> <template:placeholder name="City" />
      <br />
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Website" />:</strong> <template:placeholder name="Website" />
      <br />
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.ICQ" />:</strong> <template:placeholder name="ICQ" />,
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.MSN" />:</strong> <template:placeholder name="MSN" />,
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Skype" />:</strong> <template:placeholder name="Skype" />,
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.AIM" />:</strong> <template:placeholder name="AIM" />,
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Yahoo" />:</strong> <template:placeholder name="Yahoo" />
    </div>
    <div class="guestbook_padding_background" style="background-color: white;">
      <template:placeholder name="Text" />
      <template:placeholder name="Comments" />
    </div>
    <div class="guestbook_padding_background" style="padding-top: 2px; padding-bottom: 2px;">
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Date" />:</strong> <template:placeholder name="Date" />, <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Time" />:</strong> <template:placeholder name="Time" />
    </div>
  </div>
  <div style="width: 100%; text-align: right;">
    <template:placeholder name="AdminAddComment" /> <template:placeholder name="AdminEdit" /> <template:placeholder name="AdminDelete" />
  </div>
  <br />
  <br />
</html:template>

<html:template name="Comment">
  <template:addtaglib namespace="tools::html::taglib" prefix="template" class="getstring" />
  <br />
  <div style="width: 100%; margin: 10px; margin-bottom: 2px;">
    <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Comment" />:</strong>
  </div>
  <div style="width: 98%; margin: 10px; margin-top: 2px; margin-bottom: 0px; margin-right: 0px; border: 1px solid #dddddd;">
    <div style="background-color: #dddddd; padding-left: 2px;">
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Title" />:</strong> <template:placeholder name="Title" />
    </div>
    <div style="padding: 5px;">
      <template:placeholder name="Text" />
    </div>
    <div style="background-color: #dddddd; padding-left: 2px;">
      <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Date" />:</strong> <template:placeholder name="Date" />, <strong><template:getstring namespace="modules::guestbook" config="guestbook_lang" entry="Text.Time" />:</strong> <template:placeholder name="Time" />
    </div>
  </div>
  <div style="width: 98%; text-align: right;">
    <template:placeholder name="AdminEditComment" /> <template:placeholder name="AdminDeleteComment" />
  </div>
</html:template>

<html:template name="AdminDelete">
  <a href="<template:placeholder name="Link" />" title="Beitrag löschen!"><strong>[ del ]</strong></a>
</html:template>

<html:template name="AdminEdit">
  <a href="<template:placeholder name="Link" />" title="Beitrag bearbeiten!"><strong>[ edt ]</strong></a>
</html:template>

<html:template name="AdminAddComment">
  <a href="<template:placeholder name="Link" />" title="Kommentar hinzufügen!"><strong>[ cmt ]</strong></a>
</html:template>

<html:template name="AdminDeleteComment">
  <a href="<template:placeholder name="Link" />" title="Kommentar löschen!"><strong>[ del ]</strong></a>
</html:template>

<html:template name="AdminEditComment">
  <a href="<template:placeholder name="Link" />" title="Kommentar bearbeiten!"><strong>[ edt ]</strong></a>
</html:template>
Im Controller werden dann auf generische Art und Weise die Inhalte mit den Methoden __generateEntryList(), __createEntry() und __createComment() zusammengesetzt und in der Funktion transformContent() ausgegeben. Das Laden der Einträge übernimmt dabei die oben beschriebene Business-Schicht. Um die Einträge laden zu können wir der guestbookManager mit Hilfe der Funktion loadGuestbook() angefragt.
import('modules::guestbook::biz','guestbookManager');
import('tools::link','frontcontrollerLinkHandler');
import('core::session','sessionManager');
import('modules::guestbook::pres::documentcontroller','guestbookBaseController');
import('tools::string','stringAssistant');

class 
guestbook_display_v1_controller extends guestbookBaseController
{

   var 
$_LOCALS;
   var 
$__sessMgr;

   function 
guestbook_display_v1_controller(){
      
$this->__sessMgr = new sessionManager('Module_Guestbook');
    
// end function
   
}

   function 
transformContent(){

      
// Manager holen
      
$gM = &$this->__getGuestbookManager();

      
// Einträge ausgeben
      
$this->setPlaceHolder('Content',$this->__generateEntryList());

      
// Pager ausgeben
      
$this->setPlaceHolder('Pager',$gM->getPager());

      
// Eintragen-Link ausgeben
      
$this->setPlaceHolder('CreateEntry',$this->__generateCreateEntryLink());

      
// Eintragen-Link ausgeben
      
$this->setPlaceHolder('ControlGuestbook',$this->__generateControlGuestbookLink());

    
// end function
   
}

   function 
__generateCreateEntryLink(){

      
// Referenz auf das Template holen
      
$Template__CreateEntry = &$this->__getTemplate('CreateEntry_'.$this->__Language);

      
// Link generieren und einsetzen
      
$Link frontcontrollerLinkHandler::generateLink($_SERVER['REQUEST_URI'],array('gbview' => 'createentry','entryid' => ''));
      
$Template__CreateEntry->setPlaceHolder('Link',$Link);

      
// Ausgabe zurückgeben
      
return $Template__CreateEntry->transformTemplate();

    
// end function
   
}

   function 
__generateControlGuestbookLink(){

      
// Inhalte der Session erstören
      
$oSessMgr = new sessionManager('Module_Guestbook');

      if(
$oSessMgr->loadSessionData('AdminView') == 'true'){

         
// Referenz auf das Template holen
         
$Template__ControlGuestbook_Logout = &$this->__getTemplate('ControlGuestbook_Logout_'.$this->__Language);

         
// Link generieren und einsetzen
         
$Link frontcontrollerLinkHandler::generateLink($_SERVER['REQUEST_URI'],array('gbview' => 'adminlogin','logout' => 'true','entryid' => ''));
         
$Template__ControlGuestbook_Logout->setPlaceHolder('Link',$Link);

         
// Ausgabe zurückgeben
         
return $Template__ControlGuestbook_Logout->transformTemplate();

       
// end if
      
}
      else{

         
// Referenz auf das Template holen
         
$Template__ControlGuestbook_Login = &$this->__getTemplate('ControlGuestbook_Login_'.$this->__Language);

         
// Link generieren und einsetzen
         
$Link frontcontrollerLinkHandler::generateLink($_SERVER['REQUEST_URI'],array('gbview' => 'adminlogin','entryid' => ''));
         
$Template__ControlGuestbook_Login->setPlaceHolder('Link',$Link);

         
// Ausgabe zurückgeben
         
return $Template__ControlGuestbook_Login->transformTemplate();

       
// end else
      
}

    
// end function
   
}

   function 
__generateEntryList(){

      
// Manager holen
      
$gM = &$this->__getGuestbookManager();

      
// Einträge holen
      
$Guestbook $gM->loadGuestbook();
      
$Entries $Guestbook->getEntries();

      
// Ausgabe generieren
      
$Buffer = (string)'';

      for(
$i 0$i count($Entries); $i++){
         
$Buffer .= $this->__generateEntry($Entries[$i]);
       
// end for
      
}

      
// Puffer ausgeben
      
return $Buffer;

    
// end function
   
}

   function 
__generateEntry($Entry){

      
// Referenz auf das Template holen
      
$Template__Entry = &$this->__getTemplate('Entry');

      
// Werte setzen
      
$Template__Entry->setPlaceHolder('AdminDelete',$this->__showAdminDelete($Entry->get('ID')));
      
$Template__Entry->setPlaceHolder('AdminEdit',$this->__showAdminEdit($Entry->get('ID')));
      
$Template__Entry->setPlaceHolder('AdminAddComment',$this->__showAdminAddComment($Entry->get('ID')));
      
$Template__Entry->setPlaceHolder('ID',$Entry->get('ID'));
      
$Template__Entry->setPlaceHolder('Name',$Entry->get('Name'));
      
$Template__Entry->setPlaceHolder('EMail',stringAssistant::encodeCharactersToHTML($Entry->get('EMail')));
      
$Template__Entry->setPlaceHolder('City',$Entry->get('City'));
      
$Template__Entry->setPlaceHolder('Website',$Entry->get('Website'));
      
$Template__Entry->setPlaceHolder('ICQ',$Entry->get('ICQ'));
      
$Template__Entry->setPlaceHolder('MSN',$Entry->get('MSN'));
      
$Template__Entry->setPlaceHolder('Skype',$Entry->get('Skype'));
      
$Template__Entry->setPlaceHolder('AIM',$Entry->get('AIM'));
      
$Template__Entry->setPlaceHolder('Yahoo',$Entry->get('Yahoo'));
      
$Template__Entry->setPlaceHolder('Text',nl2br($Entry->get('Text')));
      
$Template__Entry->setPlaceHolder('Date',$Entry->get('Date'));
      
$Template__Entry->setPlaceHolder('Time',$Entry->get('Time'));

      
// Comments einfügen
      
$Comments $Entry->getComments();
      
$CommentBuffer = (string)'';

      if(
count($Comments) > 0){

         for(
$i 0$i count($Comments); $i++){
            
$CommentBuffer .= $this->__generateComment($Comments[$i],$Entry->get('ID'));
          
// end if
         
}

       
// end if
      
}

      
$Template__Entry->setPlaceHolder('Comments',$CommentBuffer);

      
// Ausgabe zurückgeben
      
return $Template__Entry->transformTemplate();

    
// end function
   
}

   ...

 
// end class

8.3. Formular-View

Im Formular-View wird das Formular zum Erzeugen eines Inhalts ausgegeben. Die Template-Datei definiert im Wesentlichen das Formular und dessen Verhalten hinsichtlich Validierung der Felder.
<@controller namespace="modules::guestbook::pres::documentcontroller" class="guestbook_createentry_v1_controller" file="guestbook_createentry_v1_controller" @>
<core:addtaglib namespace="tools::form::taglib" prefix="html" class="form" />
<core:addtaglib namespace="tools::html::taglib" prefix="html" class="getstring" />
<br />
<br />
<strong><html:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Title" /></strong>
<br />
<br />
<html:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Hint" />
<br />
<br />
<html:placeholder name="Form" />

<html:form name="GuestbookEntry" method="post">
  <table cellpadding="0" cellspacing="0" class="formtable">
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Name" />
      </td>
      <td class="formtable_row_control">
        <form:text name="Name" class="eingabe_feld" style="width: 300px;" validate="true" button="CreateGuestbookEntryButton"/>
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.EMail" />
      </td>
      <td class="formtable_row_control">
        <form:text name="EMail" class="eingabe_feld" style="width: 300px;" validate="true" validator="EMail" button="CreateGuestbookEntryButton" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.City" />
      </td>
      <td class="formtable_row_control">
        <form:text name="City" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Website" />
      </td>
      <td class="formtable_row_control">
        <form:text name="Website" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.ICQ" />
      </td>
      <td class="formtable_row_control">
        <form:text name="ICQ" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.MSN" />
      </td>
      <td class="formtable_row_control">
        <form:text name="MSN" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Skype" />
      </td>
      <td class="formtable_row_control">
        <form:text name="Skype" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.AIM" />
      </td>
      <td class="formtable_row_control">
        <form:text name="AIM" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td class="formtable_row_description">
        <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Yahoo" />
      </td>
      <td class="formtable_row_control">
        <form:text name="Yahoo" class="eingabe_feld" style="width: 300px;" />
      </td>
    </tr>
    <tr>
      <td colspan="2" class="formtable_row_description">
        <br />
        <strong><form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Text" /></strong> *
        <br />
        <br />
        <form:area name="Text" class="eingabe_feld" style="height: 200px; width: 480px; overflow: auto;" validate="true" button="CreateGuestbookEntryButton" />
      </td>
    </tr>
    <tr>
      <td colspan="2" class="formtable_row_description">
        <br />
        <strong><form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Captcha" /></strong>
        <br />
        <br />
        <form:addtaglib namespace="modules::captcha::pres::taglib" prefix="form" class="captcha" />
        <form:captcha text_class="eingabe_feld" validate="true" button="CreateGuestbookEntryButton"/>
      </td>
    </tr>
  </table>
  <br />
  <span style="font-size: 11px;">
    <form:getstring namespace="modules::guestbook" config="guestbook_lang" entry="CreateEntry.Form.Hint" />
  </span>
  <br />
  <br />
  <br />
  <form:button name="CreateGuestbookEntryButton" value="Eintragen" class="eingabe_feld" />
</html:form>
Der zugehörige DocumentController implementiert dazu lediglich die Methode transformContent(), in der abgefragt wird, ob das Formular korrekt ausgefüllt wurde. Ist das der Fall wird aus den Werten ein Entry-Domain-Objekt erstellt und dieses an die Business-Schicht zur Speicherung desselben weitergegeben.
import('modules::guestbook::biz','guestbookManager');
import('modules::guestbook::pres::documentcontroller','guestbookBaseController');

class 
guestbook_createentry_v1_controller extends guestbookBaseController
{

   var 
$_LOCALS;

   function 
guestbook_createentry_v1_controller(){

      
$this->_LOCALS variablenHandler::registerLocal(array(
                                                             
'Name',
                                                             
'EMail',
                                                             
'City',
                                                             
'Website',
                                                             
'ICQ',
                                                             
'MSN',
                                                             
'Skype',
                                                             
'AIM',