Frontcontroller-Tutorial
Artikel bewerten:
Bitte bewerten Sie den Artikel per Klick auf einen der angezeigten Sterne:
Zurück zum 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:
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
Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
Für diesen Artikel liegen aktuell keine Kommentare vor.