Implementierung eines Plugins
Als Vorbemerkung soll noch einmal ausdrücklich darauf hingewiesen werden, dass PHP zumindest in Version 4, die Stud.IP voraussetzt, keine Namensräume unterstützt. Daher müssen Klasse eindeutig benannt werden und alle Funktionen, die für Plugins verwendet werden, sollten in Klassen gekapselt sein.
Vor der Implementierung eines Plugins sollte zunächst bekannt sein, an welchen Stellen im System ein solches Plugin verlinkt sein soll und wer hierauf Zugriff besitzt. Hieraus sollte dann eine Wahl auf einen der drei Typen bzw. Basisklassen? resultieren.
Ein neues Plugin wird dann von der so gewählten Basisklasse abgeleitet.
(:code:)
<?php
class UserAdministrationPlugin extends AbstractStudIPAdministrationPlugin {
function UserAdministrationPlugin(){
parent::AbstractStudIPAdministrationPlugin();
}
}
?>
(:/code:)
Im obigen Beispiel wird von der Klasse AbstractStudIPAdministrationPlugin abgeleitet. Das Plugin erhält dadurch automatisch einige Attribute und Methoden und wird so von der PluginEngine automatisch in den Administrationsbereich von Stud.IP eingebunden. Dies geschieht allerdings erst, wenn dem Plugin auch ein entsprechendes Navigationsobjekt zugewiesen wurde. Die abstrakte Oberklasse verfügt nämlich über kein solches Navigationsobjekt. Dies ist auch bei den übrigen Basisklassen der Fall.
die Verlinkung / die Navigation
Für die Implementierung eines Plugins bedeutet dies, dass der erste Schritt immer das Erzeugen eines Navigationsobjektes ist, welches dem Plugin zugewiesen wird. Dies lässt sich üblicherweise im Rahmen der Initialisierung des Objektes im Konstruktor durchführen, kann aber später zur Laufzeit immer wieder geändert werden.
(:code:)
$nav = new PluginNavigation();
$nav->setDisplayname(_("Verwaltung von Benutzern"));
$this->setNavigation($nav);
$this->setTopNavigation($nav);
(:/code:)
Im Beispiel wird dem Plugin ein Menü mit dem Namen Verwaltung von Benutzern hinzugefügt und zusätzlich eine Top-Level-Navigation mit demselben Namen eingefügt.
Administrationsplugins weisen zusätzlich die Besonderheit auf, dass sie über eine TopNavigation verfügen können, die dazu führt, dass das Plugin auch auf der Startseite des Administrators angezeigt wird.
Systemplugins weisen die Besonderheit auf, dass sie alternativ über überhaupt keine Navigation verfügen können. In diesem Fall sollte dann aber ein BackgroundTask vorhanden sein. D.h. Systemplugins können alternativ ohne Navigation als Hintergrund-Job laufen. Sie werden dann bei jeder Aktualisierung der Seite ausgeführt. Dies eignet sich bspw. um ein Benutzertracking durchzuführen.
Bei Standardplugins kann es zusätzlich eine Subnavigation geben. Dies sind die in Veranstaltungen und Einrichtungen innerhalb von Stud.IP üblichen Bottomkats bzw. Links unterhalb eines Karteireiters.
Icons
Neben der Navigation sollte als nächstes das Icon des Plugins definiert werden. Dieses befindet sich in der Regel innerhalb des Pluginpaketes und wird durch die PluginEngine automatisch in den entsprechenden Menüs bzw. der Titelzeile des Plugins verwendet.
(:code:)
$this->setPluginiconname("img/nutzer.gif");
(:/code:)
Grunddaten
Als nächstes sollte die Methode getPluginname() überschrieben werden, die den Namen des Plugins zurückliefert. Alternativ kann auch direkt der Name des Plugins gesetzt werden. Dieser Name wird bisher nur in der Pluginadministration angezeigt und dient der Verwaltung der Plugins. Eine zukünftige anderweitige Verwendung ist aber möglich. Daher sollte dieser Name immer gesetzt werden.
Aufruf des Plugins durch die PluginEngine
Bevor man nun mit der Implementierung der Logik beginnen kann, sollte man sich einen Überblick davon verschaffen, welche Attribute und Methoden das jeweilige Plugin bereits durch die Plugin-Schnittstelle vorgegeben hat und wie diese durch die Plugin-Engine genutzt werden.
Zunächst einmal benutzt die Plugin-Engine die Informationen aus der Datenbank, um Plugins ins System zu laden. Anschließend wird jedes Plugin nach der Navigation gefragt und dann entsprechend im System verlinkt. Wird nun ein entsprechender Link durch den Nutzer angeklickt, so lädt die Plugin-Engine das angeforderte Plugin und fügt je nach Ausprägung (Standard, System, Administration) des Plugins einen entsprechenden Kopf über dem Plugin-Ausgabebereich ein und ruft dann die show-Methode des Plugins auf. Danach wird die Seite über einen entsprechenden Abschluss beendet.
Der Aufruf des Plugins kann auch über eine andere Methode erfolgen, wenn dies durch das Plugin angefordert wird. Wie dies genau funktioniert, wird an anderer Stelle beschrieben.
Das Plugin sollte also in jedem Fall über eine show-Methode verfügen, da diese der Haupteinstiegspunkt für die Plugin-Engine ist. Innerhalb dieser show-Methode sollte das Plugin den Request verarbeiten und eine Ausgabe liefern. Sinnvoll ist hier auch die Unterscheidung in mehrere Schichten nach dem Model-View-Controller-Modell (MVC).
Das hier als Beispiel verwendete Plugin und auch das PluginAdministrationPlugin benutzen dazu jeweils mindestens drei Klassen:
- UserAdministrationPlugin (Controller)
- UserAdministration (Model)
- UserAdministrationVisualization (View)
Das Beispielplugin führt in seiner show-Funktion keinerlei Unterscheidung aufgrund des eingehenden Requests durch. Statt dessen wird zunächst eine Session-Variable gelöscht und dann nur der View instanziiert und dort die Anzeige eines Suchformulars aufgerufen.
Die Visualisierungsklasse ist von einer abstrakten Oberklasse aus der Plugin-Schnittstelle abgeleitet und benötigt zur Instanziierung eine Referenz auf das aufrufende Plugin. Dies ist für eine spätere Verlinkung zwingend notwendig.
(:code:)
function show(){
unset($_SESSION["ldapresults"]);
$vis = new UserAdministrationVisualization($this);
// Standard-Ansicht zeigen
$vis->showLDAPSearchForm();
}
function importUserFromLDAP(){
// ….
}
function searchLDAP(){
// ….
}
(:/code:)
Weitere Funktionalität des Controllers steckt in den weiteren angedeuteten Methoden. Die Aufteilung in verschiedene Methoden verbessert hier die Übersichtlichkeit und Wartbarkeit des Codes. Statt der Aufteilung in verschiedene Methoden könnte sich auch der gesamte Code zur Kontrolle innerhalb der show-Methode verbergen. Dies wäre jedoch nicht sehr übersichtlicht. Trotzdem kann dies bei einigen Fallunterscheidungen sinnvoll sein.
Wie aber kann nun aus der Visualisierung heraus auf eine der enstprechenden Methoden innerhalb des Plugins zugegriffen werden.
(:code:)
function showLDAPSearchForm($nachname="",$email="",$name="",$fuzzy=false){
StudIPTemplateEngine::makeContentHeadline(_("Suche im LDAP"));
?>
<form method="POST" action="
<?= PluginEngine::getLink($this->pluginref,array(),"searchLDAP")?>">
…
</form>
<?
}
(:/code:)
Zur Erzeugung des Action-Links eines Formulars sehen wir den Aufruf der statischen Methode getLink innerhalb der PluginEngine-Klasse. Die PluginEngine-Klasse stellt einige statische Methoden bereit, die für die Entwicklung von Plugins nötig sind. Genaueres dazu hier?.
Ebenfalls ist im Code-Ausschnitt zu sehen, dass die Klasse StudIPTemplateEngine über statische Funktionen verfügt, die zur Darstellung gedacht sind. Genaueres dazu hier?.
Folgende Methoden müssen für Plugins implementiert werden, die eine Ansicht erzeugen.
- show:
Erzeugt die Ansicht des Plugins
Daneben gibt es weitere Methoden, die optional implementiert werden können.
- initialize:
Wird von der PluginEngine automatisch vor weiteren Aufrufen aufgerufen, sofern das Plugin diese Methode implementiert.
- prepareUninstallation:
Wird von der PluginEngine automatisch unmittelbar vor dem Löschen des Plugins aufgerufen. Das Plugin sollte hierin von ihm angelegte Tabellen etc. löschen.
Ausgangspunkt für eigene Entwicklungen
Als Ausgangspunkt für eigene Entwicklungen können die bereitgestellten Basis-Plugins dienen. Diese erzeugen nur einen Menüeintrag und ansonsten einen leeren Content-Bereich.
Zudem sollten folgende Klassen genauer angesehen werden:
- plugins/engine/PluginEngine.class.php
- plugins/engine/StudIPTemplateEngine.class.php
- plugins/core/AbstractStudIPPlugin.class.php
- plugins/core/AbstractStudIPStandardPlugin.class.php
- plugins/core/AbstractStudIPAdministrationPlugin.class.php
- plugins/core/AbstractStudIPSystemPlugin.class.php