>> Inhaltsverzeichnis >> Anleitung für Entwickler Schema einer Datenbank

Arbeiten mit dem Schema einer Datenbank

Wie exportiere ich ein Datenbankschema in eine Datei?

<?php 
global $YANA;
$db $YANA->connect("guestbook");
$db->exportStructure("guestbook.config");
?>

Aufbau einer Strukturdatei

Strukturdateien sind im mit XML-verwandten SML-Format geschrieben (siehe auch das Kapitel: "Das SML Dateiformat"). Im Folgenden finden Sie eine informelle, Grobübersicht zu den einzelnen Elementen.

Der folgende informelle Text erläutert die Struktur *

DATABASE {
    use_strict    (true | false)
    readonly?     (true | false)
    description?  #string
    include?      (#string | #array)
    
    TABLES {
        readonly?      (true | false)
        description?   #string
        primary_key    #string
        profile_key?   #string
        foreign_keys?  #array
    
        CONSTRAINT?    { ... }
        TRIGGER?       { ... }
    
        CONTENT {
            readonly?     (true | false)
            description?  #string
            type          #string
            length?       #numeric
            precision?    #numeric
            required?     (true | false | AUTO)
            default?      #string
            unique?       (true | false)
            index?        (true | false)

            CONSTRAINT?   { ... }
            TRIGGER?      { ... }

            /* nur für numerische Datentypen */
            unsigned?     (true | false)
            zerofill?     (true | false)

            DISPLAY? {
                HIDDEN {
                    new?     (true | false)
                    edit?    (true | false)
                    select?  (true | false)
                    search?  (true | false)
                }
                READONLY {
                    new?   (true | false)
                    edit?  (true | false)
                }
                /* nur für Typ "array" */
                numeric  (true | false)
            }
    
            /* nur für Typ "image" */
            width?       #numeric
            height?      #numeric
            ratio?       (true | false)
            background?  #array
        }
    }
}
    
CONSTRAINT {
    select?  #string
    insert?  #string
    update?  #string
    delete?  #string
}

TRIGGER {
	before_insert?  #string
	before_update?  #string
	before_delete?  #string
	after_insert?   #string
	after_update?   #string
	after_delete?   #string
}

* Hilfe: Syntaktische Elemente der Datei werden blau dargestellt. Die möglichen Werte und / oder Datentypen, welche diese Elemente enthalten dürfen, werden hinter den Elementen aufgelistet. Datentypen werden durch eine Raute (#) gekennzeichnet. Es werden folgende Datentypen verwendet: #string = ein Text, #numeric = eine Zahl, #array = ein Listentyp. Falls mehrere Werte oder Datentypen erlaubt sind, werden diese in runden Klammern, durch ein Pipesymbol (|) getrennt aufgelistet. Ein Fragezeichen (?) gibt an, dass das betreffende Element optional ist.

Der nachfolgende Abschnitt erläutert die einzelnen Elemente im Detail und liefert Beispiele.

Wie schreibe ich ein eigenes Datenbankschema?

Schema-Dateien haben die Endung "*.config" und werden im Verzeichnis "config/db/" gespeichert. Eine Verbindung auf Grundlage einer Schema-Datei wird hergestellt über den PHP-Code: $YANA->connect("Name der Datei ohne Dateiendung");

Beachten Sie, dass für die Editoren "ConTEXT" und "PSPad" Code-Templates zur Verfügung stehen, welche Ihnen gerade beim Erzeugen von Datenbankschemata viel Schreibarbeit abnehmen können. Sollten Sie einen dieser beiden Editoren verwenden, installieren Sie nach Möglichkeit zunächst diese Templates bevor Sie fortfahren.

Das folgende Listing zeigt ein Schema mit allen Elementen und alle gültigen Belegungen. Existieren mehrere mögliche Varianten, dann sind diese die verschiedenen Möglichkeiten durch eine Pipe '|' voneinander getrennt. Bezeichner, die frei gewählt werden können, sind im Text fett hervorgehoben.

/* Das Feld "USE_STRICT" legt fest, ob Queries zur Laufzeit
 * gegen das Schema validiert werden oder nicht.
 */
<USE_STRICT>true|false</USE_STRICT>

/* Das Feld "READONLY" ist optional. Default = false
 */
<READONLY>true|false</READONLY>

/* Das Feld "DESCRIPTION" ist optional und kann eine Beschreibung,
 * oder den Namen der Datenbank enthalten
 */
<DESCRIPTION>Text</DESCRIPTION>

/* Das Feld "INCLUDE" hat die gleiche Bedeutung wie der gleichnamige
 * Befehl in PHP. Es importiert eine oder mehrere Datenbankschemata in die
 * aktuelle Datei.
 * Der Dateiname wird ohne Dateiendung angegeben.
 * Also zum Beispiel: <INCLUDE>user</INCLUDE> um die Datenbank "user" zu
 * importieren, die in der Datei "config/db/user.config" beschrieben wird.
 */
<INCLUDE>Datenbankschema</INCLUDE>

/* Um mehrere Dateien zu importieren verwenden Sie folgende Schreibweise:
 */
<INCLUDE>
	<0>1.Schema</0>
	<1>2.Schema</1>
	<2>3.Schema</2>
</INCLUDE>

/* Constraints sind boolesche Ausdrücke in PHP-Syntax.
 * Sie können mit einer bestimmten SQL-Aktion verknüpft werden.
 * Ergibt der Ausdruck "false" wird die entsprechende Query nicht
 * abgeschickt und ein Log-Eintrag geschrieben. Andernfalls wird die
 * Aktion fortgesetzt.
 *
 * In Constraints können Sie keine Funktionen aufrufen, mit einer einzigen
 * Ausnahme: preg_match();
 * Außerdem haben Sie Zugriff auf folgende Konstanten:
 * $VALUE      = (für INSERT, UPDATE) Wert der eingefügt wird
 * $PERMISSION = Zugriffslevel des Nutzers, der die Aktion ausgelöst hat
 * $OPERATION  = SQL-Kommando das gerade durchgeführt wird (SELECT, INSERT, ...)
 * $TABLE      = Name der Zieltabelle (meist die aktuelle Tabelle)
 * $FIELD      = Name der Zielspalte (falls angegeben)
 * $ID         = Id des aktuellen Profils (seit Version 2.8.9)
 *
 * Beispiele:
 * <SELECT>true</SELECT>
 * <UPDATE>false</UPDATE>
 * <UPDATE>$VALUE > 0 && $VALUE < 500</UPDATE>
 * <INSERT>$PERMISSION > 50</INSERT>
 * <INSERT>preg_match('/^[\w\d-_]*$/i', $VALUE)</INSERT>
 *
 * Constraints gibt es in YANA seit Version 2.8 .
 */
<CONSTRAINT>
	<SELECT>PHP-Code</SELECT>
	<INSERT>PHP-Code</INSERT>
	<UPDATE>PHP-Code</UPDATE>
	<DELETE>PHP-Code</DELETE>
</CONSTRAINT>

/* Trigger sind Miniaturprogramme in PHP-Syntax.
 * Sie werden an eine bestimmte SQL-Aktion geknüpft und automatisch ausgeführt bevor
 * oder nachdem das SQL Statement ausgeführt wurde.
 *
 * DIESE Trigger unterscheiden sich von Triggern direkt in einer Datenbank.
 * 1) PHP kann verwendet werden,
 * 2) unabhängig vom DBMS, aber:
 * 3) kein direkter Zugriff auf die Datenbank.
 *
 * Diese Trigger eignen sich vor allem für Logging und Modifizieren von Eingabedaten.
 *
 * Außerdem haben Sie Zugriff auf folgende Konstanten:
 * $VALUE      = (für INSERT, UPDATE) Wert der eingefügt wird
 * $PERMISSION = Zugriffslevel des Nutzers, der die Aktion ausgelöst hat
 * $OPERATION  = SQL-Kommando (BEFORE_INSERT, AFTER_UPDATE, ...)
 * $TABLE      = Name der Zieltabelle (meist die aktuelle Tabelle)
 * $FIELD      = Name der Zielspalte (falls angegeben)
 * $ID         = Id des aktuellen Profils (seit Version 2.8.9)
 *
 * Beispiele:
 * <BEFORE_INSERT>$VALUE = md5($VALUE);true</BEFORE_INSERT>
 * <AFTER_DELETE>if($VALUE){print 'Erfolgreich gelöscht.';}else{print 'Fehler.';}</AFTER_DELETE>
 */
<TRIGGER>
	<BEFORE_INSERT>PHP-Code</BEFORE_INSERT>
	<BEFORE_UPDATE>PHP-Code</BEFORE_UPDATE>
	<BEFORE_DELETE>PHP-Code</BEFORE_DELETE>
	<AFTER_INSERT>PHP-Code</AFTER_INSERT>
	<AFTER_UPDATE>PHP-Code</AFTER_UPDATE>
	<AFTER_DELETE>PHP-Code</AFTER_DELETE>
</TRIGGER>

/* Wie Sie vielleicht schon vermutet haben: die Option READONLY=true
 * und der Constraint UPDATE=false haben beide den gleichen Effekt.
 */

/* Hier folgt die Definition der Tabellen.
 */
<TABLES>
	<Name der Tabelle>
		<READONLY>true|false</READONLY>
		<DESCRIPTION>Label der Tabelle</DESCRIPTION>

		<CONSTRAINT>
			<SELECT>PHP-Code</SELECT>
			<INSERT>PHP-Code</INSERT>
			<UPDATE>PHP-Code</UPDATE>
			<DELETE>PHP-Code</DELETE>
		</CONSTRAINT>
		<TRIGGER>
			<BEFORE_INSERT>PHP-Code</BEFORE_INSERT>
			<BEFORE_UPDATE>PHP-Code</BEFORE_UPDATE>
			<BEFORE_DELETE>PHP-Code</BEFORE_DELETE>
			<AFTER_INSERT>PHP-Code</AFTER_INSERT>
			<AFTER_UPDATE>PHP-Code</AFTER_UPDATE>
			<AFTER_DELETE>PHP-Code</AFTER_DELETE>
		</TRIGGER>

/* Im Feld "PRIMARY_KEY" ist der Name der Spalte anzugeben, welche den Primärschlüssel enthält.
   (in Fachliteratur siehe unter dem Stichwort: "primary key constraint")
 */
		<PRIMARY_KEY>Name der Spalte</PRIMARY_KEY>

/* Im Feld "PROFILE_KEY" kann der Name einer Spalte angegeben werden, welche den Profilschlüssel enthält.

   Sinn und Zweck:
   Sie können die Datensätze einer Tabelle einem Profil zuordnen.
   Wenn Sie das tun, sieht ein Nutzer jeweils nur die Datensätze des gerade ausgewählten Profils.

   Erzeugen eines "profile key constraint":
   1) Fügen Sie der Tabelle eine Spalte vom Typ "profile" hinzu
   2) Setzen Sie die Eigenschaft "required" dieser Spalte auf "AUTO"
   3) Setzen Sie die Eigenschaft "profile_key" der Tabelle auf den Namen der Spalte

   (Dies ist ein Spezialfall eines "compound primary key" - also eines "primary key constraint".
   Ein "Spezialfall" deshalb, weil der Schlüssel ein virtueller Schlüssel ist.
   Das heißt, dass die technische Handhabung für den Nutzer vollständig transparent geschieht.
   Sie können diesen Constraint nachträglich entfernen und der Primärschlüssel bleibt dennoch
   gültig. Das bedeutet auch, dass Sie diesen Constraint nachträglich hinzufügen oder entfernen
   können, ohne etwas am Quellcode Ihres Plugins ändern zu müssen. Prüfung und Auflösung der
   Profilschlüssel geschieht auf Ebene des DB-Layer. Dies bedeutet auch, dass es aus Sicht
   der Sicherheit Ihrer Webanwendung praktisch unmöglich ist, einen "profile key" constraint
   zu umgeben. Dieses Feature wurde eingeführt in Version 2.9.)
 */
		<PROFILE_KEY>Name der Spalte</PROFILE_KEY>

/* Im Feld "FOREIGN_KEYS" kann eine Liste von Fremdschlüsseln angegeben werden.
   (in Fachliteratur siehe unter dem Stichwort: "foreign key constraint")
 */
		<FOREIGN_KEYS>
			<Name der Spalte>Name der Zieltabelle</Name der Spalte>
			<andere Spalte>andere Zieltabelle</andere Spalte>
		</FOREIGN_KEYS>

/* Hier folgt die Definition der Tabellenspalten.
 */
		<CONTENT>
			<Name der Spalte>
				<READONLY>true|false</READONLY>

				<CONSTRAINT>
					<SELECT>PHP-Code</SELECT>
					<UPDATE>PHP-Code</UPDATE>
				</CONSTRAINT>
				<TRIGGER>
					<BEFORE_UPDATE>PHP-Code</BEFORE_UPDATE>
					<AFTER_UPDATE>PHP-Code</AFTER_UPDATE>
				</TRIGGER>

/* Im Feld "DESCRIPTION" kann ein Beschriftung für diese Spalte angegeben werden.
 * Sie können hier auch %TOKEN% verwenden, welche Sie zum Beispiel in Ihrem Programm,
 * oder als Sprachdatei festlegen, um eine Beschriftung in mehreren Sprachen anbieten
 * zu können.
 */
				<DESCRIPTION>Label der Spalte</DESCRIPTION>

/* Die primitiven, skalaren Datentypen integer, float und string entsprechen ihrem
 * Äquivalent in PHP. Zusätzlich wurden weitere nützliche Datentypen eingeführt.
 *
 * mail    = prüft beim Eintragen automatisch, ob der Wert eine gültige Mailadresse ist.
 * ip      = prüft beim Eintragen automatisch, ob der Wert eine gültige IP-Adresse ist.
 * text    = für Eingaben aus Textarea-Feldern, führt automatisch zusätzliche Prüfungen
 *           zum Schutz vor Flooding durch.
 * select  = ein Aufzählungsdatentyp, dessen Elemente im Feld "DEFAULT" definiert werden,
 *           siehe unten.
 * array   = kann verwendet werden, um PHP-Arrays zu speichern. Diese werden beim Auslesen
 *           des Wertes aus der Datenbank automatisch wieder umgewandelt.
 * image   = wird verwendet um Grafiken zu speichern. Bearbeitet Dateiuploads, die
 *           Prüfung und Konvertierung der Grafik und generiert automatisch Thumbnails.
 * file    = dieser Typ dient dem Speichern von Dateien ("binary large objects").
 *           Die Dateien selbst verbleiben nach dem Upload aus Gründen der besseren Performance
 *           im Dateisystem. Um Speicherplatz zu sparen, werden Sie automatich GZip-komprimiert.
 *           In der Datenbank wird lediglich der Dateiname gespeichert. Beim Abruf der Spalte
 *           wird der Name und Pfad der komprimierten Datei als Ergebnis zurückgeliefert.
 */
				<TYPE>integer|float|string|text|url|ip|mail|time|select|array</TYPE>

				<LENGTH>positive integer</LENGTH>

/* Für den Datentyp "float" kann mit "PRECISION" die Anzahl der Nachkommastellen festgelegt werden.
 */
				<PRECISION>positive integer</PRECISION>

/* Das Feld "REQUIRED" legt fest ob ein Feld NULLABLE ist oder nicht.
 */
				<REQUIRED>true|false</REQUIRED>

/* Das Feld "DEFAULT" legt einen Wert fest, der automatisch verwendet wird, wenn beim
 * Anlegen des Datensatzes keine anderen Angaben gemacht werden.
 */
				<DEFAULT>ein Defaultwert</DEFAULT>

/* Das Feld "UNIQUE" kann entweder den Wert true, oder false annehmen, wobei false der
 * Defaultwert ist. Ist UNIQUE=true so darf kein Wert in dieser Spalte mehr als 1 Mal
 * vorkommen. Das bedeutet, jeder Wert ist eindeutig (eng. "unique").
 * Man verwendet diese Einstellung um zusätzlich zum Primärschlüssel weitere Schlüssel
 * zu definieren.
 */
				<UNIQUE>true|false</UNIQUE>

/* Das Feld "INDEX" kann entweder den Wert true, oder false annehmen, wobei false der
 * Defaultwert ist. Ist INDEX=true so wird eine sortierte Liste der Werte dieser Spalte
 * gespeichert, was das Sortieren und Suchen nach den in der Spalte gespeicherten Werten
 * beschleunigen kann.
 */
				<INDEX>true|false</INDEX>

/*
 * Die Anweisungen für die GUI und das SDK können im Feld "DISPLAY" angegeben werden.
 * Dazu existieren jeweils zwei Einstellungen: "HIDDEN" und "READONLY".
 * Wobei "READONLY" bedeutet, dass diese Spalte nicht zum Editieren angezeigt werden soll.
 * Wie der Name schon sagt, bedeutet "HIDDEN", dass die Spalte in der Ausgabe gar nicht
 * auftauchen soll.
 * Es gibt jeweils eine Einstellung, für die Abfragen: "NEW", "EDIT", "VIEW" und "SEARCH".
 * Die Eigenschaften können jeweils global oder für jede Aktion einzeln gesetzt werden.
 */

/* Zunächst die Variante mit globalen Einstellungen
 */
				<DISPLAY>
					<HIDDEN>true|false</HIDDEN>
					<READONLY>true|false</READONLY>
				</DISPLAY>				

/* Nun die Variante mit lokalen Einstellungen für jede Option
 */
				<DISPLAY>
					<HIDDEN>
						<NEW>true|false</NEW>
						<EDIT>true|false</EDIT>
						<SELECT>true|false</SELECT>
						<SEARCH>true|false</SEARCH>
					</HIDDEN>
					<READONLY>
						<NEW>true|false</NEW>
						<EDIT>true|false</EDIT>
					</READONLY>
				</DISPLAY>

/*
 * Für den Typ "array" kann die Eigenschaft "display" zusätzlich das Flag "NUMERIC"
 * enthalten, um auszudrücken, dass es sich um ein numerisches Array handelt.
 * Dadurch werden in der grafischen Oberfläche des Programms die Schlüssel nicht
 * angezeigt und bei neuen Einträgen werden die numerischen Schlüssel automatisch
 * vergeben.
 */
				<DISPLAY>
					<NUMERIC>true|false</NUMERIC>
				</DISPLAY>

			</Name der Spalte>


/*
 * Für die Datentypen integer, ip und time kann für das Feld "REQUIRED" der Wert "AUTO"
 * gesetzt werden. Dies bedeutet, dass der Wert automatisch erzeugt wird.
 * Für time    = das aktuelle Datum als Unix-Timestamp
 * Für ip      = die IP des Besuchers
 * Für integer = autoincrement beziehungsweise der Wert einer Sequence
 */
			<Name der Spalte>
				<TYPE>integer|ip|time</TYPE>
				<REQUIRED>AUTO</REQUIRED>
			</Name der Spalte>

/*
 * Für den Datentyp select kann eine Aufzählung der erlaubten Werte angegeben werden.
 *
 * Die Semantik kann man sich relativ leicht merken:
 * + Die GUI stellt Spalten vom Typ select in Formularen als Select-Feld dar.
 * + Die Darstellung im Schema erinnert ebenfalls an ein Select-Formularfeld in HTML.
 */
			<Name der Spalte>
				<TYPE>select</TYPE>
				<DEFAULT>
					<defaultwert>Beschriftung</defaultwert>
					<option 1>Beschriftung 1</option 1>
					<option 2>Beschriftung 2</option 2>
				</DEFAULT>
			</Name der Spalte>

/*
 * Für den Datentyp image können die maximale Dateigröße, Breite und Höhe der Grafik
 * angegeben werden. Ist das Bild zu klein oder zu groß, wird es automatisch
 * auf die angegebene Größe gebracht. Mit dem Wert "Ratio" wird angegeben, ob dabei
 * das Verhältnis von Breite zu Höhe erhalten bleiben soll (true) oder nicht (false).
 * Falls "Ratio" auf "true" gesetzt wird, entsteht eventuell ein Rand um das Bild herum.
 * Deshalb kann eine Hintergrundfarbe angegeben werden.
 * Diese Hintergrundfarbe füllt den unbenutzten Bereich um die Grafik herum aus.
 *
 * Der Formulargenerator kann (wenn er verwendet wird) automatisch ein Upload-Feld
 * erzeugen, mit dem Grafiken an den Server übertragen werden können.
 * Bei einem Upload wird automatisch ein Thumbnail in der Größe 75x75px erzeugt.
 * Der Formulargenerator zeigt beim Aufrufen des Datensatzes automatisch das Thumbnail
 * und einen Link zur vollständigen Grafik an.
 *
 * Grafiken werden aus Gründen der Performance NICHT als Blob in der Datenbank
 * gespeichert, sondern in einem nicht-öffentlichen Verzeichnis im Dateisystem.
 * In der Datenbank wird lediglich der Dateipfad der Grafik hinterlegt.
 * Beim Löschen des Datensatzes (über die Datenbank-API das Frameworks) werden die
 * mit dem Datensatz assoziierte Grafik und das Thumbnail ebenfalls gelöscht.
 */
			<Name der Spalte>
				<TYPE>image</TYPE>
				<LENGTH>max. Upload-Größe in Byte</LENGTH>
				<WIDTH>Breite in Pixel</WIDTH>
				<HEIGHT>Höhe in Pixel</HEIGHT>
				<RATIO>true|false</RATIO>
				<BACKGROUND>
					<0>Zahl 0-255 (rot)</0>
					<1>Zahl 0-255 (grün)</1>
					<2>Zahl 0-255 (blau)</2>
				</BACKGROUND>
			</Name der Spalte>

/*
 * Für die numerischen Datentypen integer und float können zwei
 * weitere Eigenschaften definiert werden.
 *
 * unsigned: die Zahl wird ohne Vorzeichen gespeichert
 * zerofill: beim Darstellen der Zahl werden freie Stellen werden durch '0' aufgefüllt
 *
 * Hinweis: Die Eigenschaft "zerofill" funktioniert nur korrekt, wenn über die Eigenschaft
 * "length" eine feste Länge für die definiert ist.
 */
			<Name der Spalte>
				<TYPE>integer|float</TYPE>
				<UNSIGNED>true|false</UNSIGNED>
				<ZEROFILL>true|false</ZEROFILL>
				<LENGTH>positive integer</LENGTH>
			</Name der Spalte>


		</CONTENT>
	</Name der Tabelle>

/* Hier können weitere Tabellen folgen.
 */

</TABLES>

Betrachten Sie zunächst ein ganz einfaches Beispiel:

/* Der Kopf ist normalerweise immer gleich: */

<USE_STRICT>true</USE_STRICT>
<READONLY>false</READONLY>

/* Danach folgt die Definition der Tabellen der Datenbank */

<TABLES>
	/* hier die Tabelle 'foo' */
	<foo>
		/* Jede Tabelle muss 1 Primärschlüssel haben */
		<PRIMARY_KEY>foo_id</PRIMARY_KEY>
		/* nun folgen die Spalten */
		<CONTENT>
			/* zuerst der Primärschlüssel */
			<foo_id>
				<TYPE>integer</TYPE>
				<LENGTH>8</LENGTH>
			/* REQUIRED=auto erzeugt eine "autoincrement" Spalte */
				<REQUIRED>auto</REQUIRED>
			/* HIDDEN=true macht das Feld für Besucher unsichtbar */
				<DISPLAY>
					<HIDDEN>true</HIDDEN>
				</DISPLAY>
			</foo_id>
			/* jetzt die restlichen Felder */
			<foo_title>
				<TYPE>string</TYPE>
				<LENGTH>128</LENGTH>
				<REQUIRED>true</REQUIRED>
				<DESCRIPTION>Titel</DESCRIPTION>
			</foo_title>
			<foo_text>
				<TYPE>text</TYPE>
				<REQUIRED>false</REQUIRED>
				<DESCRIPTION>Text</DESCRIPTION>
			</foo_text>
		</CONTENT>
	</foo>
	/* eine zweite Tabelle */
	<bar>
		<PRIMARY_KEY>bar_id</PRIMARY_KEY>
		<CONTENT>
			<bar_id>
				<TYPE>string</TYPE>
				<LENGTH>32</LENGTH>
				<REQUIRED>AUTO</REQUIRED>
				<DISPLAY>
					<HIDDEN>true</HIDDEN>
				</DISPLAY>
			</bar_id>
			<bar_value>
				<TYPE>string</TYPE>
				<LENGTH>128</LENGTH>
				<REQUIRED>true</REQUIRED>
				<DESCRIPTION>Wert</DESCRIPTION>
			</bar_value>
			<bar_time>
				<TYPE>time</TYPE>
				<REQUIRED>auto</REQUIRED>
				<DESCRIPTION>Zeit</DESCRIPTION>
			</bar_time>
		</CONTENT>
	</bar>
</TABLES>

Im Folgenden ein Beispiel für eine etwas komplexere Datenbank. Dargestellt ist die Datenstruktur der Gästebuch-Anwendung:

<USE_STRICT>true</USE_STRICT>
<READONLY>false</READONLY>
<TABLES>
	<guestbook>
		<PRIMARY_KEY>guestbook_id</PRIMARY_KEY>
		<CONTENT>
			<guestbook_id>
				<TYPE>integer</TYPE>
				<LENGTH>5</LENGTH>
				<DESCRIPTION>Id (PK)</DESCRIPTION>
				<DISPLAY>
					<HIDDEN>true</HIDDEN>
				</DISPLAY>				
			</guestbook_id>
			<profile_id>
				<TYPE>string</TYPE>
				<LENGTH>128</LENGTH>
				<REQUIRED>AUTO</REQUIRED>
				<DESCRIPTION>Id (FK)</DESCRIPTION>
				<DISPLAY>
					<HIDDEN>true</HIDDEN>
				</DISPLAY>				
			</profile_id>
			<guestbook_ip>
				<TYPE>ip</TYPE>
				<LENGTH>15</LENGTH>
				<REQUIRED>AUTO</REQUIRED>
				<DISPLAY>
					<HIDDEN>true</HIDDEN>
				</DISPLAY>				
			</guestbook_ip>
			<guestbook_name>
				<TYPE>string</TYPE>
				<LENGTH>128</LENGTH>
				<REQUIRED>true</REQUIRED>
				<DESCRIPTION>Name</DESCRIPTION>
			</guestbook_name>
			<guestbook_message>
				<TYPE>text</TYPE>
				<LENGTH>3000</LENGTH>
				<REQUIRED>true</REQUIRED>
				<DESCRIPTION>Text</DESCRIPTION>
			</guestbook_message>
			<guestbook_mail>
				<TYPE>mail</TYPE>
				<LENGTH>255</LENGTH>
				<DESCRIPTION>Mail</DESCRIPTION>
			</guestbook_mail>
			<guestbook_homepage>
				<TYPE>string</TYPE>
				<LENGTH>512</LENGTH>
				<DESCRIPTION>Homepage</DESCRIPTION>
			</guestbook_homepage>
			<guestbook_messenger>
				<DESCRIPTION>Messenger</DESCRIPTION>
				<TYPE>string</TYPE>
				<LENGTH>255</LENGTH>
			</guestbook_messenger>
			<guestbook_msgtyp>
				<DESCRIPTION>Typ</DESCRIPTION>
				<TYPE>select</TYPE>
				<LENGTH>5</LENGTH>
				<DEFAULT>
					<icq>ICQ</icq>
					<aol>AOL</aol>
					<yahoo>Yahoo!</yahoo>
					<msn>MSN</msn>
				</DEFAULT>
			</guestbook_msgtyp>
			<guestbook_opinion>
				<TYPE>select</TYPE>
				<LENGTH>1</LENGTH>
				<CONSTRAINT>
					<INSERT>$VALUE >= 0 && $VALUE <= 5</INSERT>
					<UPDATE>$VALUE >= 0 && $VALUE <= 5</UPDATE>
				</CONSTRAINT>
				<DEFAULT>
					<0>unentschlossen</0>
					<1>sehr gut</1>
					<2>gut</2>
					<3>befriedigend</3>
					<4>ausreichend</4>
					<5>ungenügend</5>
				</DEFAULT>
				<DESCRIPTION>Meinung</DESCRIPTION>
			</guestbook_opinion>
			<guestbook_date>
				<TYPE>time</TYPE>
				<REQUIRED>AUTO</REQUIRED>
				<DESCRIPTION>Datum/Zeit</DESCRIPTION>
				<DISPLAY>
					<HIDDEN>
						<NEW>true</NEW>
                    			</HIDDEN>
				</DISPLAY>
			</guestbook_date>
			<guestbook_comment>
				<TYPE>text</TYPE>
				<LENGTH>1024</LENGTH>
				<REQUIRED>false</REQUIRED>
				<DESCRIPTION>Kommentar</DESCRIPTION>
				<DISPLAY>
					<READONLY>
						<EDIT>true</EDIT>
					</READONLY>
				</DISPLAY>
			</guestbook_comment>
			<guestbook_is_registered>
				<TYPE>integer</TYPE>
				<LENGTH>1</LENGTH>
				<REQUIRED>AUTO</REQUIRED>
				<DEFAULT>0</DEFAULT>
				<DISPLAY>
					<HIDDEN>true</HIDDEN>
				</DISPLAY>				
			</guestbook_is_registered>
		</CONTENT>
	</guestbook>
</TABLES>

Wie erstelle ich einen Fremdschlüssel?

Der folgende Code erzeugt zwei Tabellen "foo" und "bar". Die Tabelle "bar" enthält einen Fremdschlüssel auf Tabelle "foo".

<TABLES>

	<foo>

		Primary key constraint:
		<PRIMARY_KEY>foo_id</PRIMARY_KEY>

		<CONTENT>
			<foo_id>
				<TYPE>integer</TYPE>
				<DESCRIPTION>Primärschlüssel der Tabelle foo</DESCRIPTION>
				<REQUIRED>AUTO</REQUIRED>
			</foo_id>
			<foo_name>
				<TYPE>string</TYPE>
				<DESCRIPTION>Eine Spalte, die einen Namen oder Titel enthält</DESCRIPTION>
			</foo_name>
		</CONTENT>
	</foo>

	<bar>

		Primary key constraint:
		<PRIMARY_KEY>bar_id</PRIMARY_KEY>

		Foreign key constraint:
		<FOREIGN_KEYS>

			foo_id = Spaltenname
			foo = Tabellenname

			<foo_id>foo</foo_id>

		</FOREIGN_KEYS>

		<CONTENT>
			<bar_id>
				<TYPE>integer</TYPE>
				<REQUIRED>AUTO</REQUIRED>
				<DESCRIPTION>Primärschlüssel der Tabelle bar</DESCRIPTION>
			</bar_id>
			<foo_id>
				<TYPE>select</TYPE>
				<REQUIRED>true</REQUIRED>
				<DESCRIPTION>Fremdschlüssel auf Tabelle foo, dargestellt als Selectbox</DESCRIPTION>
				<DEFAULT>

					foo_id = Spalte, die in der Datenbank gespeichert wird
					foo_name = Spalte, die im Browser angezeigt wird

					<foo_id>foo_name</foo_id>

				</DEFAULT>
			</foo_id>
		</CONTENT>
	</bar>
</TABLES>

Zusammenhang zwischen Datenbankschemata und der Templatefunktion [%create ...%]

Die Funktion "create" (siehe Abschnitt zu Templates) dient dem Aufruf des Formulargenerators. Der Formulargenerator ist in der Lage, mit den Informationen aus dem Datenbankschema selbstständig Formulare zum Anzeigen, Durchsuchen, Erstellen, Editieren und Löschen von Datensätzen zu generieren. Notwendige Abfragen der Datenbank führt er automatisch aus. In Datenbankschemata wird der Tag "DISPLAY" verwendet, um das Verhalten des Formulargenerators zu steuern. Dieser Tag erlaubt das Ein- oder Ausblenden einzelner Spalten einer Tabelle, abhängig vom Typ des gerade angezeigten Formulars.

Darstellung der Datentypen

Der Formulargenerator zeigt Tabellenspalten abhängig von Ihrem Typ unterschiedlich an. Im Folgenden eine Auflistung der Typen mit Screenshots für die jeweilige Darstellung in der GUI.

Typ der Spalte Darstellung in GUI Beschreibung
integer, float, string Inputfeld Einzeilige Texte und Zahlen werden beim Editieren der Spalte als Inputfeld dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Textzeile dargestellt.
boolean Checkbox Eingaben vom Typ "boolean" werden beim Editieren als Checkbox repräsentiert. Beim Anzeigen der Spalte, wird eine Grafik eingefügt, welche den Status des Feldes repräsentiert.
text Textarea Mehrzeilige Texte werden beim Editieren als Textareafelder dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Fließtext dargestellt. Bei zu langen Texten werden Scrollbalken erzeugt (CSS: "overflow: auto").
url, ip Inputfeld Der Datentyp "ip" bietet die Möglichkeit, automatisch die IP-Adresse des Besuchers zu speichern. IP-Adressen werden auf Ihre syntaktische Gültigkeit geprüft. In der Regel werden Spalten dieses Typs nicht als editierbar markiert. Falls doch, wird ein Inputfeld angezeigt. Der Datentyp "url" entspricht dem Typ "string", mit dem Unterschied, dass geprüft wird ob die Eingabe eine syntaktisch korrekte URL ist.
mail HTML-Code Beim Editieren wird für diesen Datentyp wird ein Inputfeld angezeigt. Die Eingaben werden syntaktisch auf Gültigkeit geprüft. Eingaben vom Datentyp "mail" werden bei der Darstellung im Browser automatisch verschlüsselt, um Datendiebstahl zu erschweren. Dies gilt grundsätzlich für alle angezeigten Mailadressen. Die Umsetzung erfolgt automatisch in der Darstellungsschicht des Frameworks, Eingriffe von Hand sich daher unnötig.
select Selectbox Der Datentyp "select" ist ein "Aufzählungstyp" (Enumeration). Beim Editieren wird eine Select-Box erzeugt. Der Inhalt der Box kann im Datenbankschema vorgegeben werden (über die Eigenschaft "Default"). Falls das Feld ein Fremdschlüssel ist (d.h. falls auf dieser Spalte ein Foreign-Key Constraint existiert), wird das Menü automatisch mit den Einträgen der verlinkten Tabelle aufgefüllt. Dabei kann angegeben werden, aus welchen Spalten die Beschriftungen und Werte entnommen werden sollen.
set Checkbox Der Datentyp "set" ist eine Variante eines Aufzählungstyps, welcher es gestattet, mehrere Werte auszuwählen (anders als "select", welches nur einen einzigen Wert erlaubt). Beim Editieren wird eine Liste von Checkboxes erzeugt. Werte und Beschriftungen der Boxen können im Datenbankschema vorgegeben (über die Eigenschaft "Default").
time Zeitangabe: Deutsch, Englisch, Russisch Beim Editieren werden für Spalten vom Typ "time" Selectboxen angezeigt, welche die Eingabe erleichtern. Eingaben vom Typ "time" werden automatisch als Timestamp gespeichert und in der GUI als Datum dargestellt. Die Art der Darstellung kann im Administrationsmenü ausgewählt werden und passt sich den gewählten Spracheinstellungen automatisch an. Das Framework stellt das Datum stets automatisch synchron zur Zeitzone des Besuchers und in seiner jeweiligen Landessprache dar.
array Array Eingaben vom Typ "array" können mehrdimensionale Arrays sein. Diese werden beim Editieren als Paare von Schlüsseln und Werten dargestellt. Durch Klick auf "entfernen" wird ein Wert gelöscht, ein Klick auf "neuen Eintrag speichern" fügt einen neuen Wert hinzu. Beim Anzeigen werden die Werte als mehrdimensionale, aufklappbare Baummenüs dargestellt. Beim Überfahren eines Schlüssels mit der Maus, öffnet sich eine Liste der Einträge, welche diesem Schlüssel zugeordnet sind.
array (numerisch) Liste Numerische Listen werden über die Eigenschaft "display.numeric" erzeugt. Sie unterscheiden sich von "normalen" Arrays dadurch, dass keine Felder zur Eingabe des Schlüssels angezeigt werden. Die Vergabe der Schlüssel erfolgt stattdessen automatisch beim Erzeugen eines neuen Eintrags. Beim Anzeigen werden die Werte als Listenelemente dargestellt.
image Uploadfeld Spalten vom Datentyp "image" werden als Thumbnail mit einem Uploadfeld zum Einfügen oder Ersetzen der gespeicherten Grafik dargestellt. Beim Klick auf das Thumbnail wird die vollständige Grafik in einem neuen Fenster geöffnet. Die Grafikdatei wird beim Upload automatisch geprüft und konvertiert. Für die Konvertierung können im Datenbankschema zusätzliche Optionen, wie zum Beispiel die gewünschte Größe, angegeben werden.
file Uploadfeld Der Datentyp "file" dient dem Speichern von Dateien ("binary large objects"). Beim Editieren werden ein Uploadfeld zum Hochladen einer neuen Datei und ein Button für den Download der aktuell gespeicherten Datei angezeigt. Die Dateien selbst verbleiben nach dem Upload aus Gründen der besseren Performance im Dateisystem. Um Speicherplatz zu sparen, werden Sie automatich GZip-komprimiert. Die Komprimierung sorgt außerdem dafür, dass die auf dem Server gespeicherten Dateien nicht ausführbar sind und ein potentieller Angreifer den Upload nicht missbrauchen kann, um Schadcode zu übertragen. Beim Download der Datei wird diese automatisch entpackt, so dass der Nutzer keine Nachteile aus der Komprimierung erfährt und auch kein Dekomprimierungsprogramm installiert haben muss. Um trotzdem einen schnelleren Download zu gewährleisten, werden die Daten, falls der Browser des Nutzers diese Funktionalität anbietet, automatisch als komprimierter Datenstrom übertragen. Der Browser übernimmt das Entpacken selbstständig. Ein Eingreifen von Hand ist nicht erforderlich. Die Steuerung dieses Features übernimmt das Framework selbstständig und vollautomatisch.

Gegenüberstellung von Datentypen und deren Darstellung durch den Formulargenerator

besondere Konfiguration der Datentypen "image" und "file"

Das Downloaden von Dateien oder Öffnen von Grafiken bei Spalten vom Datentyp "image" oder "file", wird über die Aktion "download_file" realisiert, welche Sie im Plugin "default_library" finden. Dies geschieht normalerweise automatisch.

Aus Sicherheitsgründen ist der Zugriff auf diese Aktion per Voreinstellung auf Nutzer der Nutzergruppe "Admin" beschränkt. Dies ist die Nutzergruppe mit dem höchsten Sicherheitslevel. Wenn Sie auch Nutzern mit einem geringeren Sicherheitslevel Zugriff auf diese Daten gestatten wollen, müssen Sie die Sicherheitsbeschränkung dieser Aktion herabsetzen.

Um dies zu tun, editieren Sie bitte die Datei "plugins/default_library.config" in einem Texteditor Ihrer Wahl. Suchen Sie in dieser Datei den folgenden Abschnitt.

<DOWNLOAD_FILE>
    <TYPE>primary</TYPE>
    <MODE>1</MODE>
    <TEMPLATE>NULL</TEMPLATE>
    <PERMISSION>100</PERMISSION>
</DOWNLOAD_FILE>

Der Sicherheitslevel wird dargestellt als Zahl zwischen 0 und 100, wobei 100 der Gruppe "Admin" und 0 der Gruppe "Guest" entspricht. Ändern Sie den Wert "100" auf eine Zahl, die Ihnen angemessen erscheint.

Einige Vorschläge finden Sie in der folgenden Tabelle:

Nutzergruppe Sicherheitslevel
Gast (guest) 0
registrierter Nutzer (registered) 1
Moderator (mod) 30
Besitzer (owner) 75
Administrator (admin) 100

Gegenüberstellung von Nutzergruppe und Sicherheitslevel

In diesem Beispiel wurde der Wert auf "1" geändert.

<DOWNLOAD_FILE>
    <TYPE>primary</TYPE>
    <MODE>1</MODE>
    <TEMPLATE>NULL</TEMPLATE>
    <PERMISSION>1</PERMISSION>
</DOWNLOAD_FILE>

Speichern Sie anschließend die Datei.

Damit die Änderungen wirksam werden, müssen Sie im Administrationsmenü des Yana Frameworks den Plugin-Cache aktualisieren.

Screenshot
Abbildung: Schaltfläche zum Aktualisieren des Plugin-Cache

Nach Klick auf die Schaltfläche werden die geänderten Einstellungen sofort wirksam.

Autor: Thomas Meyer, www.yanaframework.net