Best Practise: Routing in CodeIgniter

Routing ist in MVC-Frameworks wie CodeIgniter das Mapping von Serveranfragen auf Controller-Methoden. Eine Serveranfrage ist dabei charakterisiert durch die URL sowie die Anfragemethode (GET, POST, PUT, DELETE).

CodeIgniter bringt ein umfangreiches Routing-Konzept mit. Dieses besteht aus einem einfachen Default-Verhalten (dokumentiert im Zusammenhang mit Controllern: https://codeigniter.com/user_guide/general/controllers.html) sowie einem erweitertem Routing (https://codeigniter.com/user_guide/general/routing.html).

Ich möchte zeigen, dass der erweiterte, explizite Ansatz der bessere ist.

Einfache Beispielanwendung

Um die unterschiedlichen Ansätze zeigen zu können, erstelle ich eine einfache CodeIgniter-Anwendung, die Items verwalten kann. Ein Item soll nur eine einzige Eigenschaft haben, nämlich name.

Einfache Itemverwaltung mit CRUD-Aktionen

Die Anwendung erstelle ich mithilfe von Composer.

Damit ich die Anwendung über http://codeigniter-routing.bjoerne.local aufrufen kann, konfiguriere ich meinen lokalen Apache und füge einen VirtualHost hinzu (httpd-vhosts.conf):

und konfiguriere das Anwendungsverzeichnis (httpd.conf)

Implizites Routing

Die Datenbanktabelle erstelle ich händisch. Der Datenbankzugriff geschieht über ein Item_model. Der Controller Items steuert die Aktionen.

Die Umsetzung halte ich so einfach wie möglich, jedoch soll das Löschen von Items über einen POST-Request erfolgen. Das bedeutet, dass das Löschen nicht über einen einfachen Link erfolgen kann. Stattdessen erstelle ich ein Mini-Formular mit einem Submit-Button, den ich wie einen Link gestalte. Der Grund für die Verwendung eines POST-Request liegt darin, dass GET-Requests keine Daten verändern sollen (Idempotenz-Eigenschaft). GET-Requests sollen ohne Konsequenzen aufrufbar sein, andernfalls könnten Suchmaschinenbots oder Vorschau-Browser-Plugins einen Schaden anrichten.

Aus der bisherigen Umsetzung resultieren die folgenden Methoden:

Alle Methode sind per POST und GET aufrufbar. In dieser Umsetzung müsste im Code gesteuert werden, ob das erlaubt sein soll, damit die Routen nicht wahllos verwendet werden können. Den Methodennamen new_item habe ich gewählt, weil new ein PHP-Keyword ist und als Methodenname nicht erlaubt ist.

Aus dem Methoden leiten sich automatisch die folgenden Routen ab:

  • <host>/items
  • <host>/items/new_item
  • <host>/items/create
  • <host>/items/edit/<id>
  • <host>/items/update/<id>
  • <host>/items/delete/<id>

Schwachpunkte

Das sind leider nicht die URLs, mit der eine moderne Webanwendung aufgerufen werden sollte. Vor allem durch die Verbreitung von REST-APIs hat sich das folgende Muster durchgesetzt:

  • GET /items - Liste der Items
  • GET /items/<id> - Details eines items
  • POST /items - Neues Item erstellen
  • PUT /items/<id> - Item aktualisieren
  • DELETE /items/<id> - Item löschen

Das Prinzip ist, dass eine URL eine Ressource repräsentiert. Der Aufbau ist dabei Hierarchisch. Die Hierarchieebenen sind mit / getrennt. Kürze ich eine URL um einen Teil, z.B. /items statt /items/<id>, gelange ich zum Eltern-Element.

Die Formulare zum Anlegen und Bearbeiten sind dabei Kind-Ressourcen der Item-Liste bzw. des konkreten Items. Hier empfehlen sich die URLs

  • GET /items/new
  • GET /items/<id>/edit

Die oben erwähnten PUT- und DELETE-Methoden werden von Browser-Formularen nicht unterstützt. Ein Lösung ist aber trotzdem möglich. Im folgenden Abschnitt soll es darum gehen, wie ein sauberes Routing mit zeitgemäßen und sicheren URLs in CodeIgniter möglich ist.

Explizites Routing

Wie bereits erwähnt und hier beschrieben, kann das Routing auch explizit definiert werden. Auf die Magie des impliziten Routings verzichtet man dann und muss das Routing selbst definieren. Aber nur so gelingt es, die Routen selbst zu gestalten.

Die Datei application/config/routes.php ist bereits angelegt. Hier definiere ich nun folgende Routen:

Es fällt auf, dass die Route 'items/(:num)' gleich dreimal vorkommt, als GET-, PUT- und DELETE-Request. Das wäre mit dem impliziten Routing nicht möglich.

Die URLs in der Anwendung passe ich entsprechend an.

Unterstützung für PUT- und DELETE-Requests

PUT- und DELETE-Request lassen sich auf HTML-Seiten nur simulieren, da es die Methoden immer noch nicht in die HTML-Spezifikation geschafft haben. Um sie dennoch zu unterstützen, füge ich eins der beiden folgenden hidden-Felder ein, welches ich einem benutzerdefinierten Router behandle.

CodeIgniter unterstützt benutzerdefinierte Frameworkdateien. Um das Routing zu überschreiben lege ich eine Datei application/core/MY_Router.php an. Durch Pfad und das MY_-Präfix weiß CodeIgniter, dass diese Datei das Standard-Routing überschreibt.

Lediglich die Method _parse_routes wird überschrieben und nur bei POST-Requests, die das obige hidden-Feld enthalten, wird der Router aktiv. Dann wird die REQUEST_METHOD auf den Wert des hidden-Feldes gesetzt und kann beim Routing berücksichtigt werden. Nur so können  die Route $route['items/(:num)']['put'] und $route['items/(:num)']['delete'] erreicht werden.

Deaktivierung des impliziten Routing

Im aktuellen Codestand greift das impliziten Routing noch, wenn kein Eintrag unseres Routings passt. Die Detailansicht ist sowohl über items/<id> als auch über items/show/<id> aufrufbar.

Um das zu deaktivieren, benenne ich einfach den Controller um. Statt Items heißt dieser nun Items_controller. Das gefällt mir ohnehin besser. Außerdem passe ich die Mapping in der routes.php an.

Das deaktivieren des Routing kann ich durch die folgenden Zeilen erreichen:

Quellcode

Der Quellcode des Beispielprojekte ist hier verfügbar: https://github.com/bjoerne2/codeigniter-routing-example

2018-01-12T18:11:24+00:00 12.01.2018|Tags: , , |0 Kommentare

Hinterlassen Sie einen Kommentar