Frontcontroller

1. Einleitung

Artikel bewerten:
Dieser Artikel wurde von 2 Leser(n) mit
Adventure PHP Framework Artikel bewertenAdventure PHP Framework Artikel bewertenAdventure PHP Framework Artikel bewertenAdventure PHP Framework Artikel bewerten (3.5)
von 5 Punkten bewertet. Bewerten auch Sie diesen Artikel!
Ein weiterer Bestandteil dieses Frameworks ist - wie bereits erwähnt - eine Implementierung des Frontcontrollers. Basis für die hier zur Verfügung stehende Implementierung ist die Pattern-Definition von Martin Fowler und die Auslegung des Patterns im JAVA-Framework Struts. Einführend Beispiele können auf der PHP-Patterns- Webseite eingesehen werden.

Die FrontController-Komponente des Applikations-Frameworks besteht aus einer Singleton-Instanz der Klasse FrontController, die den Benutzer-Requests auswertet und die enthaltenen Anweisungen ausführt. Es gibt mehrere Arten von Actions, die gemäß den später beschriebenen Timing Model ausgeführt werden. Im Allgemeinen werden Actions, die das Schlüsselwort "pre" enthalten, vor einer definierten Aktion ausgeführt und Actions mit "post" in der Typenbezeichnung nach einem Code-Teil. Aktionen des Typs "prepagecreate" dienen meist zum Aufbau des Models einer Applikation, Actions des Typs "posttransform" z.B. für Logging-Aufgaben oder Ähnliches. Um eigene Actions zu implementieren bietet das Framework zwei abstrakte Basisklassen für Actions (AbstractFrontcontrollerAction) und ihre Informationen (FrontcontrollerInput). Der frontcontrollerRequestFilter und der frontcontrollerRewriteRequestFilter sind Komponenten, die die Action-Anweisungen aus der URL extrahieren, so dass der FrontController diese ausführen kann. Mit diesen beiden Komponenten kommt der Entwickler aber in der Regel nicht in Berührung, da diese vom FrontController selbstständig ausgeführt werden. Um Actions zu haben, die bei jedem Request ausgeführt werden, hat der Entwickler die Möglichkeit diese Actions in der index.php zu registrieren. Diese verhalten sich gemäß dem Timing Model wie normale Actions. Das folgende UML-Diagramm zeigt die Komponenten des FrontControllers in der Übersicht:

Frontcontroller Actions Inputs UML


2. Implementierung

Die Implementierung im FrontController-Style beinhaltet im Wesentlichen zwei Bereiche. Zum einen muss eine Action- und Input-Klasse erzeugt werden, die jeweils von AbstractFrontcontrollerAction und FrontcontrollerInput ableiten, zum anderen muss eine Konfiguration angelegt werden, die eine Action beschreibt.


2.1. Action- und Input-Klassen

Die vom Entwickler erzeugte Action-Klasse kapselt die Funktion einer Action. Wie der API-Dokumentation der Klasse AbstractFrontcontrollerAction zu entnehmen ist, muss hierzu die Methode run() implementiert werden, da diese bei der Ausführung einer Action durch den FrontController angesprochen wird. Die Input-Klasse ist eine einfache Daten-Klasse die die Model-Informationen der jeweiligen Action beinhaltet. Ein Input-Objekt kann im einfachsten Anwendungsfall auch das Model einer Applikation sein. Das folgende Code-Beispiel zeigt zwei einfache Action- und Input-Klassen:

   class DemoAction extends AbstractFrontcontrollerAction
   
{

      function 
DemoAction(){
      }

      function 
run(){
         echo 
'I am front controller action class! My Name is '.$this->__Input->getAttribute('Name').'!';
       
// end function
      
}

    
// end class
   
}

   class 
DemoInput extends FrontcontrollerInput
   
{

      function 
DemoInput(){
         
$this->__Attributes['Name'] = 'Max Mueller';
       
// end function
      
}

    
// end class
   
Wird die hier gezeigte Action ausgeführt, erscheint im Browser der Satz
  I am front controller action class! My Name is Max Mueller!
Da die Actions ebenso den Context der Applikation kennen, können in den Actions beliebige Applikations-Teile verpackt werden. Ein beliebtes Beispiel ist die Benutzer-Authentifizierung. In der Action kann dann abgeprüft werden, ob der Benutzer eingeloggt ist oder nicht und ggf. die Model- Informationen des Login-Moduls setzen.


2.2. Konfiguration

Jede Action muss in einer Konfigurations-Datei definiert sein. Zur Definition gehören der Namespace, die Dateinamen für Action- und Input-Klassen, deren Namen selbst und evtl. benötigte Model-Informationen. Konfigurations-Dateien werden immer unter dem Verzeichnis
{ActionNamespace}::actions::{Context}
und mit dem Namen
{ENVIRONMENT}_actionconfig.ini
abgelegt. {ENVIRONMENT} ist dabei gegen den Wert der Umgebungsvariable zu ersetzen. Im Standard-Fall ist dies der Wert DEFAULT. Eine Action-Konfiguration beinhalten dabei ein oder mehrere Definitionen von Actions, die wie folgt aussehen:
[{ActionName}]
FC.ActionNamespace = ""
FC.ActionFile = ""
FC.ActionClass = ""
FC.InputFile = ""
FC.InputClass = ""
FC.InputParams = ""
Die aufgeführten Parametern haben dabei folgende Bedeutungen:
Da FrontController-Actions in der Regel Teile der Business-Schicht sind, sollten diese unter dem biz-Ordner einer Seite, Applikation oder eines Moduls abgelegt werden. Sinnvollerweise legt der Entwickler im Ordner biz noch einen Unterordner actions an, um die Übersichtlichkeit zu verbessern. Da Namespace, Namen der Dateien und Klassen frei wählbar sind, ist dem Entwickler hinsichtlich der Benennung und Strukturierung freie Hand gelassen.


2.3. Änderungen in der index.php

Um eine Applikation im FrontController-Style laufen zu lassen, sollte in der index.php folgendes eingetragen sein:
   // Instanz des Frontcontroller holen/erzeugen
   
$fC = &Singleton::getInstance('Frontcontroller');

   
// Context der Applikation setzen
   
$fC->set('Context','sites::demosite');

   
// Sprache der Applikation setzen
   
$fC->set('Language','de');

   
// Seite generieren
   
$fC->start('sites::demosite::pres::templates','website'); 
Ist es erwünscht, "permanente" Actions auszuführen, so ist ein
   // Standard-Action "Login" mitteilen
   
$fC->registerAction('sites::demosite::biz','Login'); 
vor dem Aufruf der Methode start() notwendig. Anschließend ist es jederzeit möglich Actions von Modulen oder Applikationen ausführen zu lassen.


2.4. Generierung von Links

Um Links in FrontController-basierten Applikationen ebenso einfach generieren zu können wie bei PageController-Anwendungen wurde die Komponente frontcontrollerLinkHandler eingeführt. Diese manipuliert einen Link auf Basis einer bestehenden URL und bettet alle in der URL erwünschten Action-Definitionen aus dem aktuellen Input-Objekt der Action ein.

Hinweis: Diese Verhaltensweise wird nur erreicht, sofern in der gewünschten Action die Klassen-Variable $__KeepInURL im Konstruktor auf true gesetzt wurde. In der Standard-Definition enthält diese den Wert false. Andernfalls werden alle Action-Anweisungen aus der generierten URL entfernt. Damit ist es möglich, komplexe Applikationen zu entwerfen, in denen unabhängige Module über eine lose URL-Kopplung koexistieren.

Das folgende Beispiel zeigt, wie der frontcontrollerLinkHandler angewendet wird. Der Einfachheit halber werden Links nur im Rewrite-Modus betrachtet. Die Manipulation ohne URL-Rewriting funktioniert analog dazu.


2.4.1. Einfache Manipulation von Parametern
In vielen Applikationen ist es notwenig Links zu generieren. In Frontcontroller-basierten Anwendungen, in denen keine Action-Anweisungen in URLs manupuliert werden müssen, kann der frontcontrollerLinkHandler wie sein "kleiner Bruder" linkHandler eingesetzt werden um URLs zu erzeugen. Aus einem Link
  http://www.adventure-php-framework.org/Seite/ChangeLog/benchmarkreport/true/param1/value1/param2/value2
kann auf einfache Weise
  http://www.adventure-php-framework.org/Seite/Guestbook/benchmarkreport/true
generiert werden. Hierzu ist lediglich ein
   // URL definieren
   
$URL 'http://www.adventure-php-framework.org/Seite/ChangeLog/benchmarkreport/true/param1/value1/param2/value2';

   
// URL-Aenderungen definieren
   
$ChangeParams = array(
                         
'Seite' => 'Guestbook',
                         
'param1' => '',
                         
'param2' => ''
                         
);

   echo 
frontcontrollerLinkHandler::generateLink($URL,$ChangeParams); 
notwenig.


2.4.2. Manipulation von Parametern und Actions
Actions werden gleichermaßen als URL-Parameter behandelt wie "normale" URL-Bestandteile. Daher gestaltet es sich sehr einfach, aus einer URL
  http://www.adventure-php-framework.org/Seite/ChangeLog/benchmarkreport/true/param1/value1/param2/value2
den Link
  http://www.adventure-php-framework.org/Seite/Guestbook/benchmarkreport/true/param1/value1/param2/value2/~/
  modules_guestbook_biz-action/LoadEntryList/pagesize/20/pager/false/adminview/true
zu generieren. Hier wurde lediglich durch ein geändertes Parameter-Array eine Action hinzugefügt:
   // URL definieren
   
$URL 'http://www.adventure-php-framework.org/Seite/ChangeLog/benchmarkreport/true/param1/value1/param2/value2';

   
// URL-Aenderungen definieren
   
$ChangeParams = array(
                         
'modules_guestbook_biz-action:LoadEntryList' => 'pagesize:20|pager:false|adminview:true',
                         
'Seite' => 'Guestbook'
                         
);

   
// Link generieren
   
echo frontcontrollerLinkHandler::generateLink($URL,$ChangeParams); 
Wurde die in der URL darzustellende Action bereits als "permanente" Action in der index.php eingehängt ist es lediglich notwendig, den frontcontrollerLinkHandler aufzurufen und die gewünschten "normalen" Parameter zu manipulieren. Dabei werden die vorhandenen Actions automatisch in die URL eingefügt.


2.4.3. Manipulation von Parametern und Actions mit generateURLParams()
Das Beispiel in Kapitel 1.4.2. hat den Nachteil, dass sich der Entwickler Gedanken über die Semantik einer FrontController-URL machen muss. Um URL-Generierung noch komfortabler zu gestalten, wurde dem frontcontrollerLinkHandler die Methode generateURLParams hinzugefügt. Diese ermöglicht, aus einem Satz von Parametern eine Action-Anweisung in Form eines Arrays zu generieren, das der Methode generateLink übergeben werden kann. Die URL-Generierung kann dann wie folgt erfolgen:
   // URL definieren
   
$URL 'http://www.adventure-php-framework.org/Seite/ChangeLog/benchmarkreport/true/param1/value1/param2/value2';

   
// URL-Aenderungen definieren
   
$ChangeParams = array(
                         
'Seite' => 'Guestbook'
                        
);

   
// Parameter der FrontController-Action erzeugen
   
$ChangeParams array_merge(
                               
$ChangeParams,
                               
frontcontrollerLinkHandler::generateURLParams(
                                                                             
'modules::guestbook::biz',
                                                                             
'LoadEntryList',
                                                                             array(
                                                                                   
'pagesize' => '20',
                                                                                   
'pager' => 'false',
                                                                                   
'adminview'  => 'true'
                                                                                  
)
                                                                             )
                              );

   
// Link generieren
   
echo frontcontrollerLinkHandler::generateLink($URL,$ChangeParams); 
Aus Performancegründen sollte diese Methode allerdings nicht übermäßig Verwendung finden, da diese bereits ~0.004 s zur Generierung des Parameter-Arrays benötigt. Ist klar, in welchem Betriebsmodus die Anwendung später laufen wird (Rewrite-URLs vs. normale URLs), sollte auf ein manuelles Generieren der URLs, wie in Kapitel 1.4.2. aufgezeigt, zurückgegriffen werden.


2.5. Timing-Modell

Der FrontController besitzt ein eigenes vierstufiges Timing-Modell, mit dem vom Entwickler beeinflusst werden kann, wann eine Action ausgeführt wird. Hierzu existiert in der Interface-Definition der Klasse AbstractFrontcontrollerAction das Attribut $__Type. Dieses ist standardmäßig mit dem Wert prepagecreate gefüllt. Soll die Action zu anderen Zeiten zum Einsatz kommen, so stehen folgende Werte für diesen Parameter zur Verfügung: Das Timing kann nur zur Entwicklungszeit per
   class MyAction extends AbstractFrontcontrollerAction
   
{

      
// Timing festlegen
      
var $__Type 'pretransform';


      function 
MyAction(){
      }

      function 
run(){
      }

    
// end class
   
manipuliert werden. Implementierungsdetails zur Methode run() finden sich in der API-Dokumentation der Klasse Frontcontroller.


2.6. Model-basiertes View-Konzept

Da es mit dem Frontcontroller möglich ist, die Business-Schicht, bzw. das Model der Anwendung vor der Präsentationsschicht zu erzeugen, kann, im Gegensatz zu einer PageController-Implementierung, die Business-Schicht dazu verwendet werden, die Präsentationsschicht zu steuern. Der hier wichtigste Bereich ist die Steuerung von Views, bzw. der Inhalte der Views.

Um den Vorteil einer Frontcontroller-basierten Anwendung auch im Bereich des GUI-Designs voll ausschöpfen zu können wurde den HTML-Tools die TagLib fcon_taglib_importdesign hinzugefügt. Diese Komponente bindet, wie oben angedeutet, Views ein die im Model der Anwendung definiert werden. Üblicherweise wird für das Model ein eigenes Applikationsmodel definiert, das aus Frontcontroller-Actions bedient und gefüllt wird. Hierzu wird in der Regel eine eigene Klasse der Form
   class DemoSiteModel extends coreObject
   
{

      function 
DemoSiteModel(){
         
$this->__Attributes['view.content.template'] = 'login';
         
$this->__Attributes['view.topmenu.template'] = 'empty';
       
// end function
      
}

    
// end class
   
implementiert, die an den relevanten Stellen mit einem
   $Model =&$this->__getServiceObject('sites::demosite::biz','DemoSiteModel'); 
verwendet oder befüllt werden kann.

In einer Template-Datei kann dann mit einem
  <fcon:importdesign
      templatenamespace="sites::apfdocupage::pres::templates"
      modelnamespace="sites::demosite::biz"
      modelfile="DemoSiteModel"
      modelclass="DemoSiteModel"
      modelparam="view.content.template"
  />
ein View in Abhängigkeit der Inhalte des Models eingebunden werden. Um die TagLib verwenden zu können muss diese jedoch dem aktuellen Document zunächt per
  <core:addtaglib namespace="tools::html::taglib" prefix="fcon" class="importdesign" />
bekannt gemacht werden.

Mit diesem Konstrukt lässt sich die Einbindung von Views bequem über das Model einer Applikation steuern und so die Verantwortung wird komplett an die Business-Schicht übergeben. Des Weiteren erfährt die Implementierung an Flexibilität gegenüber der Verwendung des PageControllers als alleinige Steuerungskomponente für das Aussehen einer GUI.


Kommentare

Bitte geben Sie Ihren Kommentar hier ein. Füllen Sie alle mit * gekennzeichneten Felder vollständig und korrekt aus. Um zum Artikel zurückzukehren klicken sie bitte hier. Zur Formatierung des Textes können folgende BBCode-ähnliche die Zeichen verwendet werden:Hinweis: Formatierungszeichen in Name und E-Mail-Adresse werden nicht akzeptiert.

Name:*
E-Mail:*

Kommentar:


Bestätigungscode:*