13.5. Konzepte zur Anwendungsentwicklung

In diesem Abschnitt werden die Konzepte erläutert die wesentlich für das entwickeln von Anwendungen sind.

13.5.1. Request Handler

Die Funktionalität einer Anwendung wird von Request Handlern bereitgestellt. Diese bearbeiten einen Request und sammeln alle benötigten Daten für die Response. Die UML Definition der Request Handler ist in Abbildung Figure 13-9 dargestellt.

Figure 13-9. UML Modell der Request Handler

Die Abarbeitung wird durch die Methode handle initiiert die durch den übermittelten Parameter Zugriff auf Kontext-Informationen des aktuellen Requests hat. Der Rückgabewert der Methode ist ein Datentransferobjekt oder der boolsche Wert true. Der Wert true impliziert das die Antwort bereits generiert wurde wodurch das Rendering nicht durchgeführt wird.

Die Standardimplementierung RequestHandlerBase bietet nützliche Funktionen u.a. zur Erstellung von Links / URLs.

Neben der Standardimplementierung gibt es eine weitere Implementierung welche den Controller des MVC-Konzepts realisiert. Dieser bildet eine zentrale Stelle zur Implementierung der CRUD-Funktionalität und verfügt über nützliche Methoden für Redirects und Link-Erstellung. Alle Aktionen (wie create, edit, retrieve, ...) des Controllers sind über die Assoziation zur Klasse Action modelliert und somit erweiterbar.

13.5.2. Datentransferobjekte

Die Daten für die Response werden in Datenobjekten verpackt die als Container dienen. Dieses Konzept findet sich in den Pattern Value Object oder Data Transfer Object wieder. Das UML Klassenmodell für die Datentransferobjekte ist in Abbildung Figure 13-10 zu sehen.

Figure 13-10. UML Modell der Datentransferobjekte

Jedes Datentransferobjekt kennt seinen View durch den es dargestellt wird. Die Standardimplementierung erbt von der PHP Klasse ArrayObject wodurch auf einfache Weise Daten gespeichert werden können.

13.5.3. Rendering

Die Aufgabe des Rending ist es die Daten die Request Handler zusammentragen in geeigneter Form zu rendern. Das UML Modell des Rendering ist in Abbildung Figure 13-11 dargestellt.

Figure 13-11. UML Modell des Rendering

Es fällt auf das vom metaframework keine Standardimplementierung bereitgestellt wird da das Rendering optional ist. In den metaframework Plug-Ins gibt es eine Implementierung auf Basis der Smarty Template Engine.

13.5.4. Interceptors

Für Aufgaben wie die Authentifizierung und Autorisierung die sich über weite Bereiche einer Anwendung erstrecken sind Request Handler nur bedingt geeignet da in jedem Request Handler die Berechtigungen geprüft werden müssten. Für solche Aufgaben gibt es die Interceptoren welche einen Request abfangen und entscheiden können, wie dieser fortgesetzt werden soll. Die Definition in UML ist in Abbildung Figure 13-12 zu sehen.

Figure 13-12. UML Modell der Interceptoren

Für Interceptoren wird eine Schnittstelle mit einer Methode vorgegeben. Diese hat über den Parameter handlerInfo Zugriff auf Kontext-Informationen zum Request und muss einen boolschen Wert zurückgeben der angibt ob der Request abgefangen wurde oder nicht. Der Wert true bedeutet das der Request abgefangen wurde und die Response vom Interceptor erzeugt wird. Bei false wird das Request Processing wie gehabt durchgeführt.

13.5.5. Extensions und Contributions

Ein Problem von modularen Anwendungen kann eine Abhängigkeit zwischen Modulen oder hier Plug-Ins sein. Beispielsweise betrifft dies das Menü. Auf die Funktionalität einiger Plug-Ins soll durch Menü-Einträge direkt zugegriffen werden können. Sind die Plug-Ins aber nicht registriert (vorhanden), so sollen diese Menü-Einträge nicht erscheinen. Solch ein indirekter Informationsaustausch ist über das Extension-Contribution Konzept realisierbar (welches von Eclipse Extension Points inspiriert wurde).

Im Gegensatz zu den anderen Konzepten gibt es hier kein UML Modell - die einzige Definition ist die Extension Registry in Abbildung Figure 13-6 . Mit der Plug-In Schnittstelle können Plug-Ins beliebige Contributions für Extensions bereitstellen:

public function getExtensions() {
    return array(
        'de.example.navigation.simple' => array('name' => 'Datenmodell', 'link' => '/ddm', 'image' => 'images/ddm.png'), 
        'de.example.navigation.complex' => new Menu_MenuBar(array(
            new Menu_Menu('class', '/class', array(
                new Menu_MenuItem('create new', '/class/create'),
                new Menu_MenuItem('list', '/class/list')
            )),
            ...
            ))
    );
}

Im Beispiel ist die Contribution eines Arrays auf die Extension de.example.navigation.simple sowie eine Objektstruktur auf de.example.navigation.complex zu sehen. Wie der Name der Extension vermuten lässt handelt es sich beide male um Navigationseinträge für das Menü. Der letztere wird bei einer komplexen Menüdarstellung genutzt, der erste bei einem einfachen Menü. Die Contributions aller Plug-Ins werden durch die Extension Registry zusammengefügt.

Der Zugriff auf die Extension Registry ist über die Service Registry während des Request Processing jederzeit aus möglich. So können die Contributions für bestimmte Extensions abgefragt und genutzt werden:

$extensionRegistry = $this->serviceRegistry->getComponent('extensionRegistry');
$contributions = array();
if ($extensionRegistry->hasContributions('de.example.navigation.simple')) {
    $contributions = $extensionRegistry->getContributions('de.example.navigation.simple');
}

Dabei ist es Aufgabe des Entwicklers sicherzustellen, das die Contributions von einem Datentyp sind, mit dem die zugreifende Logik etwas anfangen kann.