Frontcontroller-Tutorial

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 bewertenAdventure PHP Framework Artikel bewerten (4.5)
von 5 Punkten bewertet. Bewerten auch Sie diesen Artikel!

1. Einführung

Die Frontcontroller-Implementierung des Frameworks kann durch das Timing-Modell für unterschiedliche Bereiche eingesetzt werden. Das folgende Diagramm zeigt, wann Actions bei der Ausführung der Frontcontroller-Methode start() ausgeführt werden:

Frontcontroller timing model

Das vorliegende Tutorial möchte nun Einsatzgebiete des Frontcontrollers aufzeigen und konkrete Hinweise für die Implementierungen geben. Als typische Anwendungsfälle werden nun im Folgenden die Auslieferung von Bildern und die Prüfung von Login-Informationen, die zum Aufbau eines Applikationsmodels dienen, diskutiert.


2. Auslieferung von Bildern

Das Framework bietet dem Entwickler mit der Bootstrap-Architektur an, alle Inhalte über eine zentrale PHP-Datei ausliefern zu lassen. Je mehr Module eine Applikation besitzt, desto größer wird der Wunsch, auch PopUp-Fenster mit speziellen Inhalten wie Druck-Ansichten oder Formularen, bzw. Medien wie Bilder und Videos über diesen Mechanismus auszuliefern. Um derartige Inhalte darstellen zu können wird in der Regel eine weitere Bootstrap-Datei für das gewünschte Modul angelegt, das in den meißten Fällen zur index.php redundanten Code enthält.

Mit Hilfe des Frontcontrollers, bzw. einer Frontcontroller-Action, kann diesem Problem Abhilfe geschaffen werden. Das Timing-Modell des Frontcontroller-Dispatcher-Prozesses (obiges Diagramm) sieht vor, dass eine Action vor dem Erstellen der Pagecontroller-Seite (prepagecreate, siehe Frontcontroller-Dokumentation) ausgeführt werden kann. Der Entwickler ist dabei durch die Gestaltung des HTML-Codes frei, ob die mit der Action-Anweisung aufgerufene Seite im selben, oder in einem neuen Fenster erscheinen soll. Weiterer Vorteil ist, dass der Programm-Code des präsentierten Inhalts im Namespace des jeweiligen Moduls abgelegt werden kann und so eine einheitlichere und sauberere Struktur des Quellcodes erreicht werden kann. Zudem kann innerhalb einer Action problemlos eine PageController-Seite erzeugt, transformiert und ausgegeben werden um den Inhalt eines PopUp-Fensters zu zeigen.

Wie in der FrontController-Dokumentation beschrieben ist, wird eine Action durch eine Sektion in einer Konfigurationsdatei, einer Action- und einer Input-Klasse definiert. Der Umfang der Input-Klasse richtet sich nach dem Umfang der auszuliefernden Applikation, bzw. der zu erledigenden Aufgabe. Im Modul socialbookmark, das mit jedem Release ausgeliefert wird, wird die im Folgenden beschriebene Action zur Auslieferung der Bookmark-Service-Symbole folgende Dateien verwendet. Diese soll nun näher erläutert werden.


2.1. Action-Konfiguration

Die Datei DEFAULT_actionconfig.ini (siehe Ordner apps/config/modules/socialbookmark/action/sites/demosite/ im adventure-demopack-*-Release-Package) definiert die Bestandteile der Action und die Bezeichnung der Action in der URL. In den Input-Parametern werden Standard-Werte für das Input-Objekt definiert, die später Anwendung finden:
[showImage]
FC.ActionNamespace = "modules::socialbookmark::biz::actions"
FC.ActionFile = "ShowImageAction"
FC.ActionClass = "ShowImageAction"
FC.InputFile = "ShowImageInput"
FC.InputClass = "ShowImageInput"
FC.InputParams = "img:bookmark_del_icio_us|imgext:png"

2.2. Action-Implementierung

Die Datei ShowImageAction.php beinhaltet die Definition des Programm-Codes der Action. Im Fall der Bild-Auslieferung wird der Pfad zum angefragten Service-Bilder zusammengesetzt, der entsprechende Header und anschließend das Bild selbst gesendet. Um die Verarbeitung nach dem Ausliefern des Bildes zu stoppen, wird am Ende ein exit() notiert. Andernfalls würde die in der index.php definierte Seite ausgeliefert werden und der Browser könnte das Bild nicht korrekt anzeigen. Folgender Quellcode ist für die Anzeige eines Bildes zuständig:
   class ShowImageAction extends AbstractFrontcontrollerAction
   
{

      function 
ShowImageAction(){
      }

      function 
run(){

         
// Bild aus dem Input-Objekt beenden
         
$Image APPS__PATH.'/modules/socialbookmark/pres/image/';
         
$Image .= $this->__Input->getAttribute('img').'.'.$this->__Input->getAttribute('imgext');

         
// Header senden
         
header('Content-type: image/'.$this->__Input->getAttribute('imgext'));
         
header('Cache-Control: public');

         
// Datei streamen
         
readfile($Image);

         
// Abarbeitung beenden
         
exit();

       
// end function
      
}

    
// end class
   

2.3. Input-Definition

Die Datei ShowImageInput.php beinhaltet die Definition des Input-Objekts, in dem die Parameter des Action-Aufrufs bereitgestellt werden. Im Fall der Bild-Auslieferung sind hier keine weiteren Parameter-Definitionen notwendig und folgender PHP-Code genügt um die Definition der Action zu komplettieren.
   class ShowImageInput extends FrontcontrollerInput
   
{

      function 
ShowImageInput(){
      }

    
// end class
   

2.4. Praktische Anwendung

Im Socialbookmark-Modul werden die Symbole der Bookmark-Anbieter an den entsprechenden Stellen per
  <img src="/~/modules_socialbookmark-action/showImage/imgext/png/img/bookmark_technorati" alt="" />
eingebunden. Analysiert man den Aufruf der unter 2.2. dargestellten Action, so kommt den Parametern folgende Bedeutung zu:

3. Prüfung von Login-Informationen

Frontcontroller-Actions werden in der Regel dazu verwendet ein Applikationsmodel, das den Status der Anwendung repräsentiert, vor der Erzeugung der Präsentationsschicht aufzubauen. Hierzu bedient sich ein Action aus dem Input-Objekt, das vom Frontcontroller bereitgestellt wird. Falls erwünscht, können in der Konfiguration der Action bereits Standard-Werte für die Input-Parameter definiert werden. Diese dienen dann zum Zeitpunkt der Verarbeitung der Action als Standard-Attribute.

Beim Thema "Prüfung von Login-Informationen" besteht die Aufgabe der Action darin, im Request mitgesendete Login-Informationen zu prüfen oder diese aus bestehenden Sessions oder Cookies auszulesen und entsprechend für die Applikation zur Verfügung zu stellen. Diese dienen dann der übrigen Businesslogik als Grundlage der Applikationssteuerung und Erzeugung der GUI. Frontcontroller-Actions sind dabei als Bestandteil der Business-Logik zu sehen.

Das beschriebene Szenario beinhaltet im Wesentlichen zwei "business cases": Login-Informationen werden mitgesendet und Login-Informationen müssen aus anderen Quellen (Session, Cookie) bezogen und aufbereitet werden. Um einem Benutzer die Möglichkeit zu geben, sich per Cookie einzuloggen, muss die Action bei jedem Request ausgeführt werden. Zu diesem Zweck kann die für das Handling der Login-Informationen verantwortliche Action als "permanente" Action registriert werden. Dies geschieht in Bootstrap-Datei per
   $fC = &Singleton::getInstance('Frontcontroller');
   
$fC->set('Context','my::context');
   
$fC->registerAction('my::namespace','myAction'); 
Die Implementierung der Action besteht auch hier aus drei Komponenten. Im Rahmen von MCV-, FrontController- und 3-Schicht-Architektur-basierten Applikationen ist es dabei hilfreich, ein zentrales Applikationsmodel zu definieren, das den aktuellen Zustand der Applikation speichert. Dieses Objekt kann später zur Ablaufsteuerung innerhalb der Businessschicht und zur Gestaltung der GUI eingesetzt werden.

Für das Login-Beispiel dient die nachstehend aufgeführte Klasse als Applikationsmodel. Um das Beispiel einfache zu gestalten, werden nur folgende Model-Informationen beachtet:
   class ApplicationModel extends coreObject
   
{

      function 
ApplicationModel(){

         
// Definiert den gerade anzuzeigenden View (login|welcome)
         
$this->__Attributes['view.content.template'] = 'login';

         
// User-ID des aktuell eingeloggten Benutzers (null|user_id)
         
$this->__Attributes['user.id'] = null;

         
// Definiert die Methode des Logins (request|cookie|session)
         
$this->__Attributes['login.mode'] = 'request';

         
// Zeigt, ob ein fehlgeschlagener Login vorliegt
         
$this->__Attributes['login.status'] = null;

       
// end function
      
}

    
// end class
   
Im Quellcode-Beispiel wird die private Klassenvariable $__Attributes als Container für Model-Attribute verwendet. Das bietet den Vorteil, dass diese später durch den <fcon:importdesign />-Tag ausgelesen und zur Gestaltung der GUI genutzt werden können. Details können in Kapitel 5 der Sektion Standard-TagLibs eingesehen werden.


3.1. Action-Konfiguration

Um die Action als permanente Action registrieren oder über die URL ansprechen zu können, muss zunächst eine Konfigurationssektion angelegt werden. Hierzu kann folgendes Schema als Vorlage dienen:
[Login]
FC.ActionNamespace = "my::module::biz::actions::login"
FC.ActionFile = "LoginAction"
FC.ActionClass = "LoginAction"
FC.InputFile = "LoginInput"
FC.InputClass = "LoginInput"
FC.InputParams = ""

3.2. Action-Implementierung

Die eigentliche Funktionalität der Action wird in der run()-Methode definiert. Folgender Code kann dazu eingesetzt werden:
      function run(){

         
// Lokal verwendete Variablen registrieren
         
$_LOCALS variablenHandler::registerLocal(array('Username','Password','ID'));

         
// Model der Anwendung holen
         
$Model = &$this->__getServiceObject('my::namespace','ApplicationModel');

         
// sessionManager erzeugen
         
$Session = new sessionManager('MyApplication');

         
// Fall 1: (keine direkte Benutzerinteraktion)
         //
         //   a) Daten aus Session sind nicht leer und diese können erfolgreich
         //      validiert werden.
         //   b) Daten sind nicht in der Session enthalten.
         //
         
if(!isset($_REQUEST['Login'])){

            
// Fall 1.1: Session-Daten auslesen und prüfen
            
$Username $Session->loadSessionData('Username');
            
$Password $Session->loadSessionData('Password');

            if(!empty(
$Username) && !empty($Password)){

               if(
$this->__validateCredentials($Username,$Password)){

                  
// Fall 1.1.1: Daten aus Session gewonnen und erfolgreich eingeloggt
                  
$Model->setAttribute('view.content.template','content');

                
// end if
               
}
               else{

                  
// Fall 1.1.2: Daten aus Session gewonnen und diese sind nicht valide
                  
$Model->setAttribute('view.content.template','login');

                
// end if
               
}

             
// end if
            
}
            else{

               
// Fall 1.2: Keine Daten aus Session erhältlich
               
$Model->setAttribute('view.content.template','login');

             
// end else
            
}

          
// end if
         
}
         else{

            if(
myValidator::validateText($_LOCALS['Username']) && myValidator::validateText($_LOCALS['Password'])){

               
// Falls 2.1: Versuch eines Logins
               
if($this->__validateCredentials($_LOCALS['Username'],md5($_LOCALS['Password']))){

                  
// Fall 2.1.1. Login-Vorgang war erfolgreich
                  
$Model->setAttribute('view.content.template','content');

                
// end if
               
}
               else{

                  
// Fall 2.1.2: Login-Vorgang war auf Grund falscher Benutzerdaten NICHT erfolgreich
                  
$Model->setAttribute('view.content.template','login');
                  
$Model->setAttribute('login.status','failed');

                
// end else
               
}

             
// end if
            
}
            else{

               
// Fall Falls 2.2: Formular wurde unvollständig ausgefüllt
               
$Model->setAttribute('view.content.template','login');

             
// end else
            
}

          
// end if
         
}

         
// Fall 3: (Logout)
         //
         
if($this->__Input->getAttribute('action') == 'logout'){

            
// Session-Daten löschen
            
$Session->destroySession('MyApplication');

            
// Benutzerdaten aus lokalem Array löschen
            
$_LOCALS['Username'] = '';
            
$_LOCALS['Password'] = '';
            
$_LOCALS['ID'] = '';

            
// Login-Formular erzeugen
            
$Model->setAttribute('view.content.template','login');

          
// end if
         
}

       
// end function
      
Die im Code-Beispiel verwendeten Framework-Komponenten wie sessionManager, variablenHandler und myValidator müssen natürlich zuvor per
   import('my::namespace','ApplicationModel');
   
import('core::session','sessionManager');
   
import('tools::variablen','variablenHandler');
   
import('tools::validator','myValidator'); 
eingebunden werden. Die private Methode __validateCredentials() kapselt die Prüfung der Login-Daten mit Hilfe einer Business-Komponente.

Um die Model-Informationen über die Session hinweg vorzuhalten, kann das Model auch SESSIONSINGLETON erzeugt werden. Damit ist es möglich, die Action nur beim Login bzw. Logout aufrufen zu müssen, da die Login-Informationen ohnehin über die Session zur Verfügung stehen. Um dieses Verhalten zu erzeugen muss das Model per
   $Model = &$this->__getServiceObject('my::namespace','ApplicationModel','SESSIONSINGLETON'); 
erzeugt werden.


3.3. Input-Definition

Im Fall der Login-Prüfung sind keine weiteren Parameter-Definitionen im Input-Objekt notwendig. Als Input-Klasse kann daher eine leere, von FrontcontrollerInput angeleitete Klasse, dienen (siehe 2.3.).


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