Rolf b: Route strings zu Klassen Konstruktor

Beitrag lesen

Ich würde mich hier an das Prinzip "Convention before Configuration" halten. Sprich: Wenn Du in der Route einen Controller "Haschmich" findest, würde ich zwingend eine Klasse "Haschmich" oder "HaschmichController" instanziieren. Diese Klasse kann ggf. in dem einen oder anderen Namespace zu finden sein (die müsstest Du durchsuchen und dafür müsstest Du ggf. eine Liste erlaubter Controller-Namespaces führen).

In PHP müsste diese Logik auch irgendwie mit dem Class-Loader zusammenarbeiten, d.h. du bräuchtest im Classloader eine Funktion "Gibt's diese Klasse" statt blindlings einen new $controllerWithNamespace zu machen und dann ins Errorhandling zu rasseln.

Den Namen der Methode (oder Action) würde ich bei der Klassenkonstruktion außen vor lassen. Statt dessen würde ich dynamisch eine Methode aufrufen, die der Action entspricht.

In JavaScript/Typescript müssest Du Dir ebenfalls Gedanken zum Namespace machen; da weiß ich nicht wie Typescript funktioniert. Aber auch da würde ich den Namen der Action nicht an den Konstruktor geben, sondern prüfen, ob das Controller-Objekt ein Property mit dem Namen der Action hat und ob es eine Funktion ist. Wenn ja, ruf sie auf.

Als weitere Sicherheitsebene kannst Du noch festlegen, dass der Name einer Methode, die eine Action implementiert, mit dem Wort "Action" beginnen oder enden muss. Dieses "Action" fügst Du dem Action-Namen aus dem Routing hinzu. Damit stellst Du sicher, dass NUR Actions über das Routing aufgerufen werden können. Ähnliches kannst Du mit den Controllern machen, du legst die Namespaces fest in denen Controller stehen dürfen und definierst für Dich, in diesen Namespaces NUR Controller unterzubringen. Und Du kannst zwingend ein "Controller" an den Controllernamen anhängen. Viele Möglichkeiten :)

Wenn Du es unbedingt konfigurativ lösen willst, würde ich nicht Arrays durchsuchen. Sowohl PHP als auch Javascript kennen assoziative Arrays, d.h. wenn Du einen Controller Haschmich mit den Actions Schnapp und Fang haben willst, könntest Du es in Typescript so konfigurieren:

var controllerMap = { 
   Haschmich: {
      Schnapp: { controller: HaschmichController, method: 'schnappAction' },
      Fang:    { controller: HaschmichController, method: 'fangAction' }
   }
}

In PHP geht das ähnlich:

$controllerMap = ARRAY('Haschmich' => 
    ARRAY('Schnapp' => new RouteHandler('HaschmichController', 'schnappAction'),
          'Fang'    => new RouteHandler('FangController', 'fangAction')));

Und dann kannst Du es in Javascript so aufrufen (minimale Existenzprüfungen, kein Errorhandling):

routeHandler = (controllerMap[controllerName] && controllerMap[controllerName][actionName]);
if (routeHandler && routeHandler.controller && typeof routeHandler.controller === "function") {
   let controller = new routeHandler.controller();
   if (typeof controller[routeHandler.method] === "function")
      controller[routeHandler.method](routeParameters);
}

PHP ist ähnlich, da musst Du mit isset arbeiten.

Eine konfigurative Lösung hat den Nachteil, dass Du pro Web-Request nur eine einzige Route verarbeiten wirst, aber die Steuertabelle für alle aufbauen musst. Das kostet Zeit (und es kostet noch mehr Zeit, lieber pl, das aus einer Datei einzulesen). Die Konventionslösung hat den Vorteil, dass Du bei korrekt existierenden Controllerklassen und Actionmethoden zwei schnelle Dictionary-Zugriffe hast und dann am Ziel bist.

Wenn Du allerdings die Möglichkeit hast, die Steuertabelle nur einmal aufzubauen und dann requestübergreifend zu speichern, relativiert sich dieser Nachteil.

Rolf