hi hotti,
also gut, mal ein bischen ausführlicher ;)
Mein PerlResponseHandler, nennen wir ihn FWNG, ist eine Package, deren Perl-Sourcen beim Apache-Start vom Perl-Interpreter kompiliert werden. In dieser Phase (Apache-Start) ist das so, das ist mod_perl.
Ein PerlResponseHandler ist, aus der Sicht des Apachen via CGI/1.1 ein Client, der mit dem Apachen via IO (STDIN, STDOUT) kommunizieren kann (er ist kein HTTP-Client, kann sein, dass ich hier Käse verzählt habe, sorry).
Ein PerlResponseHandler definiert eine Methode mit dem Namen handler(). Bei einem HTTP-Request wird diese Methode aufgerufen und damit steht in dieser Methode eine Instanz der Klasse Apache::Request zur Verfügung.
FWNG nutzt Methoden der Instanz Apache::Request um alles zu ermitteln, was der Request mitbringt, URL, Request-Header, Parameter usw. Beim ersten, nach dem Apache-Start erfolgenden Request, wird die RoutingTable und die Realm-Configuration in den MEMCache geladen. Ansonsten dann wird in den MEMCache (RoutingTable) geschaut, welche class an den URL gebunden ist.
Realm: Je nach Benutzergruppe, Default-Realm: public
Die Klasse wird kompiliert (das passiert auch nur beim ersten Request) und danach wird eine Instanz dieser Klasse erzeugt. Dabei erbt diese Subklasse von FWNG ein paar interessante Methoden und kriegt alles, was zum Request gehört, fein säuberlich in Attribute verpackt. Diese Instanz nenne ich Response-Objekt, das ist z.B. eine Instanz der Klasse MVC::Feedback weil das Feedback-Formular aufgerufen wurde (RoutingTable, realm public: /feedback.html => class=MVC::Feedback).
Über das Response-Objekt RO werden nun alle Methoden des FWNG-Interfaces aufgerufen. Verzweigungen können sich ergeben, wenn Benutzereingaben vorhanden sind. Die komplette Business-Logik liegt in class=MVC::Feedback, bzw. in den Methoden des Framework-Interfaces, welche class MVC::Feedback definiert. Welches Template geladen wird, weiß entweder die Subklasse MVC::Feedback oder sie bekommt über ein in der URL-Konfiguration konfiguriertes Attribut mitgeteilt, wo das Template zu holen ist, auf jeden Fall ist das vom Code sauber getrennt.
I.d.R. haben die Methoden des FWNG-Interface nur wenige Zeilen, ggf. werden Sourcen ausglagert (Factory). Beispiel in MVC::Feedback:
# Benutzereingabe, control wird aufgerufen
# eine Methode des FW-Interface
sub control{
my $self = shift;
# Mit den Eingaben alle Felder wieder ausfüllen
# die Eingabefelder sind email und mesg
$self->{STASH}{email} = $self->trim(($self->param('email')))
|| return $self->error("Bitte geben Sie Ihre eMail-Adresse ein");
$self->{STASH}{mesg} = $self->trim(($self->param('mesg')))
|| return $self->error("Bitte geben Sie Ihre Nachricht ein");
# Schlüsselparameter Senden-Butten.Name
if($self->param('send')){
$self->eav('title','Nachricht gesendet');
$self->sendmail() or die $@; # Mögliche Exception: MTAd läuft nicht
# alle Exceptions werden sauber im Browser ausgegeben
# Ergebnis ausgeben
$self->{STASH}{form} = undef; # Template wird umgeschaltet
$self->{STASH}{mesg} =~ s/\n/<br>/g;
}
else{
$self->error('Unbekannter Parameter');
}
}
Zurück in sub handler() hat das Response-Objekt nun alles, was die Ausgabe braucht. Platzhalter in RO->STASH. Wir rufen auf:
$r->print($ro->start_html, $ro->menu, $ro->body, $ro->end_html);
# $r ist die Apache::Request Instanz und kommuniziert mit dem Webserver über STDOUT
Das alles läuft in einem Try-Block. Andere URLs => andere Subklassen. Mehrere URLs können diegleiche Klasse verwenden, Unerschiede sind dann über Attribute geregelt. FWNG ist eine abstrakte Klasse, verwendet wird nur die Erweiterung (Subklasse).
Ebenfalls über ein Attribut konfigurierbar, ist es möglich, alle FW-IF-Methoden in einer extra Package (Trait) zu definieren. Wir können das auch Decorator nennen, weil das NACH der Instanzerstellung möglich ist.
Flache Klassenhierarchie, saubere Verzeichnisstruktur, aufgeräumter Code. Leider sieht die Praxis da draußen komplett anders aus, da herrscht das Onion Pattern vor.
Schöne Grüße ;)