Biphrost: Dispatcher
Der Dispatcher wurde, wie der Name bereits suggeriert, zum Abfertigen von Anfragen entworfen. Dazu benötigt er den Einstiegspunkt-Algorithmus, der in einer iterativen Variante implementiert wurde und somit verständlicher ist als die rekursive Variante und sich in der Methode findEntrance befindet:
$components = ($uri == '/' ? array('index') : array_filter(explode('/', $uri)));
$dir = $this->base;
foreach($components as $i => $component)
{
if(($component = strtolower($component)) == '..') return false;
$file = $dir . $component . '.php';
$dir .= $component . '/';
if(file_exists($file)) { $result = $file; $offset = $i+1; }
if(!file_exists($dir) || !is_dir($dir)) break;
}
return (isset($result) ? array($file, array_slice($components, $offset)) : false);
Die Membervariable base enthält den Pfad, in dem sich die Einstiegspunkte befinden und wird immer mit einem Slash abgeschlossen. Um den Einstiegspunkt zu ermitteln ist ein URI erforderlich, der in der Variable $uri enthalten ist und anschließend in seine Komponenten zerlegt wird. Bei einem / als URI wird angenommen, dass /index gemeint ist. In jedem Fall existieren keine leeren Komponenten (sichergestellt durch array_filter). Anschließend beginnt der eigentliche iterative Algorithmus, der erst abbricht, wenn man keinen tieferen Ordner mehr betreten kann:
- Die aktuelle Komponente wird durch ein Pendant in Kleinbuchstaben ersetzt.
- Sollte ein ".." im URI übergeben worden sein, darf kein Einstiegspunkt gewählt werden, da wir aus Sicherheitsgründen vermeiden wollen, dass man höher gelegene Ordner betreten kann.
- Datei- und Ordnername werden zusammengesetzt.
- Existiert eine Datei mit dem generierten Namen, wird er in $result gespeichert und die Position der Komponente wird bestimmt, damit die Argumente extrahiert werden können.
Wenn ein Einstiegspunkt gefunden wurde, wird er im korrekten Format zurückgegeben. Andernfalls wird false zurückgegeben.
Diese Methode ist öffentlich, damit jeder, der Zugriff auf das
Dispatcher-Objekt hat, herausfinden kann, welcher Einstiegspunkt zu
einem übergebenen URI gehört. Dies ist vor allem relevant für
Rechtesysteme, die vorher bereits abfragen, ob es erlaubt ist, einen
Einstiegspunkt zu betreten. Die Methode dispatch
nutzt den Einstiegspunkt-Algorithmus zum Finden des Einstiegspunkt und
führt den Einstiegspunkt ggf. aus und setzt in dem Fall ein Flag, das
angibt, dass die Anfrage abgefertigt wurde.
Ein Prinzip von Bifrost ist es, dem Entwickler möglichst
freie Hand zu lassen ("Da wir nicht jeden Entwickler glücklichen machen
können, machen wir wenigstens keinen unglücklich."), weshalb im
Dispatcher bewusst auf Fehlerbehandlungsroutinen verzichtet wurde. Bei
einem nicht-existenten Einstiegspunkt wird statt einer Fehlerseite das
Transfer-Objekt nicht abgefertigt, was sich leicht mittels wasDispatched
(auf dem Transfer-Objekt) abfragen lässt. Die Bootstrap-Datei eignet
sich für solche Szenarien hervorragend. Ein anderer wichtiger Aspekt
ist die Isolation von der Außenwelt: Alle Daten der Außenwelt, die für
das Abfertigen einer Anfrage notwendig sind, werden als Parameter (der
URI) oder über das Transfer-Objekt übergeben. Somit lässt sich der
Dispatcher auch auf andere Anwendungsfälle übertragen, z.B. für
Template-Engines. Weiterhin kann man davon ausgehen, dass man immer ein
anderes Transfer-Objekt zurückbekommt als man übergibt, was durch
Klonen der Transfer-Objekte realisiert wird. Dies trägt zu einem System
der geringsten Überraschung
bei, da Transfer-Objekte nicht über unauffindbare Referenzen verändert
werden können. Somit ist es auch möglich, Anfragen an mehrere URIs mit
dem gleichen Objekt (nicht demselben!) vorzunehmen oder einen
Einstiegspunkt transparent innerhalb eines anderen Einstiegspunkt
auszuführen. Möchte man jedoch Daten von einer Anfrage zur nächsten
übernehmen, muss man den Mechanismus dafür selbst implementieren, was
aufgrund des Transfer-Konzepts kein Problem darstellen sollte.