Eingabefehler, Parameter sind hier nicht erlaubt!

An der Spitze steht die Basisklasse main und für jeden Request wird eine Subklasse gebildet

Eingabefehler

Parameter sind hier nicht erlaubt!

Ein einziges CGI-Script ist das ganze Framework

Das Herzstück ist die package main. Es ist in meinem Perl-Framework die einzige Datei, die ausführbar gemacht werden muss für die Betriebsmodi mod_cgi, fast_cgi. Für dem Modus mod_perl wird der Code der main-Class als Modul beim Start des Webservers Apache geladen.

Package main lädt die Konfiguration und stellt anhand des Request-URI fest, welche Subklasse für den requested URL geladen werden muss. Ist der Request-URI nicht konfiguriert, wird das Request/Response-Objekt (RRO) als Instanz der Klasse NotFound erstellt. Ansonsten ist RRO eine Instanz der für den Request-URI konfigurierten Subklasse.

Das Request/Response-Objekt RRO ist nun allein zuständig für die Entgegennahme aller Request-Parameter einschließlich bestimmter Request-Header und die Erstellung der Response. In seiner Subklasse, welche von der main-Class erbt, definiert RRO alle Methoden die es zur Verarbeitung von Daten der Eingaben und Bereitstellung der Daten für die Ausgabe braucht.

Framework Interface und Klassenbindung

Attributes

Der Screenshot zeigt die aktuelle Datei im Editor, gut zu sehen, wo und wie die Attribute eingetragen sind. Das View und das Datenmodell wird über die Attribute und die gebundene Subklasse bestimmt. Die Bindung einer Subklasse an den Request URL ist für das Framework charakteristisch.

Über ein Attribut interface= (nicht im Bild) ist es möglich, dem URL ein komplettes Interface zuzuweisen, welches bestimmte Methoden definieren kann. Infolge der Zuweisung eines Interface kann die jeweilige zum URL gehörige Seite interaktiv werden, beispielsweise zum Verarbeiten von Benutzereingaben in Formularen sowie anderweitiger Request-Parameter. Des Weiteren ermöglicht ein zum URL konfiguriertes Interface den Einbau von Platzhaltern zum Laden dynamischer Inhalte.

Ein zum URL konfiguriertes Interface ermöglicht AJAX und schließlich auch, dass sich hinter einem URL ein Webservice wie SOAP, REST usw. verbergen kann.

Die Alternative zu einem per Konfiguration (Attribut) zugewiesenem Interface ist die dedizierte Subklasse. Andererseits ist es per Konfiguration möglich, verschiedenen URLs, die einer Subklasse angehören, auch verschiedene Interfaces zuzuweisen. Ein zum URL konfiguriertes Interface erweitert sozusagen die das Modell bestimmende Klasse über den an die Klasse gebundenen URL.

Das Erbe der Klasse main

Inherit

Das bildlich dargestellte Beispiel verdeutlicht sowohl die Klassenbindung als auch die Vererbung: Klasse Foo erbt von Klasse main und der URL /foo.html ist an die Klasse Foo gebunden.

Eine der vererbten Methoden ist die Interface-Methode data(), sie bestimmt die Herkunft des HTML <body>. Bei einer dedizierten Klasse (Kompaktklasse) ist im Default der BODY unterhalb des __DATA__ Token notiert. Bei dieser Verwendung wird der BODY automatisch geladen ohne dass eine eigene data()-Methode definiert werden muss.

Im Regelfall ist der BODY ein Template, was mit Platzhaltern bestückt werden kann und wird vor dem Ausliefern einer vollständigen HTTP-Response gerendert. Selbstverständlich kann die Subklasse auch eine andere Herkunft des Templates definieren, das kann MySQL genausogut sein, wie eine Datei.

Für Remote Call Procedure​s und Webservice​s, sowie AJAX wird in der Regel kein HTML ausgeliefert. Statt eines HTML-<body> erstellt das Framework Inhalte mit beliebigen Content-Type und stellt beim Senden der Inhalte den entsprechenden Content-Type​-​Response-Header voran.

In Subklasse Foo nun, werden die weiteren Methoden des Interface definiert. Diese Methoden, untenstehend namentlich genannt, müssen nicht definiert sein, sie können. Das heißt, sie werden nur aufgerufen, wenn sie definiert sind:

  1. init()
  2. browse()
  3. control()
  4. putcontrol()
  5. trailer()

Wobei: Die Methoden browse() und control() schließen einander aus, so wird control() nur dann aufgerufen, wenn es HTTP-Request-Parameter (GET, POST) gibt, die Methode browse() hingegen nicht. Die Methode putcontrol() wird, wie der Name schon sagt, aufgerufen, wenn die Request-Methode PUT ist und das auch ausschließlich nur dann.

Die verbleibenden Methoden init(), trailer() werden bei jedem Request aufgerufen, wie bereits angemerkt natürlich nur dann, wenn sie in der Subklasse definiert sind und in der oben gezeigten Reihenfolge.

Zum Erbe der Klasse main gehört die Methode eav(). Mit dieser Methode hat RRO den Vollzugriff auf alle die Antwortseite betreffenden Attribute, beispielswese so:

# Ändere das title attribute
    $self->eav('title','Neuer Titel für die Seite');

Die Abkürzung EAV steht für Entity, Attribute, Value. Entity ist der URL. Ansonsten ist die Klasse main als Erblasser für Methoden eher unbedeutend, vielmehr sorgt main für einen geregelten Ablauf in der Entgegennahme des Request und der Erstellung der Response. Das Wichtigste ist die Vererbung der Konfiguration, das ist sozusagen eine maschinenlesbare Projektverwaltung für die gesamte Website. Das Request/Response-Objekt RRO hat infolge der Vererbung Vollzugriff auf sämtliche Configuration Parameter.

Ein Wort zur Codeverteilung: AutoLoader

Eine Subklasse kann sehr umfangreich sein und neben den Interface-Methoden jede Menge weitere Methoden definieren. Dabei kann es sich um Datenbankzugriffe handeln oder Zugriffe auf Bezahlsysteme und andere Drittsysteme. Perls AutoLoader ermöglicht das Auslagern von Code in Dateien, in meinem Framework mache ich von dieser Möglichkeit regen Gebrauch. Das vermeidet Code-Redundanzen, die Code-Verteilung wird übersichtlicher und Code wird nur dann geladen, wenn das im jeweiligen Programmabschnitt erforderlich ist.

Interface Methoden per Konfiguration zuweisen

Zum Verständnis dieses Entwurfsmusters: Eine Subklasse, welche selbst keine Interface-Methoden definiert, bekommt per Konfiguration ein Interface zugewiesen. Diese Zuweisung erfolgt jedoch indirekt, infolge Bindung der Subklasse an einen bestimmten URL.

Beispielsweise sei als Klasse für die hier vorliegende Seite class = DBResponse konfiguriert. Diese Klasse wird von vielen einzelnen Seiten auf dieser Domäne benutzt, sie dient dazu, den Body bzw. das Template für den Body aus einer linearen Datenbank zu lesen. Die Klasse selbst definiert keine Interface-Methoden für das Framework. Durch Konfiguration fügen wir dem URL nun ein Interface hinzu: interface = hier und in der Interface-Datei hier.pm ist eine Code-Referenz definiert:

my $control = sub{
    my $self = shift;
    $self->nocache;
    $self->eav('title', 'Eingabefehler, Parameter sind hier nicht erlaubt!');
    $self->errorP( 
        descr => 'Parameter sind hier nicht erlaubt!', 
        title => 'Eingabefehler'
    );
};
###########################################################################
{ control => $control };

Sie können obenstehende Zuweisung testen, indem Sie hier klicken. Ihr Klick erzeugt einen Parameter im HTTP-Request, somit wird der Code für die Code-Referenz control ausgeführt und ganz oben auf dieser Seite ein Error-Paragraph eingebaut mit einer definierten Fehlermeldung.

Im praktischen Einsatz ist die control()-Method​e oftmals viel umfangreicher. Zur Wahrung der Übersicht werden sogenannte Schlüsselparameter verwendet.

Routing-Table und Common Classes

Die Routing-Table steckt in der Konfiguration und betrifft lediglich die Klassenbindung:

[/index.html]
class=HTMLFile

Eine Common Class liefert verschiedene Seiten aus:

[/foo.html]
class=Foo
file=foo.tmpl

[/bar.html]
class=Foo
file=bar.tmpl

Der Template-Prozess kann abgeschaltet werden, wenn das Attribute no_tt gesetzt wird:

[/boo.html]
class=Foo
file=boo.tmpl
no_tt=1

Anbieter: nmq​rstx-18­@yahoo.de, die Seite verwendet funktionsbedingt einen Session-Cookie und ist Bestandteil meines nach modernen Aspekten in Perl entwickelten Frameworks.