Hello Controller

Quickstart

Controller sind für jedes n2n Modul zentral. Sie nehmen Anfragen entgegen, greifen über Models auf die Datenbank zu und rufen Views auf. Unser erster Schritt ist ein Controller für ein einfaches Hello World!

  1. Controller erstellen
  2. Routing registrieren
  3. Action Methoden
  4. Exkurs Exceptions
  5. Individuelle Pfade für Action-Methoden

Controller erstellen

n2n ist nach dem Model-View-Controller (MVC) Prinzip aufgebaut. Der Controller ist dabei der Teil des Programms, welcher die Aufrufe des Benutzers entgegennimmt und verarbeitet.

In n2n wird für jede Klasse ein eigenes File erstellt. Die Verzeichnisstruktur ist frei wählbar. Wir empfehlen, alle Controller-Klassen eines Moduls im Unterordner {module-namespace}/controller abzulegen.

Erstelle /app/qs/controller/BlogController.php mit diesem Inhalt:

<?php 
namespace qs\controller;

use n2n\web\http\controller\ControllerAdapter;

class BlogController extends ControllerAdapter {
    public function index() {
        echo 'Hello World!';
    }
}

Beachte, dass n2n Namespaces verwendet. Der Namespace für unseren Controller lautet: qs\controller

Ein normaler Controller erbt von der ControllerAdapter Klasse. Diese stellt alle für Controller benötigten Eigenschaften zur Verfügung.

Wenn ein Controller ohne weitere Parameter aufgerufen wird, wird die index() Methode ausgeführt. Um diesen Controller aufrufen zu können, müssen wir für diesen ein Routing registrieren.

Routing registrieren

Für jeden Controller kann ein Routing registriert werden. Wird der im Routing registrierte Pfad vom Besucher aufgerufen, ruft der ControllingPlan von n2n den vermerkten Controller auf.

Applikations- und Modulkonfiguration

Jede n2n-Applikation verfügt über eine app.ini. Diese liegt im /var/etc Verzeichnis:

/var/etc/app.ini

In dieser app.ini werden die wichtigsten Konfigurationen der Applikation gesetzt. Jedes Modul kann diese Konfigurationen über eine eigene app.ini ergänzen. Jede n2n Applikation verfügt also über die generelle app.ini und die app.ini ihrer Module.

In den app.ini-Dateien werden sämtliche Konfigurationswerte der Applikation gespeichert, welche zur Laufzeit nicht geändert werden.

Erstellen wir also für unser Modul eine eigene app.ini. Erzeuge dafür das folgende File:

/var/etc/qs/app.ini

Das neue File soll folgenden Inhalt haben:

[routing]
controllers[/blog] = "qs\controller\BlogController"

Mit [routing] geben wir an, dass mit den nachfolgenden Konfigurationswerten Controller-Routings registriert werden. Über controllers werden die Pfade registriert. Der registrierte Pfad (/blog) befindet sich in der eckigen Klammer. Ausformuliert heisst der oben eingetragene Konfigurationswert folgendes: „Jeder Request auf /blog soll an den BlogController delegiert werden“. Zu beachten: im app.ini muss die Controller Klasse mit dem vollständigen Namespace vermerkt sein!

Wenn du einen Blick in die app.ini der Applikation wirfst, wirst du feststellen, dass es auch da die Gruppe [routing] gibt. Der Context Pfad für unseren Controller könnte genauso gut in der app.ini der Applikation gesetzt werden. Wir empfehlen, Konfigurationswerte, welche sich nur auf ein Modul beziehen, in der app.ini des Modules zu speichern. Es ist auch vorstellbar, dass die app.ini der Applikation und die app.ini des Modules Werte enthalten, welche im Konflikt zueinander stehen.

Wenn die app.ini der Applikation und die app.ini eines Modules in Konflikt stehen, wird der Wert der app.ini der Applikation berücksichtigt.

Nach dem Abspeichern unserer app.ini, kann der von uns programmierte Controller jetzt wie folgt aufgerufen werden

http://localhost/[pfad-zum-public-folder-des-projektes]/blog (Bspw. http://localhost/quickstart/public/blog)

Wenn alles korrekt funktioniert, siehst du unter der oben angezeigten URL jetzt „Hello World!“ in deinem Browser.

Wenn es nicht klappt, rufe http://localhost/[pfad-zum-public-folder-des-projektes]/blog1 auf. Unter diesem Pfad ist qs1\controller\BlogController registriert.

Action Methoden

Jetzt ergänzen wir unseren Controller um die Methoden doDetail() und doThanks():

<?php
namespace qs\controller;

use n2n\web\http\controller\ControllerAdapter;

class BlogController extends ControllerAdapter {
    public function index() {
        echo 'Hello World!';
    }

    public function doDetail(int $id) {
        echo 'Detail: ' . $id;
    }

    public function doThanks() {
        echo 'Thanks';
    }
}

Jede öffentliche Methode (public) auf einem Controller, welche mit do beginnt, nennen wir Action-Methode. Action-Methoden können über Ihren Namen (ohne "do") aufgerufen werden. Um den Effekt zu sehen, rufe in deinem Browser folgende URL auf:

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/thanks

Probiere gleiches für die Action-Methode doDetail():

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/detail

Wenn alles korrekt funktioniert, kriegst du auf den oben gegebenen Pfad eine 404-Fehlermeldung! Der Grund dafür ist der $id Parameter der Action-Methode! Die Action-Methode doDetail() erwartet zwingend die Angabe einer ID! Versuche es mal mit:

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/detail/1

Wir stellen fest, dass die 1 aus dem Pfad als $id der Methode übergeben wird. Würde die Action-Methode für den Parameter $id auch NULL erlauben (int $id = null), würde n2n die Action-Methode doDetail() auch ohne Angabe des ID Parameters aufrufen. Wie du siehst, füllt n2n zusätzliche Pfade in die Parameter der Action-Methode ab.

Action-Methoden müssen public sein und mit do beginnen.

Um dies zu verfizieren, kannst du folgende Methode einbauen und aufrufen:

    public function noDo() {
        echo 'ohne do im Voraus, funktionierts nicht';
    }

Diese Methode kann weder mit:

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/noDo

noch mit

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/do

aufgerufen werden. Da die Methode noDo() nicht mit do beginnt, geht n2n davon aus, dass diese Methode nicht von extern aufgerufen werden darf. n2n antwortet mit einer 404 Fehlermeldungen, weil es auf dem BlogController keine passenden Action-Methoden findet. 

Jetzt probieren wir noch folgende private Methode:

    private function doStuff() {
        echo 'Private Methoden können nicht aufgerufen werden';
    }

Wenn du diese Methode über den folgenden Pfad aufzurufen versuchst, passiert etwas Neues:

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/stuff

n2n wirft eine Exception! Höchste Zeit also Exceptions kennen zu lernen!

Exkurs Exceptions

Exceptions sind im Konzept von n2n ganz wichtig! Bei der Entwicklung von n2n war es uns ein zentrales Anliegen, genaue Fehlermeldungen zurückzugeben. Sie sollen dem Entwickler genaue Anweisungen zur Fehlerquelle geben.

Exceptions werden nur ausgegeben, wenn das System als Testsystem registriert ist. n2n erkennt ein Testsystem am Wert SetEnv N2N_STAGE development im File public/.htaccess. Exceptions dürfen auf produktiven Systemen nicht ausgegeben werden, weil sie viele Details zum System preisgeben. Auf Produktivsystemen wird eine Exception geloggt und via E-Mail an den zuständigen Entwickler verschickt. Sämtliche Eigenschaften des Exception Handlings können im app.ini in der Gruppe [error] verwaltet werden.

In unserem Falle, weist uns die Exception darauf hin, dass doStuff() public gesetzt werden muss. Ändere dies und kontrolliere, ob es danach passt! Wenn du’s richtig gemacht hast, konnte dir die Exception bereits ein erstes Mal helfen, einen Fehler schnell und einfach zu beheben!

Individuelle Pfade für Action-Methoden

Die bisher gezeigte Variante Pfade zu setzen ist zwar einfach, aber nicht sehr flexibel. Darum können in n2n URL-Pfade für Action-Methoden auch über Annotationen definiert werden. Annotationen sind Möglichkeiten, Klassen, Eigenschaften und Methoden beschreibende Informationen mitzugeben. Leider unterstützt PHP - im Gegensatz zu Java - Annotationen offiziell nicht. Andere PHP-Frameworks behelfen sich damit, Annotationen über Kommentare zu erfassen. Wir finden diesen Ansatz nicht befriedigend, da zum Beispiel Autovervollständigung in Kommentaren nicht gewährleistet ist. In n2n werden Annotationen darum über eine eigene Methode erfasst. Das folgende Beispiel zeigt, wie sich für die Action-Methode detail() ein eigener Controller-Pfad annotieren lässt.

<?php
namespace qs\controller;
 
use n2n\reflection\annotation\AnnoInit;
use n2n\web\http\controller\ControllerAdapter;
use n2n\web\http\annotation\AnnoPath;
 
class BlogController extends ControllerAdapter {
    private static function _annos(AnnoInit $ai) {
        $ai->m('detail', new AnnoPath('/urlPart:*'));
    }
     
    public function index() {
        echo 'Hello World!';
    }
     
    public function detail(string $urlPart) {
        echo 'Detail: ' . $urlPart;
    }
     
    public function doThanks() {
        echo 'Vielen Dank für deinen Kommentar.';
    }
     
}
In n2n werden sämtliche Annotationen immer über eine private, statische Klasse _annos() definiert! Damit diese Methode gut ersichtlich ist, setzen wir diese in jeder Klasse an erste Stelle vor sämtlichen Eigenschaften und anderen Methoden. Dieser Methode wird immer ein AnnoInit übergeben. Über dieses Objekt kannst du die Klasse selbst ($ai->c()), ihre Methoden ($ai->m()) und Eigenschaften ($ai->p()) annotieren. Sämtliche Annotationsklassen, die in n2n zur Verfügung stehen, beginnen mit Anno.

Das oben gezeigte Code-Beispiel annotiert für die detail() Methode (->m()) einen Pfad (AnnoPath()), der nach dem Muster * generiert wird und dem Parameter urlPart übergeben wird. Eine Methode, welcher über eine Annotation ein Pfad zugewiesen wird, muss nicht mehr mit do beginnen! Auf das do zu verzichten macht sogar Sinn, damit nicht zwei unterschiedliche Pfade existieren, über welche die Methode aufgerufen werden kann!

Das * bewirkt, dass beliebige Zeichen mitgegeben werden können. Diese werden der Methode detail() als $urlPart übergeben. Am besten probierst du's gleich aus:

http://localhost/[pfad-zum-public-folder-des-projektes]/blog/hier-steht-irgendwas

Ändere den letzten Teil des URL Parts beliebig. Das einzige was du nicht einfügen kannst, ist ein weiterer /.

Anstelle von * könnte auch ein regulärer Ausdruck stehen, welcher genauer definiert, wie der Pfad gebildet werden soll. Probiere folgende Beispiele:

AnnoPath() Beispiel für den Aufruf
'/urlPart:*' http://localhost/[pfad-zum-public-folder-des-projektes]/blog/irgendwas
'lese/urlPart:#[0-9]+#' http://localhost/[pfad-zum-public-folder-des-projektes]/blog/lese/999

Achtung: reguläre Ausdrücke müssen mit dem Raute-Symbol (#) hinten und vorne begrenzt werden. Davon abgesehen, kann die bekannte Notation von regulären Ausdrücken verwendet werden.

Vielleicht ist dir aufgefallen, dass mit dem * Pattern ein Konflikt zwischen der detail() und doThanks() Methode besteht. Der Pfad /thanks passt sowohl für die detail() Methode als auch zur doThanks() Methode. Dies verdeutlicht, dass die Definition der Controller-Pfade sorgfältig gemacht werden muss, um zu verhindern, dass mehrdeutige Pfade existieren. Im vorliegenden Falle prüft n2n zuerst, ob für den Pfad nicht annotierte Action-Methoden zur Verfügung stellen. Zweite Priorität haben annotierte Action-Methoden. Der Pfad /thanks führt also in die Methode doThanks().

Dank der hier gezeigten Möglichkeit, Controller-Pfade nach beliebigen Mustern zu annotieren, erlaubt dir n2n die volle Kontrolle über die URL-Strukturen deiner Applikation!
Im Modul qs1 findest du die Lösung, wie dein Code momentan ausschauen sollte. Nur die Namespaces unterscheiden sich im Modul qs1. Du kannst den qs1\controller\BlogController über folgenden Pfad aufrufen: http://localhost/[pfad-zum-public-folder-des-projektes]/blog1
« Quickstart n2n Views & Templates »

comments_title

post_login_to_create

questions_title