Datenbank Framework CogniX Herbert Liechti, <[email protected]> 19. Februar 2001 Mit dem Einstieg in die Web-Programmierung vor ca 3 Jahren störte mich immer wieder, daß die sogenannten Embedded-Sprachen wie HTML::EP, Embperl, HTML::Mason, php, asp usw keine richtigen Applikationen zulassen. Die EmbeddedSprachen haben zwar klar den Vorteil, rasch eine Layout-Vorgabe in ein dynamisches Umfeld zu integrieren, versagen aber meiner Meinung nach bei der Bildung einer Applikation und eines konsistenten Benutzer-Interfaces. Eine konsistente Entwicklung, wie man sie aus der klassischen Client/ServerProgrammierung kennt, ist einfach nicht gewährleistet. Das Programmieren der Datenbank-Interfaces ist trotz der sehr guten DBI/DBD Libraries eher mühsam und langweilig, weil man stets die gleiche Funktionalität wieder programmiert. Wenn in einem Projekt Automaten (Dämonen, Scheduler etc) notwendig werden, implementiert man die Programme nochmals neu. Business- und Datenlogik sind da zumeist in den CGI-Programmen fest integriert und lassen sich nicht ohne weiteres ohne Benutzer-Interface betreiben. Die Idee ein Objekt-orientiertes Framework zu entwickeln, war da ziemlich rasch geboren und in den letzten zwei Jahren ist ein gutes Werkzeug entstanden, welches erlaubt, rasch und effizient Datenbank-Applikationen zu erstellen, die vollständig über ein Browser-Interface bedienbar sind. Auf den nachfolgenden Seiten stelle ich die wichtigsten Features des Frameworks vor. CogniX ist umfassend dokumentiert, in diesem Dokument können die Möglichkeiten von CogniX nur im Überblick beschrieben werden. 1 Inhaltsverzeichnis 1 Key features 3 2 Bezugsquelle 5 3 Architektur 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 7 9 10 10 11 12 12 13 14 6 7 Klassendefinition . . . . . . . Technische Dokumentation . . Erstellen der Tabelle in der DB Sprach-Unabhängigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 15 16 17 Bilden von Präsentations Klassen 18 5.1 5.2 Konfiguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Weiterführende Anpassungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 19 . . . . . . . . . . . . . . . . . . . . 14 Dokumentation CogniX 19 Tools 7.1 7.2 7.3 7.4 7.5 7.6 8 . . . . . . . . . . Bilden von Datenbank-Klassen 4.1 4.2 4.3 4.4 5 5 Datenlogik . . . . . . . Präsentations-Logik . . Berechtigungen . . . . Event-Handling . . . . Formatierung der Daten Ausgabe . . . . . . . . Exception Handling . . Dokumentation . . . . Tools . . . . . . . . . . Perl Module . . . . . . createTemplate crebas . . . . . prepLanguage . heinzelmann . . load . . . . . . checkIntegrity . 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Showcases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 20 20 20 20 21 2 Abbildungsverzeichnis 1 2 3 4 5 1 Architektur CogniX . . . . . . . . . . . . . . . . . . . . . . . . . . Tabellensicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abhängige Datensätze werden automatisch angezeigt . . . . . . . . . . Erfassung eines neuen Datensatzes . . . . . . . . . . . . . . . . . . . Datenbankmodell und -Dokumentation über den Browser verfügbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 7 8 8 13 Key features Die Key Features von CogniX sind: • Schnelles Erstellen von Datenbank gestützten Web-Anwendungen – Daten- und Business-Logik sind getrennt von der Präsentations-Logik. Die Teile können unabhängig voneinander betrieben werden. So ist es möglich, Programme zu schreiben, die ohne menschliche Interaktion ablaufen (Dämonen), welche die gleichen Daten-Klassen benutzen, wie die Benutzerprogramme – Generierung von Default-Präsentationsklassen – Unterstützung von Mehrsprachigkeit zum Beispiel in Abhängigkeit des aktuellen Benutzers – Automatische Unterstützung von referentieller Integrität, wenn nicht auf der Datenbank definiert – Vergabe von Benutzerrechten auf Tabellenebene sowohl für einzelne Benutzer als auch für ganze Benutzer-Gruppen – Default Web Schnittstelle * Browsing in der kompletten Datenbank-Struktur (Geeignet auch für große Datenmengen) * Fremdschlüssel können mit automatisch generierten Hyperlinks verfolgt werden (intuitive Navigation in der Datenbank-Struktur) * Freie Eingabe von Suchkriterien für Queries * Datenbankverkehr (insert, update, delete) mit Sicherstellung der referentiellen Integrität * Cascading-Deletes (Konfigurierbar) – Datenbank-Modell mit POD Dokumentation über Browser abrufbar – Generierung von SQL-Scripts für die Erstellung der Datenbank. • Unterstützung der folgenden Datenbanken: 3 – Postgres ab Version 6.5.3 Frei verfügbares objekt-relationales Datenbank-Management-System (www.postgresql.org) – Informix mit Universal Data Option Kommerzielles Datenbank-Produkt (www.informix.com) – Oracle ab 8.1.6 Kommerzielles Datenbank-Produkt (www.oracle.com) – DBD::Proxy Über einen Proxy Modus können beliebige Datenbanken auf fernen Rechnern angesprochen werden, aufwendige Installationen von Datenbank spezifischen Client- und Netz-Produkten entfällt somit komplett. Die jeweiligen Datenbank-Treiber müssen nur auf dem Datenbank-Server installiert sein. Weitere Datenbanken können mit geringem Aufwand in das Framework integriert werden. • Rasche Entwicklung von Internet-/Intranet-Applikationen – Konfiguration des Benutzer-Interfaces – Unterstützung für mehrsprachige Applikationen – Einfaches Hinzufügen von Business-Logik wo notwendig – Einfaches User/Session Handling (Apache::Session) – Unterstützung bei komplexen DB-Abfragen – Wiederverwendbarkeit von Codeteilen – Einfaches Einbinden von Client seitigem Java-Script-Code • Perl – Strikter Einsatz des objektorientierten Paradigmas von Perl – Verwendung von Perl-Libraries aus dem CPAN (z.Bsp. CGI, CGI::FastTemplate, DBI, Apache::Session) – mod-perl für einen nativen Zugriff via Web-Server auf die Applikation – Einfache Realisierung von Schnittstellen (z.Bsp. XML) Dank den frei verfügbaren Bibliotheken. • Kombinierbar Mit dem Framework können Applikationen erstellt werden, die sich hervorragend für das Verwalten von Daten über ein Web-Interface eignen. Das war die treibende Kraft für die Entwicklung von CogniX. Für Layout geprägte Anwendungen, die meist nur einen lesenden Zugriff auf eine Datenbank ausüben, sind Produkte wie ePerl, HTML::Mason sehr gut mit dem Framework kombinierbar. 4 • Dokumentation Vollständig dokumentiert inkl. Beispiel-Anwendung. Gesamtdokumentation als pdf erhältlich. 2 Bezugsquelle Mit Erscheinen dieser Dokumentation sollte CogniX über das CPAN verfügbar sein. Über unsere Web-Site http://www.thinx.ch kann die jeweils neueste Version abgeholt werden. 3 Architektur Beim Design von CogniX wurde konsequent darauf geachtet, daß Daten-, Business- und PräsentationsLogik vollständig getrennt sind. Dadurch eignet sich CogniX unter Verwendung der Datenund Business-Logik Schicht auch hervorragend für Automaten (Dämonen, Scheduler, Cron jobs etc.). Die nachfolgende Abbildung zeigt die Architektur auf. DBI DB DBD Presentati on l ogi c Data and busi ness l ogi c Abstract l ayer dbView wwwBase DbBase I mpl ementati on l ayer Table.pm wwwTable.pm Busi ness l ogi c and appli cati on l ayer blmModule applModule Uses I nheri ts Abbildung 1: Architektur CogniX 5 3.1 Datenlogik Jede Tabelle einer Datenbank wird in CogniX mit einer eigenen Klasse repräsentiert. Eine solche Klasse erbt von der Klasse DbBase. DbBase implementiert die grundsätzlichen Funktionen für den Verkehr mit der Datenbank (Select, Update, Insert, Delete) und stellt jederzeit die referentielle Integrität sicher. Validierungsfunktionen für die diversen Datentypen sind ebenfalls Bestandteil von DbBase. DbBase wiederum erbt von einer Klasse, die Datenbank abhängige Besonderheiten implementiert hat, soweit die Besonderheiten nicht über den DBD Driver abgehandelt sind (z.Bsp. SERIAL, DATETIME Datentypen). DbBase stellt diverse Hooks oder Insertion-Methoden zur Verfügung, die in der abgeleiteten Klasse implementiert werden können. So können z.Bsp. mit der Methode setDefaultsAfterInsert nach dem Einfügen eines neuen Datensatzes in der Daten-Klasse Aktionen durchgeführt werden, ohne daß die Insert Methode verändert werden muß. Hier ein kleines Beispiel dazu. Angenommen, zu einem geänderten Tupel in der DB muß jedesmal ein History-Eintrag erfolgen. =head2 setDefaultsAfterUpdate Ueberschriebene Methode aus DbBase. Wird gerufen, wenn ein Artikel-Record aktualisiert wurde. Es muß ein History Eintrag für jede Aenderung bei der Tabelle Artikel erstellt werden. Ein Eintrag in PublishHistory wird nur erstellt, wenn der Artikel einen Wert in ArtikelStatusId hat. =cut sub setDefaultsAfterUpdate { my $self = shift; $self->SUPER::setDefaultsAfterUpdate; # Zuerst die Methode der SUPER Klasse rufen if ($self->getValue(’ArtikelStatusId’)) { $main::msg->ignoreMessage(’message’, ’ok’); # Standardmeldungen unterdrücken # Neues Objekt der Klasse PublishHistory instanzieren. my $PublishObj = PublishHistory->newEmpty( { artikelId => $self->getId, ArtikelStatusId => $self->getValue(’ArtikelStatusId’), MitarbeiterId => $self->getValue(’MitarbeiterId’), Comments => ’Update Artikel’, JobDone => ’f’, rubrikId => $self->getValue(’rubrikId’), } ); $PublishObj->sqlInsert; # Wert in DB schreiben $main::msg->acceptMessage(’message’, ’ok’); } } Solche Hooks stehen für jede mögliche Aktion (Insert, Update und Delete) zur Verfügung, bevor und nachdem die Aktion ausgeführt wird/wurde. 6 3.2 Präsentations-Logik Analog zur Datenlogik wird jede Datenbank-Tabelle mit einer Präsentations-Klasse implementiert. In einem hohen Masse kann das Benutzerinterface mit Properties einfach konfiguriert werden. Eine solche Klasse erbt von wwwBase. wwwBase stellt über ein CGI-Interface die wesentlichen Funktionen für ein Benutzer-Interface zur Verfügung: • Browsing in den Datenbeständen – Tabellensicht Abbildung 2: Tabellensicht Anzeige der Tabellensicht. Mehrere Datensätze einer Tabelle werden angezeigt. Die Funktion für das Seitenweise Blättern in den Datensätzen steht zur Verfügung. – Record View 7 Abbildung 3: Abhängige Datensätze werden automatisch angezeigt Anzeige eines einzelnen Datensatzes. Die abhängigen Datensätze werden automatisch angezeigt. Diese können per Parameter auch ausgeblendet werden. – Neu Erfassung eines Datensatzes Abbildung 4: Erfassung eines neuen Datensatzes 8 Ein Formular für die Erfassung eines neuen Datensatzes. Analog steht für das Editieren das gleiche Formular zur Verfügung. – Editieren eines Datensatzes – Löschen eines Datensatzes – Suchen von Datensätzen • Navigation Mit Hyperlinks kann die Datenbank-Struktur verfolgt werden. Fremdschlüssel werden automatisch aufgelöst und können bei der Eingabe mit Listboxen, Radioboxen oder einer erweiterten Suche konfiguriert werden. Über die konfigurierten Benutzer-Berechtigungen (siehe weiter unten) können Zugriffe auf andere Tabellen eingeschränkt werden. • Scrolling Bei grösseren Datenbeständen in einer Tabelle wird ein Seitenweises vorwärts und rückwärts Blättern angeboten. Der angezeigte Ausschnitt kann konfiguriert werden. • Generelle Konfiguration Benutzerinterface Das Aussehen des Benutzerinterface kann im hohen Masse über Systemparameter, Templates und Cascading Style Sheets konfiguriert werden. 3.3 Berechtigungen Berechtigungen können in einer C/S Applikation bequem mit Datenbank eigenen Mitteln (grants) bewerkstelligt werden. Da in einer CGI-Umgebung die Datenbank jeweils nur mit einem bestimmten Benutzer angesprochen wird, funktioniert die Vergabe von Berechtigungen nicht. CogniX unterstützt deshalb die Vergabe von Benutzerrechten auf der Datenbank mit einem Modul, mit der für Benutzer und Benutzergruppen Rechte auf einer bestimmten Tabelle vergeben werden können: package grantTable; # available user groups @grantTable::groups = qw( admin user readonly ); # Assignment of the user to the group %grantTable::groupMember = ( user => ’user’, patrick => ’admin’, peter => ’admin’, herbie => ’admin’, mzaugg => ’admin’, admin => ’admin’, guest => ’readonly’, 9 ); %grantTable::Abo = #user group user => admin => readonly => ); ( Read [1, [1, [1, %grantTable::Agenda = ( #user group Read user => [1, admin => [1, readonly => [1, ); New record 1, 1, 0, Update 1, 1, 0, Delete 1, 1, 0, Lookup 1, 1, 1, ], ], ], New record 1, 1, 0, Update 1, 1, 0, Delete 1, 1, 0, Lookup 1, 1, 1, ], ], ], Der Benutzer mit dem Login patrick zum Beispiel wird über das Hash %grantTable::groupMember der Benutzergruppe admin zugeordnet. Der Benutzer erhält so zum Beispiel auf der Tabelle Abo das Recht, Daten zu lesen, Inserts, Updates und Deletes durchzuführen und bestimmte Werte (lookup) aus der Tabelle zu lesen. CogniX setzt diese Definitionen automatisch in der Applikation richtig um. So erhält die Gruppe readonly zum Beispiel in keiner der Tabellen die Möglichkeit, Datensätze zu erfassen, ändern oder löschen. 3.4 Event-Handling Gestartet wird die Applikation über ein kurzes CGI Script. Das CGI Script führt lediglich die Datenbank Connects durch und übergibt die Kontrolle danach dem aus der Klasse CogniX::CgiMain instanzierten Objekt. Das CogniX::CgiMain-Objekt bestimmt anhand der CGIParameter und der Sessionvariablen, welche Aktion ausgelöst werden muss (z.Bsp. neuer Datensatz erfassen in Tabelle Artikel). Es instanziert von der korrekten wwwKlasse (Präsentationsklasse) ein Objekt und ruft dort die notwendigen Methoden auf. 3.5 Formatierung der Daten Die Formatierung der Ausgabe in HTML erfolgt über die Klasse CogniX::htmlStyle. Zur Startzeit der Applikation wird ein Objekt dieser Klasse instanziert. Jedes CogniX Projekt besitzt eine zentrale Konfigurationsdatei, welche per Definition param.pm genannt wird. Dort werden unter anderem die Parametrierungen für die Klasse CogniX::htmlStyle vorgenommen. Aussehen der formatierten Ausgabe kann hier massgeblich beeinflusst werden. Hier sehen Sie ein Beispiel einer solchen Konfiguration: # Formatting of table elements in HTML output %main::elements = ( # Tabellenformatierung (<TABLE> Tag) dataViewTABLE => {-cellpadding => 2, -cellspacing => 1, 10 -border -width }, # Formatierung <TH> Element dataViewTH => {-align -valign -class }, => 0, => ’100%’, => => => ’left’, ’middle’, ’th1’, # Formatierung <TD> Element dataViewTD => {-align => ’left’, -valign => ’top’, -class => ’td1’, }, # Formatierung <TD> Element. Zwischen dataViewTD und dataViewTD2 # wird bei Tabellensichten immer abgewechselt. dataViewTD2 => {-align => ’left’, -valign => ’top’, -class => ’td2’, }, # Formatierung für Alert Formatierungen dataViewAlert => {-align => ’left’, -valign => ’top’, -bgcolor => ’#FF0000’, }, ); Nebst den hier angegeben Werten kann das Aussehen der Applikation durch CascadingStyle-Sheets (css) beeinflusst werden. Zum Beispiel ist oben das Element dataViewTH durch den class Parameter th1 referenziert. Im css ist dann die folgende Definition abgebildet: TH.th1 3.6 { font-size:12pt; color:white; font-family:Helvetica,sans-serif; font-weight:bold; background-color:#778899; text-align:left; } Ausgabe Während der Verarbeitung erfolgt die Ausgabe der Ergebnisse nicht unmittelbar über STDOUT sondern wird in einem Objekt der Klasse CogniX::htmlStyle zwischengespeichert. Die Präsentationsklassen, die von wwwBase abgeleitet sind, leiten die Ausgabe also an dieses Objekt weiter. Erst wenn die Verarbeitung komplett abgeschlossen ist, wird mit dem CGI::FastTemplate Module ein Template mit dem fertigen Inhalt befüllt. Im Template selber gibt es vordefinierte Platzhalter, die durch die Inhalte ersetzt werden. Layout Anpassungen sind deshalb sehr einfach zu bewerkstelligen. 11 3.7 Exception Handling Treten während der Verarbeitung Fehler auf, erhält der Benutzer nicht einfach eine Fatal Meldung des Web-Servers. CogniX nutzt intensiv den try, catch, throw Mechanismus (eval) von Perl. Ausnahmesituationen werden also behandelt und Fehlermeldungen, Warnungen, Messages werden in einem Objekt der Klasse CogniX::message gesammelt und über das Ausgabe Objekt der Klasse CogniX::htmlStyle ausgegeben. 3.8 Dokumentation Über ein CGI-Interface dbmodel.pl haben die Entwickler und falls gewünscht die Benutzer Zugang zu der technischen Dokumentation. Es werden die Definitionen aus den Datenklassen und allenfalls vorhandene POD-Dokumentation für die Aufbereitung verwendet. Zur Laufzeit wird eine Tabellenbeschreibung aufbereitet, die einerseits die Definitionen der Tabelle enthält und andererseits die aufbereitete POD-Dokumentation: 12 Abbildung 5: Datenbankmodell und -Dokumentation über den Browser verfügbar Die über- und untergeordneten Tabellen können per Hyperlink verfolgt werden. Ein Beispiel, wie die Dokumentation und die Tabellenstruktur definiert wird, erfolgt weiter unten im Abschnitt ’Bilden von Datenbank-Klassen’. 3.9 Tools In den zwei Jahren sind zahlreiche Tools rund um CogniX entstanden, die den Entwicklungsprozess optimal unterstützen. Eine Auflistung der Tools finden Sie am Schluß des Dokumentes. 13 3.10 Perl Module CogniX läuft unter mod_perl, kann aber auch über ein normales CGI Interface betrieben werden. CogniX verwendet viele Libraries aus dem CPAN: • CGI • CGI::FastTemplate • DBI • DBD Die jeweiligen Driver für eine spezifische Datenbank • Apache::Session 4 Bilden von Datenbank-Klassen In den Datenbank-Klassen werden die Struktur einer Tabelle definiert, die Beziehungen der Tabelle zu anderen Klassen (Relationship) definiert, Index-Definitionen vorgenommen. Übersetzungen in die Zielsprache(n) der Attribute und Tabellennamen erfolgt ebenfalls in der DatenbankKlasse. Für die Erstellung einer solchen Klasse steht das Tool createTemplate zur Verfügung. Per Definition muß eine Datenklasse genauso heißen wie die entsprechende Tabelle in der Datenbank. 4.1 Klassendefinition package Artikel; use strict; @Artikel::ISA = (’CogniX::DbBase’); %Artikel::attribute = ( # order/type length/mandatory/foreign key ArtikelId => [ 1, ’SERIAL’, 0, 1, 0 ], Zeitstempel => [ 2, ’DATETIME’, 0, 1, 0 ], RubrikId => [ 3, ’INTEGER’, 0, 1, ’Rubrik.RubrikId’ ], Haupttitel => [ 4, ’VARCHAR’, 80, 1, 0 ], Untertitel => [ 5, ’VARCHAR’, 600, 1, 0 ], Body => [ 6, ’OID’, 0, 1, 0 ], Reihenfolge => [ 7, ’INTEGER’, 0, 0, 0 ], MandantId => [ 8, ’INTEGER’, 0, 1, ’Mandant.MandantId’ ], PersonId => [ 9, ’INTEGER’, 0, 1, ’Person.PersonId’ ], ArtikelStatusId => [ 10, ’INTEGER’, 0, 1, ’ArtikelStatus.ArtikelStatusId’ ], FlagFrontSide => [ 14, ’BOOLEAN’, 0, 1, 0 ], ); # Detail tables @Artikel::detail = qw(ArtikelLink.oberId ArtikelLink.unterId Bild.ArtikelId 14 SlArtikel.ArtikelId ); $Artikel::pk = ’ArtikelId’; # Name of the primary key $Artikel::timestamp = ’Zeitstempel’; $Artikel::sequenz = ’artikelid_seq’; $Artikel::cascadingDelete = 1; %Artikel::indexes = ( fk_Artikel_1 => [’IX’, [’RubrikId’]], fk_Artikel_2 => [’IX’, [’MandantId’]], fk_Artikel_3 => [’IX’, [’PersonId’]], fk_Artikel_4 => [’IX’, [’ArtikelStatusId’]], ); 1; Die Attribute einer Tabelle sind als Keys im Hash %Artikel::atribute abgelegt und auf jeden Key im Hash besteht eine Referenz auf ein anonymes Array als Value. Das anonyme Array enthält die Position des Attributes in der Tabelle, den Datentyp, falls notwendig die Datenlänge, die Angabe, ob es sich um ein optionales oder obligatorisches Feld handelt und die Definitionen der Fremdschlüssel. Im Array @Artikel::detail wird definiert, was für Child-Relationships die Tabelle hat. Im obigen Beispiel sind das vier Beziehungen. Die Definition $Artikel::pk gibt an, welches Feld der Primary Key ist. $Artikel::timestamp definiert das Feld mit dem Zeitstempel. Das Feld wird verwendet, um automatisch den Zeitstempel der letzten Änderung festzuhalten. CogniX überprüft damit, ob ein Datensatz von einem anderen Benutzer in der Zwischenzeit verändert wurde. $Artikel::sequenz legt den Sequenz Namen für den SERIAL Datentyp fest für die DBSysteme Postgres und Oracle. Hat die Variable $Artikel::cascadingDelete einen wahren Wert, führt CogniX bei der Löschung eines Datensatzes einen Cascading-Delete durch; alle direkt abhängigen Datensätze werden vor dem eigentlichen Datensatz gelöscht. Mit dem Hash %Artikel::indexes werden die Indexe auf der Tabelle definiert. Der Index für den Primary Key wird automatisch erstellt. 4.2 Technische Dokumentation Die Klasse kann und soll dokumentiert werden. Natürlich ist POD das Mittel der Wahl. Hier ein kleines Beispiel: =head1 NAME Artikel.pm - Artikel Klasse =head1 DESCRIPTION Beinhaltet die Daten eines Artikels. Ein Artikel wird zwingend einer Rubrik zugeordnet. Die Zuodnung zu einem Mandanten ist redundant geführt. Aus Performance-Gründen und weil 15 über den Mandant praktisch in jeder Query eingeschränkt werden muss, wurde die Redundanz hier bewusst eingegangen. Diese Beziehung ergäbe sich auch indirekt über die Rubrik. =head1 CVS Infos Version: Datum : von : Source : $Revision: 1.12 $ $Date: 2001/02/17 21:23:40 $ $Author: herbie $ $Source: /home/cvs/zeitix/zeitix/Artikel.pm,v $ =cut Die POD-Dokumentation wird für die Aufbereitung der Dokumentation über dbmodel.pl ebenfalls als HTML aufbereitet und angezeigt (siehe weiter oben). 4.3 Erstellen der Tabelle in der DB Mit den Definitionen in der Daten-Klasse kann mit dem Tool crebas direkt ein SQL-Script für die Erstellung der Tabelle in der Datenbank erstellt werden. herbie@uranus:~/ws/zeitix/zeitix > crebas Artikel.pm /* **************************************************************************** * CREATE DATABASE SCRIPT /opt/perl5.6.0/bin/crebas * * Datum : Wed Jan 17 11:54:33 2001 * Klassen : Artikel.pm * **************************************************************************** */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * TABLE DEFINITION FOR TABLE Artikel * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ create sequence artikelid_seq START 1; create table Artikel ( ArtikelId INTEGER NOT NULL DEFAULT NEXTVAL(’artikelid_seq’), Zeitstempel DATETIME NOT NULL, RubrikId INTEGER NOT NULL, Haupttitel VARCHAR(80) NOT NULL, Untertitel VARCHAR(600) NOT NULL, Body OID NOT NULL, Reihenfolge INTEGER , MandantId INTEGER NOT NULL, PersonId INTEGER NOT NULL, ArtikelStatusId INTEGER NOT NULL, FlagFrontSide BOOLEAN NOT NULL ); /* ---------------------------------------------------------------------------* INDEXES grants and functions FOR TABLE Artikel 16 * ---------------------------------------------------------------------------*/ Create unique Index ArtikelId_ix ON Artikel(ArtikelId); Create index fk_Artikel_1 ON Artikel(RubrikId); Create index fk_Artikel_2 ON Artikel(MandantId); Create index fk_Artikel_3 ON Artikel(PersonId); Create index fk_Artikel_4 ON Artikel(ArtikelStatusId); CREATE FUNCTION Artikel_id_max() RETURNS INT4 AS ’Select max(ArtikelId) FROM Artikel’ LANGUAGE ’sql’; grant all on Artikel to public; grant all on artikelid_seq to public; Das funktioniert problemlos auch für mehrere Klassen gleichzeitig. Das oben aufgeführte Beispiel ist die Definition für Postgres. 4.4 Sprach-Unabhängigkeit Ist die Klassen Definition einmal gemacht, kann mit dem Tool prepLanguage eine Struktur vorbereitet werden, mit der die Attribute und Tabellen-Namen in mehrere Sprachen übersetzt werden können: %Artikel::langTable = ( de => ’Artikel’, en => ’Article’, ); %Artikel::langAttribute = ( ArtikelId => { de => ’Schlüssel’, en => ’Key’, }, ArtikelStatusId => { de => ’Artikel Status’, en => ’Article status’, }, Body => { de => ’Textkörper’, en => ’Body’, }, Erstelldatum => { de => ’Erstelldatum’, en => ’Creation date’, ... .. Die Struktur wird in der Klasse abgelegt. CogniX verwendet jetzt automatisch anstelle der Attribut-Namen die sprach-abhängigen Texte. 17 5 Bilden von Präsentations Klassen Analog zu der Datenklasse muß jetzt eine Präsentations Klasse gebildet werden. Per Konvention erhält eine solche Klasse als Prefix das Kürzel www. Aus der Klasse Artikel.pm wird also die Klasse wwwArtikel.pm gebildet. Dazu steht ebenfalls ein Tool (heinzelmann) zur Verfügung, das initial die notwendigen Definitionen aus der Datenklasse generiert. 5.1 Konfiguration package wwwArtikel; @wwwArtikel::ISA = (’CogniX::wwwBase’); use strict; use CogniX::htmlStyle; use CogniX::validate; # # # # # tab[O|V] = TableView rec[O|V] = RecordView con[O|V] = Construct (search form) input[O|V] = Input form where O means Order and V means View 0=no 1=yes %wwwArtikel::def = ( # Spalte 0 1 2 3 4 5 6 7 8 # Sort tabO tabV recO recV align conO conV inputO ArtikelId => [ 0, 5, 0, 5, 1, ’l’ , 5, 0, 5, Zeitstempel => [ 0, 10, 0, 10, 1, ’l’, 10, 0, 10, RubrikId => [ 1, 15, 1, 15, 1, ’l’, 15.2, 1, 15.2, sub { &wwwArtikel::getRubrikenForMandant() } ], Haupttitel => [ 0, 20, 1, 20, 1, ’hl’, 20, 1, 20, Untertitel => [ 0, 25, 0, 25, 1, ’l’, 25, 1, 25, Body => [ 0, 30, 0, 30, 1, ’l’, 30, 0, 30, Reihenfolge => [ 2, 35, 1, 35, 1, ’l’, 50.2, 1, 50.2, MandantId => [ 0, 40, 0, 40, 1, ’l’, 91, 0, 91, PersonId => [ 0, 45, 1, 45, 1, ’l’, 15.2, 1, 15.2, ArtikelStatusId => [ 0, 50, 0, 50, 1, ’l’, 50.1, 1, 50.1, FlagFrontSide => [ 0, 70, 1, 70, 1, ’l’, 70, 1, 70, ); $wwwArtikel::table = ’Artikel’; # scrollSize # How many records are displayed per page in the table view $wwwArtikel::scrollSize = 50; 9 inputV ’HIDDEN’, ’HIDDEN’, ’LISTBOX’, 10 11 lookup domain [], 0, ], [], 0, ], [’Rubrik.Rubrik’], 80, [], 0, ], ’TEXTAREA(4,80)’,[], 0, ], ’TEXTAREA(8,80)’,[], 0, ], 1, [], 0, ], ’HIDDEN’, [’Mandant.Name’], 0, ], ’LISTBOX’, [’Person.Name’], 0, ], ’LISTBOX’, [’ArtikelStatus.Text’], 0, ], ’RADIOBOX’, [], \%main::boolean, ], # Determining the invisible detail tables # If you don’t wish to show up the detail records of a depending table add these tables # to this array @wwwArtikel::doNotShowDetails = (); Ähnlich wie die Datenklasse wird für jedes Attribut die Ansicht eingestellt, wie es im Browser angezeigt werden soll. Zum Beispiel wird beim Attribut PersonId definiert, daß eine Listbox mit den Werten aus der Tabelle Person aufbereitet wird. Als Schlüssel wird die PersonId geführt und als Anzeigewert das Attribut Person.Name. Dass die PersonId als Schlüssel geführt wird, 18 ergibt sich aus den Definitionen in der Datenklasse Artikel.pm und muss hier nicht mehr extra definiert werden. Für jede mögliche Sicht (Tabellensicht, Datensatz-Sicht, Eingabemaske, Suche etc.) auf die Daten erfolgt also hier lediglich die Konfiguration, wie die Anzeige zu erfolgen hat. Felder können in der Eingabemaske und in der Datensatz-Sicht nebeneinander angeordnet werden. Die Felder ArtikelStatusId und Reihenfolge im obigen Beispiel werden mit Angabe von Dezimalstellen (50.1 und 50.2) auf der gleichen Zeile angeordnet. Mit der lookup Spalte 10 werden die Foreign Keys aufgelöst. Es wird die fremde Tabelle referenziert und das gewünschte Anzeigefeld für die Listbox/Radiobox. Es sind auch mehrere Felder möglich, die dann konkateniert werden. Anstelle eines lookups können auch Domain-Values referenziert werden, wie das bei FlagFrontSide der Fall ist. Dort wird eine Referenz auf das Hash %main::boolean abgelegt. In der zentralen Konfigurationsdatei param.pm ist da folgendes Hash definiert: # Domains Boolean %main::boolean = ( 1 => ’Yes’, 0 => ’No’, ); Sind Domain Values abhängig von einer Business-rule, kann anstelle von fremden Tabellen oder festen Domain-Values auch eine Callback-Routine (siehe Attribut RubrikId im Beispiel) definiert werden. Bei der Aufbereitung der entsprechenden Felder wird dann immer diese Routine gerufen. So ist es ein Leichtes, Listboxen im korrekten Kontext zu erstellen. 5.2 Weiterführende Anpassungen Mit den im vorgehenden Abschnitt beschriebenen Konfiguration hat man bereits eine vollständig bedienbare Applikation zur Verfügung. CogniX stellt mit wwwBase wiederum diverse Hooks oder Insertion-Points zur Verfügung, die in der Präsentationsklasse implementiert werden können. So gibt es diverse setDefaults Methoden, die zum Beispiel bei der Neuerfassung eines Datensatzes verwendet werden können, um bestimmte Defaults in der Erfassung vorzugeben. Daneben kann man für jedes Attribut eine Methode definieren, die so heißt wie das Attribut. Ist eine solche Methode definiert, ruft CogniX diese anstelle der Standard Bildungsroutinen für Felder. D.h. man kann für ein Feld ein spezifisches Verhalten implementieren. Selbstverständlich können auch die diversen Basismethoden überschrieben werden oder falls notwendig um Funktionalität erweitert werden. Die Dokumentation beschreibt die einzelnen Methoden ausführlich. 6 Dokumentation CogniX Das Framework ist komplett in POD dokumentiert worden. Zusätzlich gibt es ergänzende Dokumentation in Latex. Die Gesamtdokumentation ist als pdf File der Distribution beigepackt und 19 kann auch von unserem Web Server geladen werden. Ein Beispiel Projekt kann ebenfalls ab unserem Server geladen werden. 7 Tools Mit der Distribution werden mehrere nützliche Tools mitgeliefert, die das Arbeiten mit CogniX erleichtern. Die Tools werden mit dem make install der Distribution in ein /bin Verzeichnis installiert. 7.1 createTemplate Mit dem Tool können initial diverse Gerüste für Klassen und komplett neue Projekte erstellt werden. 7.2 crebas Erstellt aufgrund der Daten Klassen Definitionen ein ausführbares SQL Script, welches für die Erzeugung der Tabellen in der Datenbank verwendet werden kann. 7.3 prepLanguage Erstellt aus der Klassendefinition für eine Datenklasse die notwendigen Strukturen für die Übersetzung der Attribute und Tabellen-Namen in verschiedene Sprachen 7.4 heinzelmann Erstellt aus der Daten Klasse eine Default-Präsentations www-Klasse. Das Script spart ein schönes Stück Tipparbeit. Ist eine www-Klasse mit dem heinzelmann Script erstellt, muß nur noch die Konfiguration vorgenommen werden. 7.5 load Tool zum Laden von Datenbanken. Mit dem Script können z.Bsp. Stammdaten in die Datenbank geladen werden. 7.6 checkIntegrity Prüft für eine Tabelle, ob die Datensätze die Bedingungen der referentiellen Integrität erfüllen. Das Tool ist nur für Datenbanken interessant, die keine referentielle Integrität unterstützen (z.Bsp. Postgres vor Version 7.0.0). 20 8 Showcases CogniX steht mehrfach im produktiven Einsatz. Unter anderem haben wir für die zweitgrößte Tageszeitung der Schweiz (http://www.tagesanzeiger.ch) die Umsetzung einer Datenbank gestützten Online Zeitung realisiert. Ein Content Management System also. Benutzerschnittstelle für die Redaktion sowie Schnittstellen zu Fremdsystemen sind komplett mit CogniX implementiert. Ferner haben wir eine Sales Applikation für die Verwaltung von großen Adressbeständen, eine Administrations-Lösung für Privat- und Waldorfschulen, ein Projekt-Management-Tool, eine Konfigurations- und Kundendatenbank für einen Internet Provider, eine Buchhaltung mit Debitoren-Teil, ein einfaches Trouble-Ticketing System sowie weitere kleinere Tools erstellt. Im Moment sind wir an der Einführung eines eigenen CMS Systems in Kombination mit HTML::Mason. Das CMS System soll als ASP Service betrieben werden können. Details auf unserer Homepage. 21