Front-Controller Tutorial

1. Einführung

Dieses Tutorial stellt Einsatzgebiete des Front-Controller vor und gibt konkrete Hinweise für Ihre Projekte.

Als typische Anwendungsfälle werden in den folgenden Kapitel die Auslieferung von Bildern, die Prüfung von Login-Informationen und die Sprachumschaltung Ihrer Applikation 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 Front-Controllers, bzw. einer Front-Controller-Action, kann diesem Problem Abhilfe geschaffen werden. Das Timing-Modell des Front-Controller-Dispatcher-Prozesses (obiges Diagramm) sieht vor, dass eine Action vor dem Erstellen der Page-Controller-Seite (TYPE_PRE_PAGE_CREATE, siehe Front-Controller) 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 Page-Controller-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 apf-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:

APF-Konfiguration
[showImage] ActionClass = "APF\modules\socialbookmark\biz\actions\ShowImageAction" 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:

PHP-Code
use APF\core\frontcontroller\AbstractFrontcontrollerAction; class ShowImageAction extends AbstractFrontcontrollerAction { public function run() { $classLoader = RootClassLoader::getLoaderByVendor('APF'); $rootPath = $classLoader->getRootPath(); $image = $rootPath . '/modules/socialbookmark/pres/image/'; $image .= $this->getInput()->getParameter('img') . '.' . $this->getInput()->getParameter('imgext'); header('Content-type: image/' . $this->getInput()->getParameter('imgext')); header('Cache-Control: public'); readfile($image); exit(); } }

2.3. Input-Definition

Im Fall der Bild-Auslieferung sind hier keine weiteren Parameter-Definitionen notwendig und damit ist keine eigene Input-Implementierung erforderlich.

2.4. Praktische Anwendung

Im Socialbookmark-Modul werden die Symbole der Bookmark-Anbieter an den entsprechenden Stellen per

APF-Template
<img src="/~/APF_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:

  • modules_socialbookmark: Namespace, unter dem die Definition (Konfiguration, siehe Kapitel 2.1) der Action gesucht wird.
  • -action: Das Kürzel dient dazu, eine Action-Anweisung in der URL zu identifizieren.
  • showImage: Name der Action und gleichzeitig der Name der Sektion der Definition.
  • imgext: Parameter imgext
  • png: Wert des Parameters imgext
  • img: Parameter img
  • bookmark_technorati: Wert des Parameters img

3. Prüfung von Login-Informationen

Front-Controller-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 Front-Controller 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. Front-Controller-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

PHP-Code
$fC = Singleton::getInstance(Frontcontroller::class); $fC->setContext('my-app'); $fC->registerAction('VENDOR\app\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:

PHP-Code
use APF\core\pagecontroller\APFObject; class ApplicationModel extends APFObject { /** * @var string Defines the log-in method (request|cookie|session). */ private $loginMode = 'request'; /** * @var string|null Indicates whether a failed log-in attempt exists. */ private $loginStatus = null; /** * @param string $loginMode */ public function setLoginMode($loginMode) { $this->loginMode = $loginMode; } public function getLoginMode() { return $this->loginMode; } public function setLoginStatus($loginStatus) { $this->loginStatus = $loginStatus; } public function getLoginStatus() { return $this->loginStatus; } }

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:

APF-Konfiguration
[Login] ActionClass = "VENDOR\module\biz\actions\login\LoginAction"

3.2. Action-Implementierung

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

PHP-Code
use APF\core\frontcontroller\AbstractFrontcontrollerAction; use APF\core\http\Session; class LoginAction extends AbstractFrontcontrollerAction { public function run() { $username = $this->getRequest()->getParameter('Username'); $password = $this->getRequest()->getParameter('Password'); $id = $this->getRequest()->getParameter('ID'); /* @var $model ApplicationModel*/ $model = & $this->getServiceObject('VENDOR\my\namespace\ApplicationModel'); // Session erzeugen $session = $this->getRequest()->getSession('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->setLoginMode('content'); } else { // Fall 1.1.2: Daten aus Session gewonnen und diese sind nicht valide $model->setLoginMode('login'); } } else { // Fall 1.2: Keine Daten aus Session erhältlich $model->setLoginMode('login'); } } else { if (!empty($username) && !empty($password)) { // Falls 2.1: Versuch eines Logins if ($this->validateCredentials($username, md5($password))) { // Fall 2.1.1. Login-Vorgang war erfolgreich $model->setLoginMode('content'); } else { // Fall 2.1.2: Login-Vorgang war auf Grund falscher Benutzerdaten NICHT erfolgreich $model->setLoginMode('login'); $model->setLoginStatus('failed'); } } else { // Fall Falls 2.2: Formular wurde unvollständig ausgefüllt $model->setLoginMode('login'); } } // Fall 3: (Logout) // if ($this->getInput()->getParameter('action') == 'logout') { // Session-Daten löschen $session->destroySession('MyApplication'); // Login-Formular erzeugen $model->setLoginMode('login'); } } private function validateCredentials($username, $password) { ... } }

Die private Methode validateCredentials() kapselt die Prüfung der Login-Daten.

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

PHP-Code
$model = &$this->getServiceObject( 'VENDOR\my\namespace\ApplicationModel', APFService::SERVICE_TYPE_SESSION_SINGLETON );

erzeugt werden.

4. Sprachumschaltung

Das folgende Beispiel zeigt wie in einer Frontcontroller-Action die Sprache der Applikation geändert werden kann.

Die Sprache einer Applikation wird in alle Objekte injiziert, die von APFObject erben. Die Variable $this->language können Sie daher innerhalb Ihrer Komponenten nutzen, um die aktuelle Sprache zu erkennen und ggf. Sprach-abhängige Inhalte ausgeben.

Der folgende Action-Code geht davon aus, dass die Sprache über den URL-Parameter language übergeben werden kann. Die Sprache wird mit Hilfe des gespeichert um die Auswahl des Benutzers für die Zeit des aktuellen Besuchs zu behalten. Ist keine Information vorhanden, wird de als Standardsprache genutzt.

PHP-Code
use APF\core\frontcontroller\AbstractFrontcontrollerAction; use APF\core\http\Session; class ChangeLanguageAction extends AbstractFrontcontrollerAction { public function run() { // set your favourite namespace here $session = new Session('mytools\languagechoose'); // set default language to 'de' $lang = 'de'; // try loading language of URL parameter $langFromUrl = $this->getRequest()->getParameter('language'); if ($langFromUrl !== null) { $lang = $langFromUrl; } // try to load language from session $langFromSession = $session->loadSessionData('language'); if ($langFromSession !== null) { $lang = $langFromSession; } // save chosen language in session and set it in the application $session->saveSessionData('language', $lang); $actions = & $this->getFrontController()->getActions(); foreach ($actions as $hash => $DUMMY) { $actions[$hash]->setLanguage($lang); } $this->getFrontController()->setLanguage($lang); } }

Die letzten Zeilen der Implementierung zeigen, wie Sie die Sprache der bereits erzeuten Komponenten - Actions und der Front-Controller selbst - mit der neuen Sprache versorgt werden können. Wichtig ist in diesem Zusammenhang vor Allem die Bestückung von bereits erzeugten Actions, da diese ggf. Logik enthalten, die auf der aktuellen Sprache der Applikation basieren.

In einer Action können Sie via

PHP-Code
$actions = &$this->getFrontController()->getActions();

auf die Liste der aktuell registrierten Actions zugreifen. Über

PHP-Code
foreach($action as $hash => $DUMMY){ $action[$hash]->setLanguage($lang); }

versorgen Sie diese mit der gewünschten Sprache. Der Front-Controller selber wird über

PHP-Code
$this->getFrontController()->setLanguage($lang);

neu konfiguriert.

Bitte beachten Sie darauf, auch den Front-Controller selbst mit der aktuellen Sprache auszustatten, da dieser den Page-Controller erzeugt und initialisierst.

Eine weitere Implementierung findet sich im Forum.

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.