Content Management Object, Teil 1

Die erste Frage ist nach dem "Warum Objektorientiert", hier die Antwort: Das Ergebnis ist ein URL, z.B. in Form einer HTML-Datei und dieses Ergebnis lässt sich sehr gut als Objekt modellieren. Daher gibt es für das Objekt URL bestimmte Eigenschaften wie beispielsweise einen Titel, eine Description usw. Und es lässt sich mindestens eine Methode beschreiben, wie das Objekt aus der Projektverwaltung heraus erstellt wird und wie der Dateitransfer zum produktiven Webserver erfolgt.

Objektorientiert im konkreten Fall heißt: Das Perl-Script ist die Schnittstelle zwischen Projektverwaltung und Webserver, es erstellt die in der Projektverwaltung beschriebenen Objekte. Infolge der Objektorientierung sind damit die Layer klar voneinander getrennt und die gesamte Verwaltung bis hin zum Publizieren wird ungeahnt pflegleicht. Ebenfalls leicht zu pflegen ist das Manager-Script, eigens dazu wurde eine Klasse erstellt, das Perl-Modul ContentBase.pm. Objektunabhängige Funktionen in diesem Modul sind ergänzende Werkzeuge zu objektabhängigen Funktionen und die Kommunikation mit dem Webserver erfolgt ausschließlich per HTTP. Das Staging ist scalierbar und flexibel, HTML-Inhalte können sowohl als Datei auf dem Server vorliegen, als auch als Body in einer Datenbank (dynamic Content).

Es sei darauf hingewiesen, dass unter dem allgemeinen Begriff Content Management System neben der Verwaltung von Inhalten auch eine Benutzerverwaltung und die Bereitstellung von Templates verstanden wird, dies ist jedoch nicht Bestandteil des vorliegenden Artikels. Vielmehr geht es hier um Objektorientierte Programmierung mit Perl anhand eines konkreten Beispiels.

Aufgrund einer rekursiven Herangehensweise zur Modellierung des Objekts, ausgehend vom zu erwartenden Ergebnis, ergeben sich infolge der Objektorientierten Programmierung (OOP):

Dem erstgenannten Punkt kommt eine besondere Bedeutung zu in Betracht der Prozesse zum Publizieren auf dem produktiven Webserver und auf dem Testsystem. Transparenz und klar abgegrenzte abstract Layer sind beste Voraussetzungen für Teamarbeit.

Die Klasse, das Objekt und der Konstruktor

Zur Definition der Klasse wird in Perl ein Modul erstellt, welches mit der Anweisung package Modulname; beginnt:

package ContentBase;

und im Programmcode des Scripts mit use Modulname; eingebunden wird. Die Moduldatei selbst bekommt die Dateierweiterung .pm. Ein zur Klasse gehöriges Objekt wird mit der vordefinierten Klassenfunktion new() erstellt, wobei diese Methode dem eigenen Modell entsprechend überlagert wird, betrachte untenstehend den Konstruktor der Klasse ContentBase:

# URL Objekt Konstruktor
sub new{
	my $self = shift; # das Objekt selbst
	my $url = shift;  # der Kern des Objekts

	$self = {}; # Vorbelegung als Referenz auf anonymen Hash

	# Object Properties, alle möglichen Eigenschaften
	# werden hier vorbelegt:
	$self->{URL} = $url;
	$self->{TITLE} = undef;   # title Tag
	$self->{DESCR} = undef;   # meta Tag
	$self->{PICS} = undef;    # angehängte Bildergalerie
	$self->{ORDNER} = undef;  # Navigation
	$self->{TIME} = undef;    # Last-Modified
	$self->{CONTENT} = undef; # cgi und php bleibt leer
	$self->{STAGING} = undef  # dynamic, static, both

	bless $self;  # Dem Objekt wird die Klasse bekanntgegeben
	return $self; # Rückgabe Objekt
}

# Objekterstellung im Script was das Modul verwendet
use ContentBase;
my $cb = ContentBase->new($url);

Möglicherweise gäbe es noch weitere Eigenschaften für ein URL-Objekt festzulegen, beispielsweise die Festlegung auf eine bestimmtes charset oder welche CSS-Datei eingebunden wird. Hierbei wird schon deutlich, dass eine objektorientierte Heransgehensweise solche Erweiterungen nicht verbaut, das Projekt ist scalierbar. Objekteigenschaften sind im Ergebnis eines URL verschieden abgebildet, z.B. in einem Tag (Markup) oder auch als Eigenschaft einer Datei (Last Modified).

Staging

S. (Stage: die Bühne) beschreibt die Mglichkeiten der Bereitstellung von Content (URLs) auf dem Webserver, unterschieden wird zwischen static und dynamic Content.

Static Content

Die HTML-Datei liegt im Dateisystem vor, alle Attribute sind über HTML Tags im Dokument ausgezeichnet, also eingebaut einschließlich der Navigation. Beim Anfordern der Seite als HTTP Request wird die Datei vom Webserver gelesen und als Response gesendet, das erfordert keine weiteren serverseitigen Prozesse wie z.B. CGI Prozesse. Inhaltliche Änderungen erfordern ein Neuerstellen der kompletten Datei.

Dynamic Content

Die Seite wird in Bereiche aufgegliedert, die dynamisch veränderlich sind. Diese Bereiche sind durch das Markup gekennzeichnet, beispielsweise sei der body ein dynamischer Bereich. Der dynamische Bereich liegt ausgelagert vor, in einer Datenbank oder in einer vergleichbaren Datenquelle. Zusammengebaut wird die HTML-Datei zur Laufzeit, unverzüglich nach dem Request und unmittelbar vor der Response. Es sind CGI-Prozesse erforderlich in Form von Perl- oder PHP-Scripts oder anderen ausführbaren Programmdateien.

Zur bedarfsweisen Umschaltung zwischen static und dynamic Content wird i.d.R. die Rewrite-Engine des Webservers verwendet, damit wird eine Umschaltung transparent für den Besucher der Website. Umschaltbedarf besteht beispielsweise bei Wartungsarbeiten am Datenbankserver.

Das Bereitstellen von Inhalten ist nicht nur auf HTML-Dateien begrenzt, darüber hinaus gibt es CGI-Scripts in Perl oder PHP geschrieben. Im Sinne OOP werden jedoch auch Scripts genauso wie HTML-Dateien als Objekt einer Klasse betrachtet. Lediglich beim Zuweisen der Attribute zu einem Objekt wird es Unterschiede geben, die sich konsequent auch in unterschiedlichen Objekt-Methoden wiederspiegeln.

Sicher gäbe es die Möglichkeit, die Zuweisung der Eigenschaften in einer einzigen Funktion vorzunehmen. Aber gerade hier besteht die Gefahr, dass der Code unübersichtlich wird. Besser und im Sinne einer OOP ist es daher, dass bereits bei der Erstellung eines Objekts feststeht, welche Sonderfunktionen diesem Objekt zugedacht sind.

Methoden

Neben den Eigenschaften eines Objekts wird unter dem Begriff der Methode eine an das Objekt gebundene Funktion verstanden. Untenstehend verschiedene Methoden zum Zuweisen der Attribute an ein Objekt, das vorher mit dem Konstruktor erstellt wurde.

Natives HTML Objekt

Die Methode htmlObj() beschreibt das Erstellen einer HTML-Datei als Objekt und liest dazu alle benötigten Attribute direkt aus der lokalen Projektverwaltung, die als Textdatei vorliegt. Ebenfalls zur Projektverwaltung gehört ein lokales Verzeichnis, in welchem sich die Bodies befinden. Der Body wird im Sinne des Managements als Content betrachtet und auch als Solcher dem Objekt als Eigenschaft zugewiesen mit obenstehender Methode.

CGI oder PHP Script

Bezüglich der Eigenschaften macht die Methode cgiObj() genau dasselbe wie die im letzten Abschnitt genannte Funktion: Die Projektverwaltung wird eingelesen und die Attribute dem Objekt zugewiesen. Einen Body jedoch gibt es hier nicht, alle CGI-Scripts erzeugen serverseitig selbst die Ausgabe von Content.

Hinsichtlich einer Volltextsuche gibt es jedoch die (noch nicht implementierte) Möglichkeit, die Ausgabe eines CGI-Scripts per HTTP dennoch zu erfassen und als Content dem Objekt zuzuweisen bzw., nach dem Speichern in einer serverseitigen Datenbank durchsuchbar zu machen.

Virtueller Ordner

Ein virtueller Ordner stellt den Index dar und ist eine HTML-Datei, die Links zu Seiten enthält, die zu diesem Ordner gehörig sind. Eine Sonderform des virtuellen Ordners ist die Datei map.html, die über das stets sichtbare und auf jeder Seite eingebaute Hauptmenu erreichbar ist. Weitere virtuelle Ordner sind beispielsweise Dateien wie Intern.Artikel.html, Intern.Artikel.Perl.html usw. die mit der Funktion folderObj() erzeugt werden.

Untenstehende kleine Aufstellung reflektiert das bisher Gesagte hinsichtlich der Attribut-Zuweisung an ein Objekt, welches verschiedenen Anforderungen gerecht werden soll:

$cb->htmlObj();   # Native HTML Datei
$cb->cgiObj();    # CGI Script in Perl oder PHP
$cb->folderObj(); # Virtual Folder

Der Erstellung eines Objekts und dem Assignment der Properties folgt der nächste und auch schon der letzte Schritt: Das Publizieren.

Dateitransfer mit HTTP

Ein wesentliches Merkmal des hier vorgestellten Content Managements besteht darin, dass es auch zum Publizieren einen einheitlichen Prozess gibt, der die Übertragung sowohl zum Testsystem als auch zum produktiven Webserver beschreibt. Methodisch wird damit auch das Testsystem in die Übertragung der Inhalte mit einbezogen. Für die Wahl von HTTP vs. FTP sprechen einige Gründe:

Die Nachteile sollen nicht verschwiegen werden, hier sind sie:

Praktisch ist dafür jedoch lediglich ein extra Script für den serverseitigen Prozess zu schreiben. Der User Agent hingegen ist in das Content Management eingebaut und ist eine Methode, die mit dem Objekt selbst aufgerufen wird, um das Objekt zum Server zu senden.

So wie es für FTP den Secure Pedanten SFTP gibt oder auch das Secure Copy Protocol SCP, gibt es auch für HTTP einen Secure Socket Layer: HTTPS. Darüber hinaus kann ein Dateitransfer per HTTP so verlässlich gemacht werden, wie das gewünscht wird. Beispielsweise kann eine MD5-Checksumme im Request Header mitgesendet werden, die dann in der Response gegengeprüft wird. Im Einfachsten Fall wird die Anzahl der übertragenene bytes per CONTENT_LENGTH geprüft.

Server Prozess, das Script für den Dateitransfer

So einfach wie das Hyper Text Transfer Protocol ist das serverseitige Script unkompliziert in Perl. Die Objekt Properties werden im HTTP-Header übertragen und finden sich in der CGI-Umgebung, im Hash %ENV. Der Content wird bei einem POST aus dem Standard-Eingabekanal STDIN gelesen und liegt als Binary vor. Der Serverprozess erledigt die im Pflichtenheft "Staging" gestellten Aufgaben, baut also entweder ein HTML-Objekt komplett mit den Eigenschaften als Datei für das Dateisystem zusammen oder schreibt den Body getrennt von den Eigenschaften in eine Datenbank, oder macht Beides (Properties STAGING => static, dynamic, both).

MySQL wird von vielen Hostern angeboten und ist mit dem Perl-Modul DBI einfach anzubinden. Da ein URL eindeutig ist, kann er als Primärschlüssel der Tabelle dienen, in welcher neben dem Content auch alle Attribute gespeichert sind, die Abfrage wird sehr performant ausfallen.

Eine interessante Alternative zum MySQL sind lineare Datenbanken, für Perl gibt es dazu DB_File, was an der Berkeley University entwickelt wurde. Eine DB nach DB_File wird in Perl an einen Hash gebunden und entsprechend einfach ist der Zugriff zum Lesen oder Schreiben.

Die Seite, die Sie gerade lesen, kommt aus einem in einer Binärdatei serialisierten Hash. Die zugehörigen Attribute liegen ebenfalls in einer Binärdatei vor und werden zur Laufzeit eingebaut, ebenso der HTML-Header, die Navigation und die Seite abschließende Tags. Zur Erzeugung einer HTML-Seite wird serverseitig über eine Basisklasse zunächst ein Objekt erstellt, bevor der Content in den Hauptspeicher geladen wird. Die Objekterstellung ist gleichzeitig die Prüfung, ob die angeforderte Seite existiert, bei einer erfolgreichen Objekterstellung wird die Seite ausgeliefert, ansonsten wird ein HTTP-Status 410 ausgegeben.

Der integrierte User Agent als Objekt-Methode

Wie bereits dargelegt, erfolgt die Übermittlung der Objekteigenschaften beim Transfer eines Objekts zum Webserver über den HTTP-Header und der Request Methode POST. Die Schlüsselrolle wird daher einer Funktion zuteil, die einen Custom Header ermöglicht, praktisch wird dazu das Standard-Modul HTTP::Headers eingebunden und über das Header-Objekt die Attribute in den Header eingebaut:

# HTTP Headers, ein eigener (custom) Header mit den Objekt-Attributen
my $h = HTTP::Headers->new;    # Header Object
$h->header(
	'MY_URL' => '/index.html',
	'MY_TITLE'    => 'Startseite ...'
);

# den Request formal zusammenbauen
my $req = HTTP::Request->new('POST', $ServerAgent, $h, $CONTENT);

# Request senden
my $res = $ua->request($req);

# Response ausgeben
print $res->content;

Zu beachten ist, dass Angaben im HTTP-Header nur ASCII-Zeichen enthalten dürfen, daher muss ein URI::Escape gemacht werden, das ist ebenfalls ein in der Perl-Distribution enthaltenes Standardmodul. Serverseitig wird das Escape wieder rückgängig gemacht, die Feldnamen wie MY_TITLE usw., finden sich im Hash %ENV mit dem Prefix HTTP_ also beispielsweise als HTTP_MY_URL. Eine Zusammenfassung der gesamten Prozedur siehe untenstehend:

my $url = '/index.html';          # Lege URL fest
my $cb = ContentBase->new($url);  # Objekterstellung
$cb->htmlObj();                   # Zuweisen der Eigenschaften
$cb->httpTransfer();              # Publizieren
                                  # fertig!

Projektverwaltung und Objektunabhängige Funktionen

Die Textdatei linkbase.ini der Projektverwaltung kann mit einem beliebigen Editor bearbeitet werden. In dieser Datei sind die virtuellen Ordner notiert mit den dazugehörigen HTML-Dokumenten oder auch Scripts in Form der Eigenschaften wie url, title, description usw.

Während eine Objektmethode wie htmlObj() das Objekt mit Eigenschaften befüllt, gibt es objektunabhängige Funktionen, die beispielsweise alle virtuellen Ordner aus der Projektverwaltung parsen oder alle URLs die es überhaupt gibt im Web-Projekt.

Das eigentliche lokale Manager-Script cman.pl wird auf der Kommandozeile gestartet wie folgt:

Obligatorisch:
-r   Remote
-l   Local
Beide Schalter schliessen sich aus.

Optional:
-f   Eine Datei (.html) wird aktualisiert
-i   Alle virtuellen Ordner werden aktualisiert
-g   Alle cgi's werden aktualisiert
-c   Ein CGI (.cgi) wird aktualisiert
-p   Eine PHP Datei wird aktualisiert
Ohne optionale Schalter wird alles aktualisiert (Cleanup).

Und bedient sich dazu sowohl objektabhängiger als auch objektunabhängier Funktionen des Moduls ContentBase.pm. Ebenfalls objektunabhängig ist eine Funktion zum Löschen eines Objekts was bereits publiziert wurde, also auf dem Server vorliegt. Soll ein Objekt auf dem Server gelöscht werden, erfolgt dies über die Cleanup-Option, hierbei wird der komplette Inhalt der Projektverwaltung mit publizierten Objekten abgeglichen.

Damit sind wir am Ende des Artikels angelangt. Das hier beschriebene Management von Content eignet sich vorzüglich für eine webbasierte hierarchische Dokumentenablage und bewährt sich in der Praxis.

Last-Modified: Tue, 22 Jun 2010 19:50:34 GMT