PApp

 view release on metacpan or  search on metacpan

doc/pws2001.sdf  view on Meta::CPAN

 <perl><![CDATA[
    $stylesheet[0] = $papp->load_stylesheet("demo/demo1");
    $stylesheet[1] = $papp->load_stylesheet("demo/demo2");
 ]]></perl>
!endblock perl

Naja, zuerst müsste man es schreiben oder besser klauen. Ausserdem muss
man es nicht zuerst laden, aber darüber gehe ich einfach mal hinweg...

Das C<perl>-Element ist übrigens {{nicht}} in einem Modul: Perl-Code,
der nicht in ein Modul gesteckt wird, wird beim Laden der Applikation
ausgeführt, d.h. ganz ähnlich wie ein Perl-Modul. Zu diesem Zeitpunkt
kann man aufwendige Initialisierungen machen bzw. Dateien nachladen, die
man später braucht.

Wie wendet man diese "Stylesheets" nun an? Ganz einfach, man packt alle
Module, die "gestyled" werden sollen, in ein C<style>-Element:

!block perl
 <style apply="output" expr="$stylesheet[ $S{style} ]">

 <module name=""><phtml><![CDATA[
    <p/><?slink __"To the edito...
    <p/><?slink __"Edit projec...
 ]]></phtml></module>

 ...
 </style>
!endblock perl

Das C<apply> bezieht sich auf den Zeitpunkt, zu dem das Stylesheet
angewendet werden soll. C<apply="output"> bestimmt, dass das Stylesheet
kurz vor der Ausgabe angewendet werden soll. Normalerweise würde man nun
den Dateinamen des Stylesheets mit C<src="pfad"> angeben, da wir aber
zwischen zwei Stylesheets hin- und herschalten wollen, geben wir mit
C<expr> einen Perl-Ausdruck an, der ein Stylesheet-Objekt als Ergebnis
haben (sollte).  Das muss {{natürlich}} auch kein XSLT-Stylesheet sein,
aber wem sage ich das...

Das Modul ist übrigens (bis auf die durch "..." angedeuteten Lücken)
vollständig, d.h. der Kopf mit Titel und Sprachumschalter (sowie
Stylesheet-Umschalter) wird durch das Stylesheet hinzugefügt.

H1: Tinychat - ein kleiner Chat in 20 Zeilen

Zum Schluss noch ein sehr einfaches Beispiel: C<macro/tinychat.papp> ist
ein sehr einfaches Chat-Fenster: Es zeigt die letzten fünf Eingabezeilen
an, gefolgt von einer Eingabebox. Der Chat-Inhalt ist systemweit, d.h. auf
allen Servern in einem PApp-System ist immer derselbe Text, man kann diese
"Chatbox" also in beliebige Programme einbauen.

!block perl
 <macro name="tinychat*()"><pxml><![CDATA[
 #if $A{tinychat_submit} && $P{input} && !reload_p
 <:
    lockenv {
       my $r = getenv "TINYCHAT";
       shift @$r while @$r > 5;
       push @$r, escape_html sprintf "%s: %s",
                    username || "<ANON$userid>", $P{input};
       setenv "TINYCHAT", $r;
    }; 
 :> 
 #endif
 <: 
    my $r = getenv "TINYCHAT";
    echo map "<tt>$_</tt><br />", @$r;
 :>
 <br />
 <?sform -tinychat_submit => 1:>__"Chat: "<?textfield "input":><?endform:>
 ]]></pxml></macro>
!endblock

Zuallererst ist C<tinychat> nur eine Funktion, teilt sich also den
Namensraum mit dem Aufrufer. Tinychat ist so winzig und so schlecht
konfigurierbar, dass das Sinn macht... Sehen wir uns mal den Teil an, der
die Ausgabe erledigt:

!block perl
 <: 
    my $r = getenv "TINYCHAT";
    echo map "<tt>$_</tt><br />", @$r;
 :>
!endblock

Die Texte sind in einer "Environment"-Variable gespeichert. Diese
Variablen sind global für das gesamte PApp-System und könenn auch
ausserhalb von PApp abgefragt bzw. verändert werden. Das ganze ist also
eher ein System zur asynchronen Kommunikation. Neben normalen Strings kann
man alles darin ablegen, was irgendwie serialisierbar ist, insbesondere
eine Array-Referenz, in der die einzelnen Zeilen sind.

Zur Ausgabe wird also lediglich die Variable C<PAPP_TINYCHAT> ausgelesen
und die einzelnen Zeilen in ein "<tt>zeile</tt><br />" gepackt.

Fehlt noch das Eingabefeld:

!block perl
 <?sform -tinychat_submit => 1:>
 __"Chat: "
 <?textfield "input":>
 <?endform:>
!endblock

Hier wird kein C<editform> benutzt: Der Overhead ist im Vergleich
zum Gewinn (es gibt keinen) zu gross.  Die Funktion C<sform>
(die auch von C<ef_begin> benutzt wird) gibt das einleitende
C<FORM>-Tag aus.  Dann folgt der Text C<Chat:> und ein ganz normales
HTML-C<INPUT>-Element. C<endform> schleisslich gibt ein "</FORM>" aus und
existiert eigentlich nur aus Symmetrie.

Das Eingabefeld heisst C<input>. Was passiert, wenn wir sonst noch
ein C<input>-Feld haben und dieses andere Feld submittet wird?  Kein
Problem{{}}: Wir übergeben C<sform> einfach ein Argument, das nur dazu
dient, die Information "Tinychat-Formular ist gemeint" zu übertragen.

Ganz nebenbei: C<sform> ist - wie sehr viele PApp-Funktionen - sehr
einfach definiert:

!block perl
   PApp::HTML::_tag "form", { method => 'GET', action => &surl };
!endblock

Nun zum Teil, der die Eingabezeile nach dem Abschicken hinzufügt:

!block perl
 #if $A{tinychat_submit} && $P{input} && !reload_p
 <:
    lockenv {
       my $r = getenv "TINYCHAT";
       shift @$r while @$r > 5;
       push @$r, escape_html sprintf "%s (%s): %s",
                    username || "<ANON$userid>", $P{input};
       setenv "TINYCHAT", $r;
    }; 
 :> 
 #endif
!endblock

Die erste Zeile testet drei Dinge:

^ Es muss "unser" Formular sein; das erkennt man daran, dass der Parameter
  C<tinychat_submit> logisch wahr ist.
& Die Eingabe sollte nicht leer sein (o.k. "0" ist auch nicht erlaubt).
& Die Seite sollte nicht das Ergebnis eines "Reloads" sein.

Der letzte Punkt bedarf einer Erklärung: PApp weiss, wie oft eine
Seite angefordert wurde und teilt dies über die Funktion C<reload_p>
mit, die die Anzahl der Seitenaufrufe für {{dieselbe}} Seite minus
eins zurückliefert. Ist diese Zahl ungleich null, wurde der Code schon
ausgeführt.

Das eigentliche hinzufügen ist Standard: Variable holen, alte Zeilen
rauslöschen, neue Zeile hinzufügen, Variable auf neuen Wert setzen.

Die Funktion C<lockenv>, in die die Manipulation eingeschlossen ist,
schützt das Programm gegen gleichzeitige Modifikationen anderer
Webserver, d.h. die Operation wird atomar.  C<escape_html> quoted das
Argument. Die Funktion C<username> (aus dem C<macro/admin>-Paket) liefert
den Namen des Benutzers, falls dieser einen besitzt. Ansonsten nimmt
Tinychat C<ANON> + die numerische User-ID, die jedem Benutzer zugeteilt
wird.

H1: Die Nachteile

Bei allen Vorteilen, es gibt auch Nachteile... die packe ich ans Ende und
fasse mich auch gerne sehr kurz:

H2: Die Lizenz (Oder doch ein Vorteil?)

Tja, PApp war doch tatsächlich mal GPL, und zwar zu einer Zeit, zu der
wir es praktisch nur als CGI-Krücke verwendet haben. Inzwischen hat
sich PApp gemausert und wurde zu einem unserer Standbeine. Als eine
andere Firma versuchte, uns mit unserem Produkt Konkurrenz bei unseren
Kunden zu machen ("wir können da einfach ein paar Dutzend Programmierer
dransetzen"), mussten wir leider handeln.

Die "PApp Public License" ist so ähnlich wie die MySQL Public License,
d.h. wer sie privat einsetzt (bzw. für die Forschung und Lehre oder
für eine not-for-profit-Organisation), darf PApp weiterhin kostenlos
nutzen. Wer kräftig Kohle damit macht, muss uns einen Teil davon abgeben
(die eigentliche Lizenz ist etwas länger ;).

Langfristig ist geplant, PApp wieder in GPL oder besser zu
überführen. Mittelfristig muss man damit Leben ;)

H2: Die Abhängigkeiten

Zur Zeit gibt es keine Perl-Release, die annähernd mit UTF8
zurechtkommt. Z.Zt. (d.h. buchstäblich in dieser Minute) benötigt
PApp perl-5.7.0-DEVEL7952 oder ein paar hundert Patches davor oder
danach. Demnächst wird auf DEVEL8xxx umgestellt (z.Zt. gibt es einige
Bugs, die dies verhindern). PApp funktioniert zwar wunderbar, aber eben
nur, wenn die restlichen Komponenten aufeinander abgestimmt sind.



( run in 0.523 second using v1.01-cache-2.11-cpan-6aa56a78535 )