Erweiterung bestehender Funktionen

1. Einführung

In der täglichen Arbeit tritt häufig die Situation auf, dass eine bestehende Bibliothek die bisherigen Anforderungen erfüllt hat, der aktuell zu lösende Spezialfall jedoch nicht. Viele Entwickler neigen in der geschilderten Situation dazu, die Funktion für den aktuellen Anwendungsfall neu zu implementieren. Andere wiederum versuchen krampfhaft eine Bibliothek zu suchen, die diesen Spezialfall abdeckt. Diese Möglichkeiten führt zwar sicher zum Ziel, verringern jedoch entweder die Wartbarkeit, da weitere externe Bibliotheken eingebunden oder gar beliebig kombiniert werden, und erhöhen dabei gleichzeit die Fehleranfälligkeit. Darüber hinaus sollte sich jeder bewusst sein, dass eine API-Änderung automatisch bedeutet, sich vom Update-Pfad der eingesetzten Bibliothek zu entfernen, da in einer Version eingefügte Quick-Hacks womöglich in einer neueren Version nicht mehr funktionieren.

Dieses Tutorial möchte daher eine Methode aufzeigen, wie bestehende Funktionen ohne Anpassung an der verwendeten Biblothek für den eigenen Bedarf "angepasst" und genutzt werden können. Das Tutorial geht dabei davon aus, dass die behandelten Bibliotheken bzw. Module kein eigener Code ist, da diese Methode sonst keinen Sinn macht.

Mancher Leser wird zurecht anmerken, dass eine Anpassung einer Bibliothek bedeutet, dass die Signatur - die API der Bibliothek, oder des Moduls - nicht allgemeingültig genug ausgelegt ist. In vielen Fällen muss ich dem Leser Recht geben, es gibt jedoch erfahrungsgemäß relativ viele API-Definitionen, die nicht für exakt jeden Anwendungsfall mit genau einer Methode verwendbar sind.

2. Beispiel einer TagLib

Das folgende Beispiel soll an Hand des im Release des Frameworks enthaltenen Moduls socialbookmark zeigen, wie eine vorhandene Bibliothek für den eigenen Gebrauch erweitert werden kann.

2.1. Aufgabenstellung

Die im apf-codepack-* enthaltenen Bibliotheken des Moduls, sehen die Möglichkeit vor, dieses per XML-Tag in den Inhaltsbereich einzubinden. Dazu enthält das Modul eine TagLib, deren Eigenschaften unter Socialbookmarking, Kapitel 5, beschrieben werden. Die Tagdefinition sieht dabei vor, dass ein Titel der aktuellen Seiten, der beim Bookmarkservice als Linktitel verwendet wird, als Tag-Attribut übergeben werden kann. Da die Definition jedoch statisch ist, ist es zunächst nicht möglich einen dynamischen Titel an die TagLib zu übergeben. Gerade in einer CMS-Seite, in der der Titel abhängig der anzuzeigenden Seite dynamisch variiert, ist das problematisch!

2.2. Analyse der bestehenden API

Um die aktuell mögliche Funktion zu analysieren, muss sich der Entwickler die Frage stellen: Was ist schon möglich und was fehlt wirklich? Im Fall des Socialbookmarking-Moduls ist die Antwort denkbar einfach: statisches Anzeigen der Bookmark-Icons ist möglich, dynamische Titel nicht!

2.3. Erweiterung der API durch Wrapping

Ein sehr beliebtes Mittel ist Wrapping. Wrapping in der Programmierung bedeutet, eine weitere Schicht um eine Bibliothek - oder hier eine Taglib - zu legen und dadurch die Funktionalität ohne Veränderung der eingesetzten Komponente zu erweitern.

Betrachten wir zunächst die Funktionalität der bisherigen TagLib-Klasse. Diese implementiert eine transform()-Methode, die die Tag-Eigenschaften an den socialbookmarkManager übergibt und diesen für die Ausgabe der Bookmarking-Elemente verwendet. Der Quellcode der Klasse (im apf-codepack-* zu finden unter apps/modules/socialbookmark/pres/taglib) wird im folgenden Kasten dargestellt (Kommentare wurden gekürzt):

PHP-Code
namespace APF\modules\socialbookmark\pres\taglib; use APF\core\pagecontroller\Document; use APF\modules\socialbookmark\biz\SocialBookmarkBarManager; class SocialBookmarkBarTag extends Document { public function __construct() { $this->setAttribute('width', '20'); $this->setAttribute('height', '20'); $this->setAttribute('title', null); $this->setAttribute('url', null); } public function transform() { $bm = & $this->getServiceObject('APF\modules\socialbookmark\biz\SocialBookmarkBarManager'); /* @var $bm SocialBookmarkBarManager */ $bm->setImageWidth($this->getAttributes('width')); $bm->setImageHeight($this->getAttributes('height')); $bm->setUrl($this->getAttribute('url')); $bm->setTitle($this->getAttribute('title')); return $bm->getBookmarkCode(); } }

Um den Titel der aktuell angezeigten Seite dynamisch zu gestalten, ist es nun ratsam, eine weitere TagLib zu definieren, die ausschließlich die neue Funktionalität beinhaltet, jedoch Gebrauch der bereits bestehenden Funktion macht. Um ein konkretes Beispiel aufzeigen zu können, soll der neu zu erstellende Tag my:bookmark genannt werden. Diese beinhaltet dann folgenden Quellcode:

PHP-Code
namespace VENDOR\socialbookmark\pres\tags; use APF\modules\socialbookmark\pres\taglib\SocialBookmarkBarTag; class MyBookmarkTag extends SocialBookmarkBarTag { public function transform() { // Beziehen des aktuellen Titels $title = ...; // Title in Tag-Attribut einsetzen $this->setAttributes('title', $title); // Ausgabe mit Hilfe der Eltern-Methode transform() erzeugen return parent::transform(); } }

In der Methode transform() wird dabei lediglich der Titel der Seite je nach Anwendungsfall erzeugt und dem dafür vorgesehenen Attribut übergeben. Die eigentliche Erzeugung der Ausgabe wird der bisherigen TagLib-Methode überlassen. Durch diese Änderung bleibt es weiterhin möglich, dem Tag die Attribute

  • width
  • height
  • target

mitzugeben, ohne das Verhalten nochmals in der neuen Klasse implementieren zu müssen. Das Einbinden der erweiterten TagLib funktioniert dann wie gewohnt mit

APF-Template
<core:addtaglib class="VENDOR\socialbookmark\pres\tags\MyBookmarkTag" prefix="my" name="bookmark" /> <my:bookmark width="16" height="16" />

Details zur Implementierung von Tags können unter Implementierung von Tags nachgelesen werden.

2.4. Umgang mit Updates

Sollte die verwendete Bibliothek zukünftig eine andere API unterstützen, beschränkt sich die Anpassung lediglich auf das Füllen des Attributes title, da der interne Ablauf der Methode transform() unberührt bleibt. Weiterer Vorteil ist, dass die API der Wrapper-Klasse konstant bleibt und keine Anpassung im Gesamtsystem zur Einbindung des Moduls vorgenommen werden muss. Das in diesem Tutorial aufgezeigte Beispiel hat sich zwar "nur" auf die Erweiterung einer TagLib beschränkt, das Prinzip ist jedoch auf andere Bereiche anwendbar.

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.